Merge branch 'feature-updatedomains-php'

This commit is contained in:
Benjamin Sonntag 2018-10-22 16:52:45 +02:00
commit b5b8bc3028
32 changed files with 1023 additions and 1646 deletions

1
.gitignore vendored
View File

@ -41,3 +41,4 @@ bureau/locales/fr_FR/LC_MESSAGES/messages.po~
bureau/locales/it_IT/LC_MESSAGES/messages.po~ bureau/locales/it_IT/LC_MESSAGES/messages.po~
bureau/locales/nl_NL/LC_MESSAGES/messages.po~ bureau/locales/nl_NL/LC_MESSAGES/messages.po~
bureau/locales/pt_BR/LC_MESSAGES/messages.po~ bureau/locales/pt_BR/LC_MESSAGES/messages.po~
.tx/alternc.alternc

View File

@ -130,8 +130,8 @@ $dom->unlock();
<select class="inl" name="https_<?php ehe($dt['name']); ?>" id="https_<?php ehe($dt['name']); ?>"> <select class="inl" name="https_<?php ehe($dt['name']); ?>" id="https_<?php ehe($dt['name']); ?>">
<option value="http"<?php selected((strtoupper($type)==strtoupper($dt['name']) && $sd["https"]=="http") || false); ?>><?php __("HTTP Only (redirect HTTPS to HTTP)"); ?></option> <option value="http"<?php selected((strtoupper($type)==strtoupper($dt['name']) && $sd["https"]=="http") || false); ?>><?php __("HTTP Only (redirect HTTPS to HTTP)"); ?></option>
<option value="https"<?php selected((strtoupper($type)==strtoupper($dt['name']) && $sd["https"]=="http") || true); ?>><?php __("HTTPS Only (redirect HTTP to HTTPS)"); ?></option> <option value="https"<?php selected((strtoupper($type)==strtoupper($dt['name']) && $sd["https"]=="https") || true); ?>><?php __("HTTPS Only (redirect HTTP to HTTPS)"); ?></option>
<option value="both"<?php selected((strtoupper($type)==strtoupper($dt['name']) && $sd["https"]=="http") || false); ?>><?php __("Both HTTP and HTTPS hosted at the same place"); ?></option> <option value="both"<?php selected((strtoupper($type)==strtoupper($dt['name']) && $sd["https"]=="both") || false); ?>><?php __("Both HTTP and HTTPS hosted at the same place"); ?></option>
</select> </select>
<?php } ?> <?php } ?>
</td> </td>
@ -147,7 +147,7 @@ $dom->unlock();
} }
?></button> ?></button>
<?php if ($isedit) { ?> <?php if ($isedit) { ?>
<button class="inb cancel" name="cancel" onclick="document.location = 'dom_edit.php?domain=<?php echo $domain; ?>'"><?php __("Cancel"); ?></button> <button class="inb cancel" type="button" name="cancel" onclick="document.location = 'dom_edit.php?domain=<?php echo $domain; ?>'"><?php __("Cancel"); ?></button>
<?php } ?> <?php } ?>
</td> </td>
</tr> </tr>

View File

@ -197,7 +197,6 @@ if (!$r["sub"][$i]["only_dns"]) {
__("HTTP and HTTPS"); __("HTTP and HTTPS");
break; break;
default: default:
__("Unknown");
break; break;
} }
} }

View File

@ -39,7 +39,7 @@ if (!defined("ALTERNC_PANEL")) exit(); // must be included ;)
if (file_exists("styles/style-custom.css") ) { if (file_exists("styles/style-custom.css") ) {
echo '<link rel="stylesheet" href="styles/style-custom.css" type="text/css" />'; echo '<link rel="stylesheet" href="styles/style-custom.css" type="text/css" />';
} }
if (count($addhead['css'])) { if (isset($addhead) && count($addhead['css'])) {
foreach($addhead['css'] as $css) echo $css."\n"; foreach($addhead['css'] as $css) echo $css."\n";
} }
$favicon = variable_get('favicon', 'favicon.ico' ,'You can specify a favicon, for example /images/my_logo.ico', array('desc'=>'URL','type'=>'string')); $favicon = variable_get('favicon', 'favicon.ico' ,'You can specify a favicon, for example /images/my_logo.ico', array('desc'=>'URL','type'=>'string'));
@ -53,7 +53,7 @@ $favicon = variable_get('favicon', 'favicon.ico' ,'You can specify a favicon, fo
<script src="/javascript/jquery-ui/jquery-ui.min.js" type="text/javascript"></script> <script src="/javascript/jquery-ui/jquery-ui.min.js" type="text/javascript"></script>
<script src="/javascript/jquery-tablesorter/jquery.tablesorter.min.js" type="text/javascript"></script> <script src="/javascript/jquery-tablesorter/jquery.tablesorter.min.js" type="text/javascript"></script>
<?php <?php
if (count($addhead['js'])) { if (isset($addhead) && count($addhead['js'])) {
foreach($addhead['js'] as $js) echo $js."\n"; foreach($addhead['js'] as $js) echo $js."\n";
} }
?> ?>

View File

@ -1,525 +0,0 @@
<?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
----------------------------------------------------------------------
*/
/**
* bind9 file management class
*
* @copyright AlternC-Team 2000-2017 https://alternc.com/
*/
class system_bind {
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 $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/';
/**
* Return the part of the conf we got from the database
*
* @global m_mysql $db
* @param string $domain
* @return array $this->cache_conf_db
*/
function conf_from_db($domain=false) {
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
sub_domaines sd,
domaines_type dt
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;
}
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 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.");
}
} /* Class system_bind */

View File

@ -242,6 +242,26 @@ class DB_Sql {
return $data; return $data;
} }
/* pdo equivalent of fetch() */
function fetch($mode=PDO::FETCH_ASSOC) {
if (!$this->pdo_query) {
$this->halt("next_record called with no query pending.");
return FALSE;
}
$data = $this->pdo_query->fetch($mode);
$this->Errno = $this->pdo_query->errorCode();
$this->Error = $this->pdo_query->errorInfo();
if ($data == FALSE) {
if ($this->Auto_Free)
$this->free();
return FALSE;
}
return $data;
}
/** /**
* table locking * table locking
*/ */

View File

@ -1245,3 +1245,54 @@ function _dovecot_hash($password) {
$hash = _sha512cr($password); $hash = _sha512cr($password);
return '{SHA512-CRYPT}' . $hash; 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;
}

184
bureau/class/m_apache.php Normal file
View File

@ -0,0 +1,184 @@
<?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/";
// 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="";
}
// Replace needed vars in template file
$tpl=file_get_contents($template);
$tpl = strtr($tpl, array(
"%%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;
$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"];
@unlink($confdir."/".$subdom["fqdn"].".conf");
$this->shouldreload=true;
}
// ------------------------------------------------------------
/**
* 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

238
bureau/class/m_bind.php Normal file
View File

@ -0,0 +1,238 @@
<?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 BIND 9+ zone management templates in AlternC 3.5+
*
* @copyright AlternC-Team 2000-2018 https://alternc.com/
*/
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 $zone_file_directory = '/var/lib/alternc/bind/zones';
// ------------------------------------------------------------
/** 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;
}
// ------------------------------------------------------------
/**
* 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);
// add the SUBDOMAIN entries
$zone .= $this->conf_from_db($domain);
// 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 "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;
}
}
// ------------------------------------------------------------
/**
* 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 (del_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);
}
// ------------------------------------------------------------
/**
* 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) {
$ret=0;
exec($this->RNDC." reload 2>&1",$out,$ret);
if ($ret!=0) {
$msg->raise("ERROR","bind","Error while reloading bind, error code is $ret\n".implode("\n",$out));
} else {
$msg->raise("INFO","bind","Bind reloaded");
}
}
if ($this->shouldreconfig) {
$ret=0;
exec($this->RNDC." reconfig 2>&1",$out,$ret);
if ($ret!=0) {
$msg->raise("ERROR","bind","Error while reconfiguring bind, error code is $ret\n".implode("\n",$out));
} else {
$msg->raise("INFO","bind","Bind reconfigured");
}
}
}
// ------------------------------------------------------------
/**
* 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 sub_domaines table
* @global m_mysql $db
* @param string $domain
* @return string a zonefile excerpt
*/
function conf_from_db($domain) {
global $db;
$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
sd.type=dt.name
AND sd.enable IN ('ENABLE', 'ENABLED')
ORDER BY ENTRY ;");
$t="";
while ($db->next_record()) {
$t.= $db->f('ENTRY')."\n";
}
return $t;
}
} // m_bind

View File

@ -54,15 +54,7 @@ class m_dom {
* du domaine par update_domains.sh * du domaine par update_domains.sh
* @access private * @access private
*/ */
var $fic_lock_cron = "/run/alternc/cron.lock"; const fic_lock_cron = "/run/alternc/cron.lock";
/**
* Le cron a-t-il été bloqué ?
* Il faut appeler les fonctions privées lock et unlock entre les
* appels aux domaines.
* @access private
*/
var $islocked = false;
var $type_local = "VHOST"; var $type_local = "VHOST";
var $type_url = "URL"; var $type_url = "URL";
@ -84,9 +76,10 @@ class m_dom {
* Constructeur * Constructeur
*/ */
function m_dom() { function m_dom() {
global $L_FQDN; global $L_FQDN, $domislocked;
$this->tld_no_check_at_all = variable_get('tld_no_check_at_all', 0, 'Disable ALL check on the TLD (users will be able to add any domain)', array('desc' => 'Disabled', 'type' => 'boolean')); $this->tld_no_check_at_all = variable_get('tld_no_check_at_all', 0, 'Disable ALL check on the TLD (users will be able to add any domain)', array('desc' => 'Disabled', 'type' => 'boolean'));
variable_get('mailname_bounce', $L_FQDN, 'FQDN of the mail server, used to create vhost virtual mail_adress.', array('desc' => 'FQDN', 'type' => 'string')); variable_get('mailname_bounce', $L_FQDN, 'FQDN of the mail server, used to create vhost virtual mail_adress.', array('desc' => 'FQDN', 'type' => 'string'));
$domislocked=false;
} }
@ -642,35 +635,35 @@ class m_dom {
* @param string $dom nom de domaine é effacer * @param string $dom nom de domaine é effacer
* @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon. * @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
*/ */
function del_domain($dom) { function del_domain($domain) {
global $db, $msg, $hooks; global $db, $msg, $hooks;
$msg->log("dom", "del_domain", $dom); $msg->log("dom", "del_domain", $domain);
$dom = strtolower($dom); $domain = strtolower($domain);
$this->lock(); $this->lock();
if (!$r = $this->get_domain_all($dom)) { if (!$r = $this->get_domain_all($domain)) {
return false; return false;
} }
$this->unlock(); $this->unlock();
// Call Hooks to delete the domain and the MX management: // Call Hooks to delete the domain and the MX management:
// TODO : the 2 calls below are using an OLD hook call, FIXME: remove them when unused // TODO : the 2 calls below are using an OLD hook call, FIXME: remove them when unused
$hooks->invoke("alternc_del_domain", array($dom)); $hooks->invoke("alternc_del_domain", array($domain));
$hooks->invoke("alternc_del_mx_domain", array($dom)); $hooks->invoke("alternc_del_mx_domain", array($domain));
// New hook calls: // New hook calls:
$hooks->invoke("hook_dom_del_domain", array($r["id"])); $hooks->invoke("hook_dom_del_domain", array($r["id"]));
$hooks->invoke("hook_dom_del_mx_domain", array($r["id"])); $hooks->invoke("hook_dom_del_mx_domain", array($r["id"]));
// Now mark the domain for deletion: // Now mark the domain for deletion:
$db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ?;", array($dom)); $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ?;", array($domain));
$this->set_dns_action($dom, 'DELETE'); $this->set_dns_action($domain, 'DELETE');
return true; return true;
} }
function domshort($dom, $sub = "") { function domshort($domain, $sub = "") {
return str_replace("-", "", str_replace(".", "", empty($sub) ? "" : "$sub.") . $dom); return str_replace("-", "", str_replace(".", "", empty($sub) ? "" : "$sub.") . $domain);
} }
@ -694,11 +687,11 @@ class m_dom {
* @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon. * @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
*/ */
function add_domain($domain, $dns, $noerase = false, $force = false, $isslave = false, $slavedom = "") { function add_domain($domain, $dns, $noerase = false, $force = false, $isslave = false, $slavedom = "") {
global $db, $msg, $quota, $L_FQDN, $tld, $cuid, $hooks; global $db, $msg, $quota, $L_FQDN, $tld, $cuid, $hooks, $domislocked;
$msg->log("dom", "add_domain", $domain); $msg->log("dom", "add_domain", $domain);
// Locked ? // Locked ?
if (!$this->islocked) { if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!")); $msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false; return false;
} }
@ -1037,10 +1030,10 @@ class m_dom {
* *
*/ */
function get_domain_all($dom) { function get_domain_all($dom) {
global $db, $msg, $cuid; global $db, $msg, $cuid, $domislocked;
$msg->debug("dom", "get_domain_all", $dom); $msg->debug("dom", "get_domain_all", $dom);
// Locked ? // Locked ?
if (!$this->islocked) { if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!")); $msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false; return false;
} }
@ -1072,13 +1065,14 @@ class m_dom {
$db->query("SELECT sd.*, dt.description AS type_desc, dt.only_dns, dt.advanced, dt.has_https_option FROM sub_domaines sd LEFT JOIN domaines_type dt on UPPER(dt.name)=UPPER(sd.type) WHERE compte= ? AND domaine= ? ORDER BY dt.advanced,sd.sub,sd.type ;", array($cuid, $dom)); $db->query("SELECT sd.*, dt.description AS type_desc, dt.only_dns, dt.advanced, dt.has_https_option FROM sub_domaines sd LEFT JOIN domaines_type dt on UPPER(dt.name)=UPPER(sd.type) WHERE compte= ? AND domaine= ? ORDER BY dt.advanced,sd.sub,sd.type ;", array($cuid, $dom));
// Pas de webmail, on le cochera si on le trouve. // Pas de webmail, on le cochera si on le trouve.
$r["sub"] = array(); $r["sub"] = array();
$data = $db->fetchAll(); $i=0;
foreach($data as $i=>$record) { while ($record=$db->fetch()) {
$r["sub"][$i] = $record; $r["sub"][$i] = $record;
// FIXME : replace sub by name and dest by valeur in the code that exploits this function : // FIXME : replace sub by name and dest by valeur in the code that exploits this function :
$r["sub"][$i]["name"] = $record["sub"]; $r["sub"][$i]["name"] = $record["sub"];
$r["sub"][$i]["dest"] = $record["valeur"]; $r["sub"][$i]["dest"] = $record["valeur"];
$r["sub"][$i]["fqdn"] = ((!empty($r["sub"][$i]["name"])) ? $r["sub"][$i]["name"] . "." : "") . $r["name"]; $r["sub"][$i]["fqdn"] = ((!empty($r["sub"][$i]["name"])) ? $r["sub"][$i]["name"] . "." : "") . $r["name"];
$i++;
} }
$db->free(); $db->free();
return $r; return $r;
@ -1098,10 +1092,10 @@ class m_dom {
* Retourne FALSE si une erreur s'est produite. * Retourne FALSE si une erreur s'est produite.
*/ */
function get_sub_domain_all($sub_domain_id) { function get_sub_domain_all($sub_domain_id) {
global $db, $msg, $cuid; global $db, $msg, $cuid, $domislocked;
$msg->debug("dom", "get_sub_domain_all", $sub_domain_id); $msg->debug("dom", "get_sub_domain_all", $sub_domain_id);
// Locked ? // Locked ?
if (!$this->islocked) { if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!")); $msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false; return false;
} }
@ -1263,10 +1257,10 @@ class m_dom {
* @return boolean true if the preference has been set * @return boolean true if the preference has been set
*/ */
function set_subdomain_ssl_provider($sub_domain_id,$provider) { function set_subdomain_ssl_provider($sub_domain_id,$provider) {
global $db, $msg, $cuid, $ssl; global $db, $msg, $cuid, $ssl, $domislocked;
$msg->log("dom", "set_sub_domain_ssl_provider", $sub_domain_id." / ".$provider); $msg->log("dom", "set_sub_domain_ssl_provider", $sub_domain_id." / ".$provider);
// Locked ? // Locked ?
if (!$this->islocked) { if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!")); $msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false; return false;
} }
@ -1308,13 +1302,14 @@ class m_dom {
* de $type (url, ip, dossier...) * de $type (url, ip, dossier...)
* @param string $https the HTTPS behavior : HTTP(redirect https to http), * @param string $https the HTTPS behavior : HTTP(redirect https to http),
* HTTPS(redirect http to https) or BOTH (both hosted at the same place) * HTTPS(redirect http to https) or BOTH (both hosted at the same place)
* or nothing "" when not applicable for this domain type.
* @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon. * @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
*/ */
function set_sub_domain($dom, $sub, $type, $dest, $sub_domain_id = 0, $https) { function set_sub_domain($dom, $sub, $type, $dest, $sub_domain_id = 0, $https="") {
global $db, $msg, $cuid, $bro; global $db, $msg, $cuid, $bro, $domislocked;
$msg->log("dom", "set_sub_domain", $dom . "/" . $sub . "/" . $type . "/" . $dest); $msg->log("dom", "set_sub_domain", $dom . "/" . $sub . "/" . $type . "/" . $dest);
// Locked ? // Locked ?
if (!$this->islocked) { if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!")); $msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false; return false;
} }
@ -1396,10 +1391,10 @@ class m_dom {
* *
*/ */
function del_sub_domain($sub_domain_id) { function del_sub_domain($sub_domain_id) {
global $db, $msg; global $db, $msg, $domislocked;
$msg->log("dom", "del_sub_domain", $sub_domain_id); $msg->log("dom", "del_sub_domain", $sub_domain_id);
// Locked ? // Locked ?
if (!$this->islocked) { if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!")); $msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false; return false;
} }
@ -1442,11 +1437,11 @@ class m_dom {
* TRUE sinon. * 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; global $db, $msg, $hooksthis;
$msg->log("dom", "edit_domain", $dom . "/" . $dns . "/" . $gesmx); $msg->log("dom", "edit_domain", $dom . "/" . $dns . "/" . $gesmx);
// Locked ? // Locked ?
if (!$this->islocked && !$force) { if (!$domislocked && !$force) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!")); $msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false; return false;
} }
@ -1765,15 +1760,20 @@ class m_dom {
* @access private * @access private
*/ */
function lock() { function lock() {
global $msg; global $msg,$domislocked;
$msg->debug("dom", "lock"); $msg->debug("dom", "lock");
if ($this->islocked) { if ($domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- Lock already obtained!")); $msg->raise("ERROR", "dom", _("--- Program error --- Lock already obtained!"));
} }
while (file_exists($this->fic_lock_cron)) { // wait for the file to disappear, or at most 15min:
while (file_exists(m_dom::fic_lock_cron) && filemtime(m_dom::fic_lock_cron)>(time()-900)) {
clearstatcache();
sleep(2); sleep(2);
} }
$this->islocked = true; @touch(m_dom::fic_lock_cron);
$domislocked = true;
// extra safe :
register_shutdown_function(array("m_dom","unlock"),1);
return true; return true;
} }
@ -1783,13 +1783,15 @@ class m_dom {
* return true * return true
* @access private * @access private
*/ */
function unlock() { function unlock($isshutdown=0) {
global $msg; global $msg,$domislocked;
$msg->debug("dom", "unlock"); $msg->debug("dom", "unlock");
if (!$this->islocked) { if (!$isshutdown && !$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!")); $msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
} }
$this->islocked = false; // don't use $this since we may be called by register_shutdown_function out of an object instance.
@unlink(m_dom::fic_lock_cron);
$domislocked = false;
return true; return true;
} }
@ -1892,199 +1894,103 @@ class m_dom {
/** /**
* Return an array with all the needed parameters to generate conf * complex process to manage domain and subdomain updates
* of a vhost. * Launched every minute by a cron as root
* If no parameters, return the parameters for ALL the vhost. * should launch hooks for each domain or subdomain,
* Optionnal parameters: id of the sub_domaines * so that apache & bind could do their job
* */ */
function generation_parameters($id = null, $only_apache = true) { function update_domains() {
global $db, $msg; global $db, $hooks;
$msg->log("dom", "generation_parameters"); if (posix_getuid()!=0) {
$params = ""; echo "FATAL: please lauch me as root\n";
/** 2016_05_18 : this comments was here before escaping the request... is there still something to do here ? exit();
* // BUG BUG BUG FIXME
* // Suppression de comptes -> membres existe pas -> domaines a supprimer ne sont pas lister
*/
$query = "
select
sd.id as sub_id,
lower(sd.type) as type,
m.login,
m.uid as uid,
if(length(sd.sub)>0,concat_ws('.',sd.sub,sd.domaine),sd.domaine) as fqdn,
concat_ws('@',m.login,v.value) as mail,
sd.valeur
from
sub_domaines sd left join membres m on sd.compte=m.uid,
variable v,
domaines_type dt
where
v.name='mailname_bounce'
and lower(dt.name) = lower(sd.type)";
$query_args = array();
if (!is_null($id) && intval($id) == $id) {
$query .= " AND sd.id = ? ";
array_push($query_args, intval($id));
}
if ($only_apache) {
$query .=" and dt.only_dns is false ";
} }
$query .= " $this->lock();
order by
m.login,
sd.domaine,
sd.sub;";
// fix in case we forgot to delete SUBDOMAINS before deleting a DOMAIN
$db->query("UPDATE sub_domaines sd, domaines d SET sd.web_action = 'DELETE' WHERE sd.domaine = d.domaine AND sd.compte=d.compte AND d.dns_action = 'DELETE';");
$db->query($query, $query_args); // Search for things to do on DOMAINS:
$db->query("SELECT * FROM domaines WHERE dns_action!='OK';");
$r = array(); $alldoms=array();
while ($db->next_record()) { while ($db->next_record()) {
$r[$db->Record['sub_id']] = $db->Record; $alldoms[$db->Record["id"]]=$db->Record;
} }
return $r; // now launch hooks
} if (count($alldoms)) {
$hooks->invoke("hook_updatedomains_dns_pre");
foreach($alldoms as $id=>$onedom) {
if ($onedom["gesdns"]==0 || $onedom["dns_action"]=="DELETE") {
$ret = $hooks->invoke("hook_updatedomains_dns_del",array($onedom));
} else {
$ret = $hooks->invoke("hook_updatedomains_dns_add",array($onedom));
}
if ($onedom["dns_action"]=="DELETE") {
/** $db->query("DELETE FROM domaines WHERE domaine=?;",array($onedom));
* Return an array with all informations of the domains_type } else {
* used to generate Apache conf. // we keep the highest result returned by hooks...
* Die if templates missing. rsort($ret,SORT_NUMERIC); $returncode=$ret[0];
* Warning: an Apache domains_type must have 'only_dns' == TRUE $db->query("UPDATE domaines SET dns_result=?, dns_action='OK' WHERE domaine=?;",array($returncode,$onedom["domaine"]));
* }
* */
function generation_domains_type() {
global $dom;
$d = array();
foreach ($dom->domains_type_lst() as $k => $v) {
if ($v['only_dns'] == true) {
continue;
} }
if (!$j = file_get_contents(ALTERNC_APACHE2_GEN_TMPL_DIR . '/' . strtolower($k) . '.conf')) { $hooks->invoke("hook_updatedomains_dns_post");
die("Error: missing file for $k");
}
$d[$k] = $v;
$d[$k]['tpl'] = $j;
}
return $d;
}
/**
* Launch old fashionned hooks as there was in AlternC 1.0
* @TODO: do we still need that?
*/
function generate_conf_oldhook($action, $lst_sub, $sub_obj = null) {
if (is_null($sub_obj)) {
$sub_obj = $this->generation_parameters(null, false);
}
if (!isset($lst_sub[strtoupper($action)]) || empty($lst_sub[strtoupper($action)])) {
return false;
} }
$lst_by_type = $lst_sub[strtoupper($action)];
foreach ($lst_by_type as $type => $lid_arr) { // Search for things to do on SUB-DOMAINS:
$script = "/etc/alternc/functions_hosting/hosting_" . strtolower($type) . ".sh"; $db->query("SELECT sd.*, dt.only_dns FROM domaines_type dt, sub_domaines sd WHERE dt.name=sd.type AND sd.web_action!='OK';");
if (!@is_executable($script)) { $alldoms=array();
continue; $ignore=array();
} $delete=array();
foreach ($lid_arr as $lid) { while ($db->next_record()) {
$o = $sub_obj[$lid]; // only_dns=1 => weird, we should not have web_action SET to something else than OK ... anyway, skip it
$cmd = $script . " " . escapeshellcmd(strtolower($action)) . " "; if ($db->Record["only_dns"]) {
$cmd .= escapeshellcmd($o['fqdn']) . " " . escapeshellcmd($o['valeur']); if ($db->Record["web_action"]=="DELETE") {
$delete[]=$db->Record["id"];
system($cmd); } else {
} $ignore[]=$db->Record["id"];
} // foreach $lst_by_type }
}
/**
* Generate apache configuration.
* Die if a specific FQDN have 2 vhost conf.
*
* */
function generate_apacheconf($p = null) {
// Get the parameters
$lst = $this->generation_parameters($p);
$gdt = $this->generation_domains_type();
// Initialize duplicate check
$check_dup = array();
$ret = '';
foreach ($lst as $p) {
// Check if duplicate
if (in_array($p['fqdn'], $check_dup)) {
die("Error: duplicate fqdn : " . $p['fqdn']);
} else { } else {
$check_dup[] = $p['fqdn']; $alldoms[$db->Record["id"]]=$db->Record;
} }
}
foreach($delete as $id) {
$db->query("DELETE FROM sub_domaines WHERE id=?;",array($id));
}
foreach($ignore as $id) {
// @FIXME (unsure it's useful) maybe we could check that no file exist for this subdomain ?
$db->query("UPDATE sub_domaines SET web_action='OK' WHERE id=?;",array($id));
}
// now launch hooks
if (count($alldoms)) {
$hooks->invoke("hook_updatedomains_web_pre");
foreach($alldoms as $id=>$subdom) {
// is it a delete (DISABLED or DELETE)
if ($subdom["web_action"]=="DELETE" || strtoupper(substr($subdom["enable"],0,7))=="DISABLE") {
$ret = $hooks->invoke("hook_updatedomains_web_del",array($subdom["id"]));
} else {
$hooks->invoke("hook_updatedomains_web_before",array($subdom["id"])); // give a chance to get SSL cert before ;)
$ret = $hooks->invoke("hook_updatedomains_web_add",array($subdom["id"]));
$hooks->invoke("hook_updatedomains_web_after",array($subdom["id"]));
}
// Get the needed template if ($subdom["web_action"]=="DELETE") {
$tpl = $gdt[$p['type']] ['tpl']; $db->query("DELETE FROM sub_domaines WHERE id=?;",array($id));
} else {
// Replace needed vars // we keep the highest result returned by hooks...
$tpl = strtr($tpl, array( rsort($ret,SORT_NUMERIC); $returncode=$ret[0];
"%%LOGIN%%" => $p['login'], $db->query("UPDATE sub_domaines SET web_result=?, web_action='OK' WHERE id=?;",array($returncode,$id));
"%%fqdn%%" => $p['fqdn'], }
"%%document_root%%" => getuserpath($p['login']) . $p['valeur'],
"%%account_root%%" => getuserpath($p['login']),
"%%redirect%%" => $p['valeur'],
"%%UID%%" => $p['uid'],
"%%GID%%" => $p['uid'],
"%%mail_account%%" => $p['mail'],
"%%user%%" => "FIXME",
));
// Security check
if ($p['uid'] < 1999) { // if UID is not an AlternC uid
$ret.= "# ERROR: Sub_id: " . $p['sub_id'] . "- The uid seem to be dangerous\n";
continue;
} }
$hooks->invoke("hook_updatedomains_web_post");
// Return the conf
$ret.= "# Sub_id: " . $p['sub_id'] . "\n" . $tpl;
} }
return $ret; $this->unlock();
} }
/**
* Return an array with the list of id of sub_domains waiting for an action
*/
function generation_todo() {
global $db, $msg;
$msg->debug("dom", "generation_todo");
$db->query("select id as sub_id, web_action, type from sub_domaines where web_action !='ok';");
$r = array();
while ($db->next_record()) {
$r[strtoupper($db->Record['web_action'])][strtoupper($db->Record['type'])][] = $db->f('sub_id');
}
return $r;
}
function subdomain_modif_are_done($sub_domain_id, $action) {
global $db;
$sub_domain_id = intval($sub_domain_id);
switch (strtolower($action)) {
case "delete":
$sql = "DELETE FROM sub_domaines WHERE id =$sub_domain_id;";
break;
default:
$sql = "UPDATE sub_domaines SET web_action='OK' WHERE id='$sub_domain_id'; ";
}
$db->query($sql);
return true;
}
/** /**
* @param string $dns_action * @param string $dns_action
*/ */
@ -2095,15 +2001,8 @@ class m_dom {
} }
function set_dns_result($domain, $dns_result) {
global $db;
$db->query("UPDATE domaines SET dns_result= ? WHERE domaine= ?; ", array($dns_result, $domain));
return true;
}
/** /**
* List if there is problems in the domains. * List if there are problems on the domain.
* Problems can appear when editing domains type properties * Problems can appear when editing domains type properties
*/ */
function get_problems($domain) { function get_problems($domain) {
@ -2160,6 +2059,8 @@ class m_dom {
_("Default mail server"); _("Default mail server");
_("Default backup mail server"); _("Default backup mail server");
_("AlternC panel access"); _("AlternC panel access");
_("DKIM Key");
_("Email autoconfiguration");
} }
} /* Class m_domains */ } /* Class m_domains */

View File

@ -99,8 +99,8 @@ class m_lxc implements vm {
} }
} }
$msg = serialize($params); $message = serialize($params);
if (fwrite($fp, $msg . "\n") < 0) { if (fwrite($fp, $message . "\n") < 0) {
$this->error[] = 'Unable to send data'; $this->error[] = 'Unable to send data';
return FALSE; return FALSE;
} }
@ -135,22 +135,22 @@ class m_lxc implements vm {
$pass = $pass ? $pass : $mem->user['pass']; $pass = $pass ? $pass : $mem->user['pass'];
$uid = $uid ? $uid : $mem->user['uid']; $uid = $uid ? $uid : $mem->user['uid'];
$msgg = array('action' => 'start', 'login' => $login, 'pass' => $pass, 'uid' => $uid); $message = array('action' => 'start', 'login' => $login, 'pass' => $pass, 'uid' => $uid);
$msgg['mysql_host'] = $mysql->dbus->Host; $message['mysql_host'] = $mysql->dbus->Host;
$res = $this->sendMessage($msgg); $res = $this->sendMessage($message);
if ($res === FALSE) { if ($res === FALSE) {
return $this->error; return $this->error;
} else { } else {
$data = unserialize($res); $data = unserialize($res);
$error = (int) $data['error']; $error = (int) $data['error'];
$hostname = $data['hostname']; $hostname = $data['hostname'];
$msg = $data['msg']; $message = $data['msg'];
$date_start = 'NOW()'; $date_start = 'NOW()';
$uid = $mem->user['uid']; $uid = $mem->user['uid'];
if ($error != 0) { if ($error != 0) {
$msg->raise("ERROR", 'lxc', _($msg)); $msg->raise("ERROR", 'lxc', _($message));
return FALSE; return FALSE;
} }
$db->query("INSERT INTO vm_history (ip,date_start,uid,serialized_object) VALUES (?, ?, ?, ?);", array($hostname, $date_start, $uid, $res)); $db->query("INSERT INTO vm_history (ip,date_start,uid,serialized_object) VALUES (?, ?, ?, ?);", array($hostname, $date_start, $uid, $res));
@ -166,8 +166,8 @@ class m_lxc implements vm {
global $mem; global $mem;
$login = $login ? $login : $mem->user['login']; $login = $login ? $login : $mem->user['login'];
$msgg = array('action' => 'get', 'login' => $login); $message = array('action' => 'get', 'login' => $login);
$res = $this->sendMessage($msgg); $res = $this->sendMessage($message);
if (!$res) { if (!$res) {
return FALSE; return FALSE;
} }

View File

@ -469,9 +469,9 @@ ORDER BY
if ($db->next_record()) { 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='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 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; return true;
} }
@ -912,6 +912,7 @@ ORDER BY
} }
// ------------------------------------------------------------
/** /**
* hook function called by AlternC when a domain is created for * hook function called by AlternC when a domain is created for
* the current user account using the SLAVE DOMAIN feature * 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 * hook function called by AlternC when a domain is created for
* the current user account * the current user account
@ -937,7 +939,7 @@ ORDER BY
* @access private * @access private
*/ */
function hook_dom_add_mx_domain($domain_id) { 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); $msg->log("mail", "hook_dom_add_mx_domain", $domain_id);
$db->query("SELECT value FROM variable where name='mailname_bounce';"); $db->query("SELECT value FROM variable where name='mailname_bounce';");
@ -947,8 +949,9 @@ ORDER BY
} }
$mailname = $db->f("value"); $mailname = $db->f("value");
// set spf & dmarc for this domain // 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()) { if ($db->next_record()) {
$this->set_dns_autoconf($db->Record["domaine"],$db->Record["compte"]);
if ($spf = variable_get("default_spf_value")) { if ($spf = variable_get("default_spf_value")) {
$this->set_dns_spf($db->Record["domaine"], $spf); $this->set_dns_spf($db->Record["domaine"], $spf);
} }
@ -960,13 +963,14 @@ ORDER BY
} }
// ------------------------------------------------------------
/** /**
* hook function called by variables when a variable is changed * hook function called by variables when a variable is changed
* @access private * @access private
*/ */
function hook_variable_set($name, $old, $new) { function hook_variable_set($name, $old, $new) {
global $msg, $db; 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") { if ($name == "default_spf_value") {
$new = trim($new); $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', valeur='';",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', valeur='';",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 * 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. * 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 * 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. * account's login is current and if not it's $login.
@ -1055,5 +1087,139 @@ 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,compte,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;
} else {
$add[]=$db->Record;
}
}
foreach($add as $domain) {
$this->dkim_add($domain["domaine"],$domain["compte"]);
}
foreach($del as $domain) {
$this->dkim_del($domain["domaine"],$domain["compte"]);
}
}
// ------------------------------------------------------------
/**
* 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,$uid) {
global $db;
$target_dir = "/etc/opendkim/keys/$domain";
// Create a dkim key when it's not already there :
if (!file_exists($target_dir.'/alternc.txt')) {
$this->shouldreloaddkim=true;
if (! is_dir($target_dir)) mkdir($target_dir); // create dir
// Generate the key, 1200 bits (better than 1024)
$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_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);
}
// Search for the subdomain entry, if it's not already there, create it:
$db->query("SELECT id FROM sub_domaines WHERE domaine=? AND sub='alternc._domainkey';",array($domain));
if (!$db->next_record()) {
// Add subdomaine entry
$dkim_key=$this->dkim_get_entry($domain);
$db->query("INSERT INTO sub_domaines SET domaine=?, compte=?, sub='alternc._domainkey', type='dkim', valeur=?;",array($domain,$uid,$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,$uid) {
$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);
}
$db->query("DELETE FROM sub_domaines WHERE domaine=? AND sub='alternc._domainkey';",array($domain));
// No need to do DNS_ACTION="UPDATE" => we are in the middle of a HOOK
}
// ------------------------------------------------------------
/**
* 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) {
global $msg;
$key=file_get_contents("/etc/opendkim/keys/".$domain."/alternc.txt");
// easy: monoline key
if (preg_match('#alternc._domainkey IN TXT "(.*)"#',$key,$mat)) {
return $mat[1];
} else {
// Need to parse a multiligne key:
$inkey=false; $result="";
$lines=explode("\n",$key);
foreach($lines as $line) {
if (preg_match('#alternc._domainkey\s+IN\s+TXT\s+\( "(.*)"#',$line,$mat)) {
$result.=$mat[1]; $inkey=true; continue;
}
if ($inkey && preg_match('#^\s*"(.*)"\s*\)#',$line,$mat)) {
$result.=$mat[1]; $inkey=false; break;
}
if ($inkey && preg_match('#^\s*"(.*)"\s*$#',$line,$mat)) {
$result.=$mat[1]; $inkey=true; continue;
}
}
if ($result)
return $result;
}
$msg->debug("mail","dkim_get_entry($domain) failed");
return false;
}
// @TODO hook after reloading DNS zones => if necessary, restart opendkim
} /* Class m_mail */ } /* Class m_mail */

View File

@ -372,7 +372,34 @@ INSTR(CONCAT(sd.sub,IF(sd.sub!='','.',''),sd.domaine),'.')+1))=?
return $db->Record; return $db->Record;
} }
// -----------------------------------------------------------------
/** Return paths to certificate, key, and chain for a certificate
* given it's ID.
* @param $id integer the certificate by id
* @return array cert, key, chain (not mandatory) with full path.
*/
function get_certificate_path($id) {
global $db, $msg, $cuid;
$msg->log("ssl", "get_certificate_path",$id);
$id = intval($id);
$db->query("SELECT id FROM certificates WHERE id=?;",array($id));
if (!$db->next_record()) {
$msg->raise("ERROR","ssl", _("Can't find this Certificate"));
// Return cert 0 info :)
$id=0;
}
$chain=self::KEY_REPOSITORY."/".floor($id/1000)."/".$id.".chain";
if (!file_exists($chain))
$chain=false;
return array(
"cert" => self::KEY_REPOSITORY."/".floor($id/1000)."/".$id.".pem",
"key" => self::KEY_REPOSITORY."/".floor($id/1000)."/".$id.".key",
"chain" => $chain
);
}
// ----------------------------------------------------------------- // -----------------------------------------------------------------
/** Return all the valid certificates that can be used for a specific FQDN /** Return all the valid certificates that can be used for a specific FQDN
* return the list of certificates by order of preference * return the list of certificates by order of preference
@ -612,6 +639,34 @@ SELECT ?,?,?, FROM_UNIXTIME(?), FROM_UNIXTIME(?), ?, ?, sslcsr FROM certificate
} }
// -----------------------------------------------------------------
/** Launched by hosting_functions.sh launched by update_domaines.sh
* Action may be create/postinst/delete/enable/disable
* Change the template for this domain name to have the proper CERTIFICATE
* An algorithm determine the best possible certificate, which may be a BAD one
* (like a generic self-signed for localhost as a last chance)
*/
public function hook_updatedomains_web_before($subdomid) {
global $db, $msg, $dom;
$msg->log("ssl", "hook_updatedomains_web_before($subdomid)");
$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;
$domtype=$dom->domains_type_get($subdom["type"]);
// the domain type must be a "dns_only=false" one:
if ($domtype["only_dns"]==true) {
return; // nothing to do : this domain type does not involve Vhosts
}
$subdom["fqdn"]=$subdom["sub"].(($subdom["sub"])?".":"").$subdom["domaine"];
list($cert) = $this->get_valid_certs($subdom["fqdn"], $subdom["provider"]);
$this->write_cert_file($cert);
// Edit certif_hosts:
$db->query("UPDATE sub_domaines SET certificate_id=? WHERE id=?;",array($cert["id"], $subdom["id"]));
}
// ---------------------------------------------------------------- // ----------------------------------------------------------------
/** Search for the best certificate for a user and a fqdn /** Search for the best certificate for a user and a fqdn
@ -627,7 +682,25 @@ SELECT ?,?,?, FROM_UNIXTIME(?), FROM_UNIXTIME(?), ?, ?, sslcsr FROM certificate
// get the first good certificate: // get the first good certificate:
list($cert) = $this->get_valid_certs($fqdn, $subdom["provider"]); list($cert) = $this->get_valid_certs($fqdn, $subdom["provider"]);
$this->write_cert_file($cert);
// we have the files, let's fill the output array :
$output=array(
"id" => $cert["id"],
"crt" => $CRTDIR . "/" . $cert["id"].".pem",
"key" => $CRTDIR . "/" . $cert["id"].".key",
);
if (file_exists($CRTDIR . "/" . $cert["id"].".chain")) {
$output["chain"] = $CRTDIR . "/" . $cert["id"].".chain";
}
return $output;
}
// -----------------------------------------------------------------
/** Write certificate file into KEY_REPOSITORY
* @param $cert array an array with ID sslcrt sslkey sslchain
*/
function write_cert_file($cert) {
// we split the certificates by 1000 // we split the certificates by 1000
$CRTDIR = self::KEY_REPOSITORY . "/" . floor($cert["id"]/1000); $CRTDIR = self::KEY_REPOSITORY . "/" . floor($cert["id"]/1000);
@mkdir($CRTDIR,0750,true); @mkdir($CRTDIR,0750,true);
@ -659,16 +732,6 @@ SELECT ?,?,?, FROM_UNIXTIME(?), FROM_UNIXTIME(?), ?, ?, sslcsr FROM certificate
chmod($CRTDIR . "/" . $cert["id"].".chain",0640); chmod($CRTDIR . "/" . $cert["id"].".chain",0640);
} }
} }
// we have the files, let's fill the output array :
$output=array(
"id" => $cert["id"],
"crt" => $CRTDIR . "/" . $cert["id"].".pem",
"key" => $CRTDIR . "/" . $cert["id"].".key",
);
if (file_exists($CRTDIR . "/" . $cert["id"].".chain")) {
$output["chain"] = $CRTDIR . "/" . $cert["id"].".chain";
}
return $output;
} }

View File

@ -14,8 +14,8 @@ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 5 * * * alterncpanel /usr/lib/alternc/sqlbackup.sh -t daily 0 5 * * * alterncpanel /usr/lib/alternc/sqlbackup.sh -t daily
0 4 * * 0 alterncpanel /usr/lib/alternc/sqlbackup.sh -t weekly 0 4 * * 0 alterncpanel /usr/lib/alternc/sqlbackup.sh -t weekly
# Every 5 minutes, spool waiting domain changes # Every minute, spool waiting domain changes
*/5 * * * * root /usr/lib/alternc/update_domains.sh * * * * * root /usr/lib/alternc/update_domains.php
# Every 5 minutes, do mails actions # Every 5 minutes, do mails actions
*/5 * * * * root /usr/lib/alternc/update_mails.sh */5 * * * * root /usr/lib/alternc/update_mails.sh

View File

@ -42,8 +42,9 @@ case "$1" in
# corriger les permissions du chroot # corriger les permissions du chroot
mkdir -p /var/spool/postfix/var/run/saslauthd || true mkdir -p /var/spool/postfix/var/run/saslauthd || true
dpkg-statoverride --quiet --update --add root sasl 710 /var/spool/postfix/var/run/saslauthd || true if ! dpkg-statoverride --list /var/spool/postfix/var/run/saslauthd >/dev/null ; then
dpkg-statoverride --quiet --update --add root sasl 710 /var/spool/postfix/var/run/saslauthd || true
fi
db_get "alternc/alternc_mail" db_get "alternc/alternc_mail"
VMAIL_HOME="$RET" VMAIL_HOME="$RET"

View File

@ -5,10 +5,6 @@
DocumentRoot /usr/share/alternc/panel/admin DocumentRoot /usr/share/alternc/panel/admin
ServerName %%fqdn%% ServerName %%fqdn%%
# Mail autoconfig
ServerAlias autoconfig.*
ServerAlias autodiscover.*
RewriteEngine on RewriteEngine on
RewriteRule ^/admin/(.*) /$1 [R=301,L] RewriteRule ^/admin/(.*) /$1 [R=301,L]
@ -17,20 +13,6 @@
RewriteEngine On RewriteEngine On
RewriteRule ^webmail /webmail-redirect.php [L] RewriteRule ^webmail /webmail-redirect.php [L]
# Mail autoconfig
RewriteRule ^/mail/mailautoconfig.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^/mail/config-v1.1.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^mail/mailautoconfig.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^mail/config-v1.1.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^/autodiscover/autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^/Autodiscover/Autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^/Autodiscover.xml$ mailautoconfig_outlook.php [L]
RewriteRule ^/autodiscover.xml$ mailautoconfig_outlook.php [L]
RewriteRule ^autodiscover/autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^Autodiscover/Autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^Autodiscover.xml$ mailautoconfig_outlook.php [L]
RewriteRule ^autodiscover.xml$ mailautoconfig_outlook.php [L]
# will be used to define aliases such as /javascript /webmail /squirrelmail ... # will be used to define aliases such as /javascript /webmail /squirrelmail ...
IncludeOptional /etc/alternc/apache-panel.d/*.conf IncludeOptional /etc/alternc/apache-panel.d/*.conf

View File

@ -0,0 +1,53 @@
<VirtualHost *:80>
DocumentRoot /usr/share/alternc/panel/admin
AssignUserId alterncpanel alterncpanel
SetEnv LOGIN "0000-panel"
ServerName %%fqdn%%
# Mail autoconfig
RewriteRule ^/mail/mailautoconfig.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^/mail/config-v1.1.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^mail/mailautoconfig.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^mail/config-v1.1.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^/autodiscover/autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^/Autodiscover/Autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^/Autodiscover.xml$ mailautoconfig_outlook.php [L]
RewriteRule ^/autodiscover.xml$ mailautoconfig_outlook.php [L]
RewriteRule ^autodiscover/autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^Autodiscover/Autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^Autodiscover.xml$ mailautoconfig_outlook.php [L]
RewriteRule ^autodiscover.xml$ mailautoconfig_outlook.php [L]
</VirtualHost>
<VirtualHost *:443>
DocumentRoot /usr/share/alternc/panel/admin
AssignUserId alterncpanel alterncpanel
SetEnv LOGIN "0000-panel"
ServerName %%fqdn%%
# Mail autoconfig
RewriteRule ^/mail/mailautoconfig.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^/mail/config-v1.1.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^mail/mailautoconfig.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^mail/config-v1.1.xml$ /mailautoconfig_thunderbird.php [L]
RewriteRule ^/autodiscover/autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^/Autodiscover/Autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^/Autodiscover.xml$ mailautoconfig_outlook.php [L]
RewriteRule ^/autodiscover.xml$ mailautoconfig_outlook.php [L]
RewriteRule ^autodiscover/autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^Autodiscover/Autodiscover.xml$ /mailautoconfig_outlook.php [L]
RewriteRule ^Autodiscover.xml$ mailautoconfig_outlook.php [L]
RewriteRule ^autodiscover.xml$ mailautoconfig_outlook.php [L]
SSLEngine On
SSLCertificateFile %%CRT%%
SSLCertificateKeyFile %%KEY%%
%%CHAINLINE%%
</VirtualHost>

View File

@ -10,6 +10,11 @@
RewriteCond %{REQUEST_FILENAME} !/.well-known/acme-challenge/ RewriteCond %{REQUEST_FILENAME} !/.well-known/acme-challenge/
RewriteRule ^/(.*)$ http://%%fqdn%%/$1 [R=301,L] RewriteRule ^/(.*)$ http://%%fqdn%%/$1 [R=301,L]
SSLEngine On
SSLCertificateFile %%CRT%%
SSLCertificateKeyFile %%KEY%%
%%CHAINLINE%%
</Virtualhost> </Virtualhost>
<VirtualHost *:80> <VirtualHost *:80>

View File

@ -5,6 +5,7 @@
acl "allslaves" { acl "allslaves" {
{ {
127.0.0.1; 127.0.0.1;
::1;
//AUTO-SLAVES// //AUTO-SLAVES//
}; };
}; };

View File

@ -1 +1 @@
zone "@@DOMAINE@@" { type master; file "@@ZONE_FILE@@"; allow-query { any; }; }; zone "@@DOMAIN@@" { type master; file "@@ZONE_FILE@@"; allow-query { any; }; };

View File

@ -354,9 +354,8 @@ do
fi fi
done done
# ensure dovecot, postfix, apache, can access ssl certificates: # ensure dovecot, postfix, can access ssl certificates:
adduser dovecot ssl-cert adduser dovecot ssl-cert
adduser www-data ssl-cert
adduser postfix ssl-cert adduser postfix ssl-cert
run-parts --arg=certificates /usr/lib/alternc/install.d run-parts --arg=certificates /usr/lib/alternc/install.d

View File

@ -115,7 +115,7 @@ CREATE TABLE IF NOT EXISTS domaines (
noerase tinyint(4) NOT NULL default '0', noerase tinyint(4) NOT NULL default '0',
dns_action enum ('OK','UPDATE','DELETE') NOT NULL default 'UPDATE', dns_action enum ('OK','UPDATE','DELETE') NOT NULL default 'UPDATE',
dns_result varchar(255) not null default '', 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), PRIMARY KEY (id),
UNIQUE KEY (domaine) UNIQUE KEY (domaine)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
@ -479,8 +479,10 @@ CREATE TABLE IF NOT EXISTS `domaines_type` (
PRIMARY KEY ( `name` ) PRIMARY KEY ( `name` )
) ENGINE=InnoDB COMMENT = 'Type of domains allowed'; ) ENGINE=InnoDB COMMENT = 'Type of domains allowed';
INSERT IGNORE INTO `domaines_type` (name, description, target, entry, compatibility, only_dns, need_dns, advanced, enable) values 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'), ('dkim', 'DKIM Key', 'TXT', '%SUB% IN TXT "%TARGET%"', 'txt,defmx,defmx2,mx,mx2,url,ip,ipv6', true, true, true, 'ADMIN'),
('autodiscover', 'Email autoconfiguration', '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'), ('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'), ('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'), ('ipv6', 'IPv6 redirect', 'IPV6', '%SUB% IN AAAA %TARGET%', 'ip,ipv6,txt,mx,mx2,defmx,defmx2', true, true, true, 'ALL'),
@ -793,7 +795,6 @@ CREATE TABLE IF NOT EXISTS `certificates` (
-- make it re-exec-proof -- make it re-exec-proof -- BUT don't overwrite existing value !
DELETE FROM alternc_status WHERE name='alternc_version'; INSERT IGNORE INTO alternc_status SET name='alternc_version',value='3.5.0.1.sql';
INSERT INTO alternc_status SET name='alternc_version',value='3.5.0.1.sql';

View File

@ -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', 'TXT', '%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', 'Email autoconfiguration', '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 MODIFY `lastlogin` DATETIME NOT NULL DEFAULT 0;
ALTER TABLE mailbox ADD `lastloginsasl` DATETIME NOT NULL DEFAULT 0 AFTER `lastlogin`; 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); -- upgrade to better hashes ($6$, 20000 loops) in membres and ftpusers
ALTER TABLE `ftpusers` MODIFY `encrypted_password` varchar(255); 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 -- upgrade to merge alternc-ssl into alternc + change the way we work on SSL
DROP TABLE IF EXISTS `certif_alias`; DROP TABLE IF EXISTS `certif_alias`;
ALTER TABLE `certificates` ALTER TABLE `certificates`
@ -28,7 +37,8 @@ ALTER TABLE `domaines_type`
UPDATE `domaines_type` SET `has_https_option`=1 WHERE name='vhost'; UPDATE `domaines_type` SET `has_https_option`=1 WHERE name='vhost';
-- Backport old certif_hosts data to sub_domaines -- 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`; DROP TABLE IF EXISTS `certif_hosts`;
-- Set https status (http,https,both) -- 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 `https` = "http" WHERE https = '';
UPDATE `sub_domaines` SET `type` = REPLACE(`type`,'-ssl',''); UPDATE `sub_domaines` SET `type` = REPLACE(`type`,'-ssl','');
UPDATE `sub_domaines` SET `type` = REPLACE(`type`,'-mixssl',''); UPDATE `sub_domaines` SET `type` = REPLACE(`type`,'-mixssl','');
-- Disable https status when domains_type don't provide this -- 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); 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 UPDATE sub_domaines AS sd INNER JOIN
(SELECT MIN(id) id FROM `sub_domaines` GROUP BY domaine,sub,type HAVING count(id) > 1) sd1 (SELECT MIN(id) id FROM `sub_domaines` GROUP BY domaine,sub,type HAVING count(id) > 1) sd1
ON sd.id = sd1.id ON sd.id = sd1.id
SET `https` = "both"; SET `https` = "both";
-- Delete duplicate lines -- 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 -- we need to regenerate all vhost, they will be by AlternC.install
-- UPDATE `sub_domaines` SET `web_action` = 'UPDATE'; -- UPDATE `sub_domaines` SET `web_action` = 'UPDATE';
-- change some variable names : -- change some variable names :
UPDATE variable UPDATE variable
@ -72,6 +83,6 @@ DELETE FROM variable WHERE name IN (
'ftp_human_name' '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 ''; ALTER TABLE `domaines_type` CHANGE `entry` `entry` TEXT DEFAULT '';

View File

@ -0,0 +1,33 @@
#!/usr/bin/php -q
<?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)
);
}

View File

@ -690,101 +690,6 @@ class m_domTest extends TestCase
); );
} }
/**
* @covers m_dom::generation_parameters
* @todo Implement testGeneration_parameters().
*/
public function testGeneration_parameters()
{
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
/**
* @covers m_dom::generation_domains_type
* @todo Implement testGeneration_domains_type().
*/
public function testGeneration_domains_type()
{
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
/**
* @covers m_dom::generate_conf_oldhook
* @todo Implement testGenerate_conf_oldhook().
*/
public function testGenerate_conf_oldhook()
{
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
/**
* @covers m_dom::generate_apacheconf
* @todo Implement testGenerate_apacheconf().
*/
public function testGenerate_apacheconf()
{
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
/**
* @covers m_dom::generation_todo
* @todo Implement testGeneration_todo().
*/
public function testGeneration_todo()
{
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
/**
* @covers m_dom::subdomain_modif_are_done
* @todo Implement testSubdomain_modif_are_done().
*/
public function testSubdomain_modif_are_done()
{
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
/**
* @covers m_dom::set_dns_action
* @todo Implement testSet_dns_action().
*/
public function testSet_dns_action()
{
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
/**
* @covers m_dom::set_dns_result
* @todo Implement testSet_dns_result().
*/
public function testSet_dns_result()
{
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
/** /**
* @covers m_dom::get_problems * @covers m_dom::get_problems

View File

@ -1,223 +0,0 @@
#!/bin/bash
# dns.sh next-gen by Fufroma
# Init some vars
. /etc/alternc/local.sh
. /usr/lib/alternc/functions.sh
# Init some other vars
ZONE_TEMPLATE="/etc/alternc/templates/bind/templates/zone.template"
NAMED_TEMPLATE="/etc/alternc/templates/bind/templates/named.template"
NAMED_CONF="/var/lib/alternc/bind/automatic.conf"
RNDC="/usr/sbin/rndc"
dns_zone_file() {
echo "/var/lib/alternc/bind/zones/$1"
}
dns_is_locked() {
local domain=$1
if [ ! -r "$(dns_zone_file $domain)" ] ; then
return 1
fi
grep "LOCKED:YES" "$(dns_zone_file $domain)"
return $?
}
dns_get_serial() {
local domain=$1
local serial=$(( $(grep "; serial" $(dns_zone_file $domain) 2>/dev/null|awk '{ print $1;}') + 1 ))
local serial2=$(date +%Y%m%d00)
if [ $serial -gt $serial2 ] ; then
echo $serial
else
echo $serial2
fi
}
dns_get_zonettl() {
local domain=$1
local zonettl=$(
$MYSQL_DO "SELECT zonettl FROM domaines d WHERE d.domaine='$domain';"
)
# default value
if [ "$zonettl" == "" ] ; then
zonettl="86400"
fi
if [ "$zonettl" -eq "0" ] ; then
zonettl="86400"
fi
echo $zonettl
}
dns_chmod() {
local domain=$1
chgrp bind $(dns_zone_file $domain)
chmod 640 $(dns_zone_file $domain)
return 0
}
dns_named_conf() {
local domain=$1
if [ ! -f "$(dns_zone_file $domain)" ] ; then
echo Error : no file $(dns_zone_file $domain)
return 1
fi
# Add the entry
grep -q "\"${domain/./\\.}\"" "$NAMED_CONF"
if [ $? -ne 0 ] ; then
local tempo=$(cat "$NAMED_TEMPLATE")
tempo=${tempo/@@DOMAINE@@/$domain}
tempo=${tempo/@@ZONE_FILE@@/$(dns_zone_file $domain)}
echo $tempo >> "$NAMED_CONF"
# Kindly ask Bind to reload its configuration
# (the zone file is already created and populated)
$RNDC reconfig
# Hook it !
run-parts --arg=dns_reconfig --arg="$domain" /usr/lib/alternc/reload.d
fi
}
dns_delete() {
local domain=$1
# Delete the zone file
if [ -w "$(dns_zone_file $domain)" ] ; then
rm -f "$(dns_zone_file $domain)"
fi
local reg_domain=${domain/./\\.}
# Remove from the named conf
local file=$(cat "$NAMED_CONF")
echo -e "$file" |grep -v "\"$reg_domain\"" > "$NAMED_CONF"
# Remove the conf from openDKIM
rm -rf "/etc/opendkim/keys/$domain"
grep -v "^$reg_domain\$" /etc/opendkim/TrustedHosts >/etc/opendkim/TrustedHosts.alternc-tmp && mv /etc/opendkim/TrustedHosts.alternc-tmp /etc/opendkim/TrustedHosts
grep -v "^alternc\._domainkey\.$reg_domain " /etc/opendkim/KeyTable >/etc/opendkim/KeyTable.alternc-tmp && mv /etc/opendkim/KeyTable.alternc-tmp /etc/opendkim/KeyTable
grep -v "^$domain alternc\._domainkey\.$reg_domain\$" /etc/opendkim/SigningTable >/etc/opendkim/SigningTable.alternc-tmp && mv /etc/opendkim/SigningTable.alternc-tmp /etc/opendkim/SigningTable
# Ask the dns server for restart
$RNDC reconfig
# Hook it !
run-parts --arg=dns_reconfig --arg="$domain" /usr/lib/alternc/reload.d
}
# DNS regenerate
dns_regenerate() {
local domain=$1
local manual_tag=";;; END ALTERNC AUTOGENERATE CONFIGURATION"
local zone_file=$(dns_zone_file $domain)
# Check if locked
dns_is_locked "$domain"
if [ $? -eq 0 ]; then
echo "DNS $domain LOCKED"
return 1
fi
# Get the serial number if there is one
local serial=$(dns_get_serial "$domain")
# Get the zone ttl
local zonettl=$(dns_get_zonettl "$domain")
# Generate the headers with the template
local file=$(cat "$ZONE_TEMPLATE")
# Add the entry
file=$(
echo -e "$file"
$MYSQL_DO "select distinct 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 sd.type=dt.name and sd.domaine='$domain' and sd.enable in ('ENABLE', 'ENABLED') order by entry ;"
)
##### Mail autodetect for thunderbird / outlook - START
# If $file contain DEFAULT_MX
if [ ! -z "$(echo -e "$file" |egrep 'DEFAULT_MX' )" ] ; then
# If $file ! contain autoconfig -> add entry
if [ -z "$(echo -e "$file" |egrep '^autoconfig' )" ] ; then
file="$(echo -e "$file" ; echo -e "autoconfig IN CNAME $FQDN.\n")"
fi
# if $file ! contain autodiscover -> add entry
if [ -z "$(echo -e "$file" |egrep '^autodiscover' )" ] ; then
file="$(echo -e "$file" ; echo -e "autodiscover IN CNAME $FQDN.\n")"
fi
fi # End if containt DEFAULT_MX
##### Mail autodetect for thunderbird / outlook - END
##### OpenDKIM signature management - START
# If $file contain DEFAULT_MX
if [ ! -z "$(echo -e "$file" |egrep 'DEFAULT_MX' )" ] ; then
# If necessary, we generate the key:
if [ ! -d "/etc/opendkim/keys/$domain" ] ; then
mkdir -p "/etc/opendkim/keys/$domain"
pushd "/etc/opendkim/keys/$domain" >/dev/null
opendkim-genkey -r -d "$domain" -s "alternc"
chown opendkim:opendkim alternc.private
popd
local reg_domain=${domain/./\\.}
grep -q "^$reg_domain\$" /etc/opendkim/TrustedHosts || echo "$domain" >>/etc/opendkim/TrustedHosts
grep -q "^alternc\._domainkey\.$reg_domain " /etc/opendkim/KeyTable || echo "alternc._domainkey.$domain $domain:alternc:/etc/opendkim/keys/$domain/alternc.private" >> /etc/opendkim/KeyTable
grep -q "^$domain alternc\._domainkey\.$reg_domain\$" /etc/opendkim/SigningTable || echo "$domain alternc._domainkey.$domain" >> /etc/opendkim/SigningTable
fi
# we add alternc._domainkey with the proper key
if [ -r "/etc/opendkim/keys/$domain/alternc.txt" ] ; then
file="$(echo -e "$file" ; cat "/etc/opendkim/keys/$domain/alternc.txt")"
fi
fi
##### OpenDKIM signature management - END
# Replace the vars by their values
# Here we can add dynamic value for the default MX
file=$( echo -e "$file" | sed -e "
s/%%fqdn%%/$FQDN/g;
s/%%ns1%%/$NS1_HOSTNAME/g;
s/%%ns2%%/$NS2_HOSTNAME/g;
s/%%DEFAULT_MX%%/$DEFAULT_MX/g;
s/%%DEFAULT_SECONDARY_MX%%/$DEFAULT_SECONDARY_MX/g;
s/@@fqdn@@/$FQDN/g;
s/@@ns1@@/$NS1_HOSTNAME/g;
s/@@ns2@@/$NS2_HOSTNAME/g;
s/@@DEFAULT_MX@@/$DEFAULT_MX/g;
s/@@DEFAULT_SECONDARY_MX@@/$DEFAULT_SECONDARY_MX/g;
s/@@DOMAINE@@/$domain/g;
s/@@SERIAL@@/$serial/g;
s/@@PUBLIC_IP@@/$PUBLIC_IP/g;
s/@@ZONETTL@@/$zonettl/g;
" )
# Add the manually entered resource records (after the special tag ;;; END ALTERNC AUTOGENERATE CONFIGURATION)
if [ -r "$zone_file" ] ; then
file=$(
echo -e "$file"
grep -A 10000 "$manual_tag" "$zone_file"
)
fi
# Add the special tag at the end of the zone, if it is not here yet:
if ! echo -e "$file" | grep -q "$manual_tag"
then
file=$(echo -e "$file"; echo "$manual_tag")
fi
# Init the file
echo -e "$file" > "$zone_file"
# And set his rights
dns_chmod $domain
# Add it to named conf
dns_named_conf $domain
# Hook it !
run-parts --arg=dns_reload_zone --arg="$domain" /usr/lib/alternc/reload.d
# ask bind to reload the zone
$RNDC reload $domain
}

View File

@ -1,225 +0,0 @@
#!/bin/bash
. /usr/lib/alternc/functions.sh
TEMPLATE_DIR="/etc/alternc/templates/apache2"
HOSTING_DIR="/etc/alternc/functions_hosting"
HTML_HOME="$ALTERNC_HTML"
VHOST_DIR="/var/lib/alternc/apache-vhost"
launch_hooks() {
local ACTION=$1
if [ ! $2 ] ; then
# If no VTYPE specified
return 0
fi
local VTYPE=$2
EXITCODE=0
if [ -x "$HOSTING_DIR/hosting_$VTYPE.sh" ] ; then
# If a specific script exist for this VTYPE,
# we launch it, and return his return code
"$HOSTING_DIR/hosting_$VTYPE.sh" "$1" "$2" "$3" "$4"
EXITCODE=$?
fi
# also launch ssl update domains hook
/usr/lib/alternc/update_certs.sh "$1" "$2" "$3" "$4"
# No specific script, return 0
return "$EXITCODE"
}
host_conffile() {
# Return the absolute path of a conf file for a FQDN
local FQDN="$1"
local U_ID=$(get_uid_by_domain "$FQDN")
local CONFFILE="$VHOST_DIR/${U_ID:(-1)}/$U_ID/$FQDN.conf"
echo $CONFFILE
return 0
}
host_create() {
# Function to create a vhost for a website
# First, it look if there is a special file for
# this type of vhost
# If there isn't, it use the default function
# and the template file provided
local VTYPE="$1"
launch_hooks "create" "$1" "$2" "$3" "$4"
if [ $? -gt 10 ] ; then
# If the hooks return a value > 10
# it's mean we do not continue the
# "default" actions
return $?
fi
# There is no special script, I use the standart template
# If I do not found template manualy define, I look
# If there is an existing template with the good name
# First, usefull vars. Some may be empty or false, it's
# OK, it will be solve in the "case" below
local FQDN=$2
local MAIL_ACCOUNT=$3
local REDIRECT=$4 # Yes, TARGET_DIR and REDIRECT are the same
local TARGET_DIR=$4 # It's used by different template
local U_ID=$(get_uid_by_domain "$FQDN")
local G_ID="$U_ID"
local USER=$(get_account_by_domain $FQDN)
local user_letter=`print_user_letter "$USER"`
local DOCUMENT_ROOT="${HTML_HOME}/${user_letter}/${USER}$TARGET_DIR"
local ACCOUNT_ROOT="${HTML_HOME}/${user_letter}/${USER}/"
local FILE_TARGET=$(host_conffile "$FQDN")
# In case VTYPE don't have the same name as the template file,
# here we can define it
local TEMPLATE=''
case $VTYPE in
# "example")
# TEMPLATE="$TEMPLATE_DIR/an-example.conf"
# ;;
*)
# No template found, look if there is some in the
# template dir
[ -r "$TEMPLATE_DIR/$VTYPE" ] && TEMPLATE="$TEMPLATE_DIR/$VTYPE"
[ ! "$TEMPLATE" ] && [ -r "$TEMPLATE_DIR/$VTYPE.conf" ] && TEMPLATE="$TEMPLATE_DIR/$VTYPE.conf"
;;
esac
# If TEMPLATE is empty, stop right here
[ ! "$TEMPLATE" ] && return 6
# Forbid generation for website with UID/GID == 0
if [[ $U_ID == 0 || $G_ID == 0 ]] ; then
log_error "Fatal error: update_domains/function_dns/host_create : FQDN = $FQDN - TYPE = $VTYPE - UID = $U_ID - GID = $G_ID . Stopping generation"
return 7
fi
# Create a new conf file
local TMP_FILE=$(mktemp "/tmp/alternc_host.XXXXXX")
cp "$TEMPLATE" "$TMP_FILE"
# Substitute special characters :
FQDN2="`echo $FQDN | sed -e 's/\\\\/\\\\\\\\/g' -e 's/#/\\\\#/g' -e 's/&/\\\\\\&/g'`"
DOCUMENT_ROOT2="`echo $DOCUMENT_ROOT | sed -e 's/\\\\/\\\\\\\\/g' -e 's/#/\\\\#/g' -e 's/&/\\\\\\&/g'`"
ACCOUNT_ROOT2="`echo $ACCOUNT_ROOT | sed -e 's/\\\\/\\\\\\\\/g' -e 's/#/\\\\#/g' -e 's/&/\\\\\\&/g'`"
REDIRECT2="`echo $REDIRECT | sed -e 's/\\\\/\\\\\\\\/g' -e 's/#/\\\\#/g' -e 's/&/\\\\\\&/g'`"
USER2="`echo $USER | sed -e 's/\\\\/\\\\\\\\/g' -e 's/#/\\\\#/g' -e 's/&/\\\\\\&/g'`"
# Put the good value in the conf file
sed -i \
-e "s#%%LOGIN%%#$USER#g" \
-e "s#%%fqdn%%#$FQDN2#g" \
-e "s#%%document_root%%#$DOCUMENT_ROOT2#g" \
-e "s#%%account_root%%#$ACCOUNT_ROOT2#g" \
-e "s#%%redirect%%#$REDIRECT2#g" \
-e "s#%%UID%%#$U_ID#g" \
-e "s#%%GID%%#$G_ID#g" \
-e "s#%%mail_account%%#$MAIL_ACCOUNT#g" \
-e "s#%%user%%#$USER2#g" \
$TMP_FILE
## Fix for wildcard
if [[ "$FQDN2" == "*."* ]]; then
sed -i "s/ServerName/ServerAlias/" $TMP_FILE
fi
# Check if all is right in the conf file
# If not, put a debug message
# NO : redirect and document_root COULD contains legitimate %% expressions (...)
# local ISNOTGOOD=$(grep "%%" "$TMP_FILE")
# [ "$ISNOTGOOD" ] && (echo "# There was a probleme in the generation : $ISNOTGOOD" > "$TMP_FILE" ; return 44 )
# Put the conf file in prod
mkdir -p "$(dirname "$FILE_TARGET")"
mv -f "$TMP_FILE" "$FILE_TARGET"
# Execute post-install hooks
launch_hooks "postinst" "$1" "$2" "$3" "$4"
if [ $? -gt 10 ] ; then
# If the hooks return a value > 10
# it's mean we do not continue the
# "default" actions
return $?
fi
# All is quit, we return 0
return 0
}
host_disable() {
host_change_enable "disable" "$1" "$2" "$3" "$4"
}
host_enable() {
host_change_enable "enable" "$1" "$2" "$3" "$4"
}
host_change_enable() {
# Function to enable or disable a host
local STATE=$1
# Execute hooks
launch_hooks "$1" "$2" "$3" "$4"
if [ $? -gt 10 ] ; then
# If the hooks return a value > 10
# it's mean we do not continue the
# "default" actions
return $?
fi
local TYPE=$2 # no use here, but one day, maybe... So here he is
local FQDN=$3
local FENABLED=$(host_conffile "$FQDN")
local FDISABLED="$FENABLED-disabled"
case $STATE in
"enable")
local SOURCE="$FDISABLED"
local TARGET="$FENABLED"
;;
"disable")
local TARGET="$FDISABLED"
local SOURCE="$FENABLED"
;;
*)
return 1
;;
esac
if [ ! -e "$TARGET" ] && [ -e "$SOURCE" ] ; then
# If the "target" file do not exist and the "source" file exist
mv -f "$SOURCE" "$TARGET"
else
return 2
fi
}
host_delete() {
local VTYPE=$1
local FQDN=$2
# Execute post-install hooks
launch_hooks "delete" "$1" "$2" "$3" "$4"
if [ $? -gt 10 ] ; then
# If the hooks return a value > 10
# it's mean we do not continue the
# "default" actions
return $?
fi
# Fix of a longstanding BUG: we only DELETE the vhost file if the type is a vhost one !
if [ -f "${TEMPLATE_DIR}/${VTYPE}.conf" ]
then
local FENABLED=$(host_conffile "$FQDN")
local FDISABLED="$FENABLED-disabled"
[ -w "$FENABLED" ] && rm -f "$FENABLED"
[ -w "$FDISABLED" ] && rm -f "$FDISABLED"
fi
}

View File

@ -1,85 +0,0 @@
#!/usr/bin/php -q
<?php
/**
*
* Generate Apache configuration for AlternC
*
* To force generation, /launch/generate_apache_conf.php force
*
* Return the number of vhost modified, return 0 if no action
*
**/
require_once("/usr/share/alternc/panel/class/config_nochk.php");
ini_set("display_errors", 1);
/*
FIXME :
- add security check
*/
// Check if we can modify Apache conf
@touch(ALTERNC_VHOST_FILE);
if ( ! is_writable( ALTERNC_VHOST_FILE )) {
die("Error: ".ALTERNC_VHOST_FILE." is not writable\n");
}
// Do we need to regenerate apache conf ?
$db->query("select count(*) as c from sub_domaines where web_action != 'OK';");
if (! $db->next_record()) $nb_todo = 0;
$nb_todo = $db->f('c');
// But, we may have forced it
if ( ! in_array('force', $argv) && $nb_todo < 1) {
die('0');
}
$todo = $dom->generation_todo();
$parameters = $dom->generation_parameters();
// Generate apache conf
$conf = $dom->generate_apacheconf();
if (! $conf) {
die("Error: generate empty configuration\n");
}
// Add some headers
$conf2 = "###BEGIN OF ALTERNC AUTO-GENERATED FILE - DO NOT EDIT MANUALLY###
# Generation: ".date('Y-m-d H:i:s');
// Do we need to include manual configuration ?
if ( is_dir( ALTERNC_VHOST_MANUALCONF ) ) {
$conf2.="\n## Manual VHOST\nInclude ".ALTERNC_VHOST_MANUALCONF."\n" ;
} else {
$conf2.="\n## Manual VHOST directory missing (".ALTERNC_VHOST_MANUALCONF.")\n" ;
}
$conf2.="\n$conf\n\n###END OF ALTERNC AUTO-GENERATED FILE - DO NOT EDIT MANUALLY###\n";
// Write the conf !
if (! file_put_contents(ALTERNC_VHOST_FILE, $conf2) ) {
die("Error: writing content\n");
}
// Update the database to inform that we did the job
foreach ( $todo as $taction=>$tlist){
foreach ($tlist as $ttype) {
foreach($ttype as $tid) {
$dom->subdomain_modif_are_done($tid, $taction);
}
}
}
// Hooks !
foreach (array('DELETE', 'CREATE', 'UPDATE', 'ENABLE', 'DISABLE') as $y) {
if (!isset($todo[$y]) || empty($todo[$y])) continue;
$dom->generate_conf_oldhook($y, $todo); // old hooks for compatibility
$hooks->invoke("hook_genconf", array($y, $todo[$y], $parameters)); // modern hooks
}
echo $nb_todo;

View File

@ -1,24 +0,0 @@
#!/usr/bin/php -q
<?php
/**
*
* Generate Bind configuration for AlternC
*
* To force generation, /launch/generate_bind_conf.php --force
*
*
**/
require_once("/usr/share/alternc/panel/class/config_nochk.php");
ini_set("display_errors", 1);
$bind = new system_bind();
$force = false;
if (in_array('--force', $argv)) { // Want to force
$force=true;
}
$bind->regenerate_conf($force);

View File

@ -4,7 +4,6 @@
. /usr/lib/alternc/functions.sh . /usr/lib/alternc/functions.sh
echo "This script will rebuild all web configuration and regenerate DNS." echo "This script will rebuild all web configuration and regenerate DNS."
echo "Only files in $VHOST_MANUALCONF will be preserved."
echo "Use --force to skip confirmation" echo "Use --force to skip confirmation"
if [ ! "$1" == "--force" ] ; then if [ ! "$1" == "--force" ] ; then
@ -20,7 +19,6 @@ mysql_query "update domaines set dns_action = 'UPDATE' WHERE dns_action != '
echo "Now launching update_domains to rebuild." echo "Now launching update_domains to rebuild."
/usr/lib/alternc/update_domains.sh /usr/lib/alternc/update_domains.sh
/usr/lib/alternc/generate_bind_conf.php --force
echo "Finish." echo "Finish."

10
src/update_domains.php Normal file
View File

@ -0,0 +1,10 @@
#!/usr/bin/php -q
<?php
// bootstrap
require_once("/usr/share/alternc/panel/class/config_nochk.php");
putenv("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
$dom->update_domains();

View File

@ -1,168 +1,5 @@
#!/bin/bash #!/bin/bash
# Update domain next-gen by fufroma # This is now done using PHP-only scripting
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
for CONFIG_FILE in \ /usr/lib/alternc/update_domains.php
/etc/alternc/local.sh \
/usr/lib/alternc/functions.sh \
/usr/lib/alternc/functions_hosting.sh \
/usr/lib/alternc/functions_dns.sh
do
if [ ! -r "$CONFIG_FILE" ]; then
echo "Can't access $CONFIG_FILE."
exit 1
fi
. "$CONFIG_FILE"
done
stop_if_jobs_locked
# Some vars
umask 022
LOCK_FILE="/usr/share/alternc/panel/cron.lock" # FIXME doesn't seem clean to be here
OLDIFS="$IFS"
NEWIFS=" "
RELOAD_WEB="$(mktemp /tmp/alternc_reload_web.XXXX)"
RELOAD_DNS="$(mktemp /tmp/alternc_reload_dns.XXXX)"
B="µµ§§" # Strange letters to make split in query
# Somes check before start operations
if [ `id -u` -ne 0 ]; then
log_error "must be launched as root"
elif [ -z "$DEFAULT_MX" -o -z "$PUBLIC_IP" ]; then
log_error "Bad configuration. Please use: dpkg-reconfigure alternc"
elif [ -f "$LOCK_FILE" ]; then
process=$(ps f -p `cat "$LOCK_FILE"|tail -1`|tail -1|awk '{print $NF;}')
if [ "$(basename $process)" = "$(basename "$0")" ] ; then
log_error "last cron unfinished or stale lock file ($LOCK_FILE)."
else
rm "$LOCK_FILE"
fi
fi
# backward compatibility: single-server setup
if [ -z "$ALTERNC_SLAVES" ] ; then
ALTERNC_SLAVES="localhost"
fi
# We lock the application
echo $$ > "$LOCK_FILE"
echo "" > "$RELOAD_WEB"
echo "" > "$RELOAD_DNS"
# For domains we want to delete completely, make sure all the tags are all right
# set sub_domaines.web_action = delete where domaines.dns_action = DELETE
mysql_query "update sub_domaines sd, domaines d set sd.web_action = 'DELETE' where sd.domaine = d.domaine and sd.compte=d.compte and d.dns_action = 'DELETE';"
# Sub_domaines we want to delete
# sub_domaines.web_action = delete
for sub in $( mysql_query "select concat_ws('$B',lower(sd.type), if(length(sd.sub)>0,concat_ws('.',sd.sub,sd.domaine),sd.domaine)) from sub_domaines sd where web_action ='DELETE';") ; do
host_delete ${sub/$B/ }
mysql_query "delete from sub_domaines where concat_ws('$B',lower(type), if(length(sub)>0,concat_ws('.',sub,domaine),domaine)) = '$sub' and web_action ='DELETE';"
echo 1 > "$RELOAD_WEB"
done
# Sub domaines we want to update
# sub_domaines.web_action = update and sub_domains.only_dns = false
IFS="$NEWIFS"
mysql_query "
select concat_ws('$IFS',sd.id, lower(sd.type), if(length(sd.sub)>0,concat_ws('.',sd.sub,sd.domaine),sd.domaine), concat_ws('@',m.login,v.value), sd.valeur )
from sub_domaines sd,membres m,variable v
where sd.compte=m.uid and sd.web_action ='UPDATE' and v.name='mailname_bounce'
;" | while read sdid type domain mail valeur ; do
host_create "$type" "$domain" "$mail" "$valeur"
mysql_query "update sub_domaines sd set web_action='OK',web_result='$?' where sd.id = '$sdid' ; "
echo 1 > "$RELOAD_WEB"
done
# Domaine to enable
mysql_query "select concat_ws('$IFS',sd.id, lower(sd.type),if(length(sd.sub)>0,concat_ws('.',sd.sub,sd.domaine),sd.domaine),sd.valeur) from sub_domaines sd where sd.enable ='ENABLE' ;"|while read sdid type domain valeur ; do
host_enable "$type" "$domain" "$valeur"
mysql_query "update sub_domaines sd set enable='ENABLED' where sd.id = '$sdid' ;"
echo 1 > "$RELOAD_WEB"
done
# Domains to disable
mysql_query "select concat_ws('$IFS', sd.id, lower(sd.type),if(length(sd.sub)>0,concat_ws('.',sd.sub,sd.domaine),sd.domaine),sd.valeur) from sub_domaines sd where sd.enable ='DISABLE' ;"|while read sdid type domain valeur ; do
host_disable "$type" "$domain" "$valeur"
mysql_query "update sub_domaines sd set enable='DISABLED' where sd.id = '$sdid' ;"
echo 1 > "$RELOAD_WEB"
done
# Domains we do not want to be the DNS serveur anymore :
# domaines.dns_action = UPDATE and domaines.gesdns = 0
for dom in `mysql_query "select domaine from domaines where dns_action = 'UPDATE' and gesdns = 0;"| tr '\n' ' '`
do
dns_delete $dom
mysql_query "update domaines set dns_action = 'OK', dns_result = '$?' where domaine = '$dom'"
echo 1 >"$RELOAD_DNS"
done
# Domains we have to update the dns :
# domaines.dns_action = UPDATE
for dom in `mysql_query "select domaine from domaines where dns_action = 'UPDATE';" | tr '\n' ' '`
do
echo "dns_regenerate : domain=/$dom/"
dns_regenerate $dom
mysql_query "update domaines set dns_action = 'OK', dns_result = '$?' where domaine = '$dom'"
echo 1 >"$RELOAD_DNS"
done
# Domains we want to delete completely, now we do it
# domaines.dns_action = DELETE
for dom in `mysql_query "select domaine from domaines where dns_action = 'DELETE';" | tr '\n' ' '`
do
dns_delete $dom
# Web configurations have already bean cleaned previously
mysql_query "delete from sub_domaines where domaine='$dom'; delete from domaines where domaine='$dom';"
echo 1 >"$RELOAD_DNS"
done
if [ ! -z "$(cat "$RELOAD_WEB")" ] ; then
# Just to encourage user to use THIS directory and not another one
test -d "$VHOST_MANUALCONF" || mkdir -p "$VHOST_MANUALCONF"
# Concat the apaches files
tempo=$(mktemp "$VHOST_FILE.XXXXX")
(
echo "###BEGIN OF ALTERNC AUTO-GENERATED FILE - DO NOT EDIT MANUALLY###"
find "$VHOST_DIR"/ -mindepth 2 -type f -iname "*.conf" -print0 | xargs -0 cat
echo "###END OF ALTERNC AUTO-GENERATED FILE - DO NOT EDIT MANUALLY###"
) > "$tempo"
if [ $? -ne 0 ] ; then
log_error " web file concatenation failed"
fi
touch "$VHOST_FILE"
if [ ! -w "$VHOST_FILE" ] ; then
log_error "cannot write on $VHOST_FILE"
fi
mv "$tempo" "$VHOST_FILE"
# We must reload apache
# we assume we run apache on the master
/usr/lib/alternc/alternc_reload apache || true
# Launch hooks for apache reload
run-parts --arg=web_reload /usr/lib/alternc/reload.d
fi
# If we added / edited / deleted at least one dns zone file, we go here in the end:
if [ ! -z "$(cat "$RELOAD_DNS")" ] ; then
service opendkim restart
run-parts --arg=dns_reload /usr/lib/alternc/reload.d
fi
## FIXME : move the slave part into the /usr/lib/alternc/reload.d directory to be an hook
#for slave in $ALTERNC_SLAVES; do
# if [ "$slave" != "localhost" ]; then
# ssh alternc@$slave alternc_reload 'apache' || true
# fi
#done
rm -f "$LOCK_FILE" "$RELOAD_ZONES" "$RELOAD_WEB" "$INOTIFY_UPDATE_DOMAIN" "$RELOAD_DNS"
exit 0