+
diff --git a/bureau/admin/reset.php b/bureau/admin/reset.php
new file mode 100644
index 00000000..796998d0
--- /dev/null
+++ b/bureau/admin/reset.php
@@ -0,0 +1,15 @@
+temporary_login($_GET['uid'], $_GET['timestamp'],
+ $_GET['token']);
+ if ($logged_in) {
+ $msg->raise('INFO', 'admin/reset', _('Please change your password'));
+ header("Location: /mem_param.php");
+ exit;
+ }
+}
+header("Location: /index.php");
diff --git a/bureau/class/class_system_bind.php b/bureau/class/class_system_bind.php
deleted file mode 100644
index 698b9939..00000000
--- a/bureau/class/class_system_bind.php
+++ /dev/null
@@ -1,525 +0,0 @@
-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);
- $hooks->invoke_scripts("/usr/lib/alternc/reload.d", array('dns_reload_zone', $domain) );
- $this->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 */
-
diff --git a/bureau/class/db_mysql.php b/bureau/class/db_mysql.php
index 8e5a3c36..9ec79968 100644
--- a/bureau/class/db_mysql.php
+++ b/bureau/class/db_mysql.php
@@ -242,6 +242,26 @@ class DB_Sql {
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
*/
diff --git a/bureau/class/functions.php b/bureau/class/functions.php
index b9c94817..cd9e782c 100755
--- a/bureau/class/functions.php
+++ b/bureau/class/functions.php
@@ -1245,3 +1245,54 @@ function _dovecot_hash($password) {
$hash = _sha512cr($password);
return '{SHA512-CRYPT}' . $hash;
}
+
+
+// ------------------------------------------------------------
+/**
+ * Add the line of text $line into file $file.
+ * do not duplicate (check)
+ * @param $file string the full path to the file where we should add the line
+ * @param $line string the line to add (without the termination \n, WILL BE ADDED)
+ * @return boolean TRUE if the line has been added, or FALSE if the line ALREADY EXISTED
+ */
+function add_line_to_file($file,$line) {
+ $f=fopen($file,"rb");
+ $found=false;
+ while($s=fgets($f,1024)) {
+ if (trim($s)==$line) {
+ $found=true;
+ return false;
+ }
+ }
+ fclose($f);
+ $f=fopen($file,"ab");
+ fputs($f,trim($line)."\n");
+ fclose($f);
+ return true;
+}
+
+
+// ------------------------------------------------------------
+/**
+ * Remove the line of text $line from file $file.
+ * @param $file string the full path to the file where we should remove the line
+ * @param $line string the line to add (without the termination \n, WILL BE REMOVED)
+ * @return boolean TRUE if the line has been found and removed, or FALSE if the line DIDN'T EXIST
+ */
+function del_line_from_file($file,$line) {
+ $f=fopen($file,"rb");
+ $g=fopen($file.".new","wb");
+ $found=false;
+ while($s=fgets($f,1024)) {
+ if (trim($s)!=$line) {
+ fputs($g,$s);
+ } else {
+ $found=true;
+ }
+ }
+ fclose($f);
+ fclose($g);
+ rename($file.".new",$file); // overwrite atomically
+ return $found;
+}
+
diff --git a/bureau/class/m_action.php b/bureau/class/m_action.php
index 0c0aca29..27351686 100644
--- a/bureau/class/m_action.php
+++ b/bureau/class/m_action.php
@@ -241,7 +241,7 @@ class m_action {
* @global m_messages $msg
* @global m_mysql $db
* @param type $all
- * @return boolean
+ * @return boolean|int The number of rows purged; False is there was an error
*/
function purge($all = null) {
global $msg, $db;
diff --git a/bureau/class/m_apache.php b/bureau/class/m_apache.php
new file mode 100644
index 00000000..8371f039
--- /dev/null
+++ b/bureau/class/m_apache.php
@@ -0,0 +1,185 @@
+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,$msg;
+ $db->query("SELECT sd.*, dt.only_dns, dt.has_https_option, m.login FROM domaines_type dt, sub_domaines sd LEFT JOIN membres m ON m.uid=sd.compte WHERE dt.name=sd.type AND sd.web_action!='OK' AND id=?;",array($subdomid));
+ $db->next_record();
+ $subdom=$db->Record;
+ $confdir = $this->vhostroot."/".substr($subdom["compte"],-1)."/".$subdom["compte"];
+ $deleteme= $subdom["sub"].(($subdom["sub"])?".":"").$subdom["domaine"].".conf";
+ @unlink($confdir."/".$deleteme);
+ $this->shouldreload=true;
+ }
+
+
+ // ------------------------------------------------------------
+ /**
+ * 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
+
diff --git a/bureau/class/m_bind.php b/bureau/class/m_bind.php
new file mode 100644
index 00000000..5403de51
--- /dev/null
+++ b/bureau/class/m_bind.php
@@ -0,0 +1,238 @@
+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
+
diff --git a/bureau/class/m_dom.php b/bureau/class/m_dom.php
index 64d50a7f..7d94e238 100644
--- a/bureau/class/m_dom.php
+++ b/bureau/class/m_dom.php
@@ -54,15 +54,7 @@ class m_dom {
* du domaine par update_domains.sh
* @access private
*/
- var $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;
+ const fic_lock_cron = "/run/alternc/cron.lock";
var $type_local = "VHOST";
var $type_url = "URL";
@@ -84,9 +76,10 @@ class m_dom {
* Constructeur
*/
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'));
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
* @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
*/
- function del_domain($dom) {
+ function del_domain($domain) {
global $db, $msg, $hooks;
- $msg->log("dom", "del_domain", $dom);
- $dom = strtolower($dom);
+ $msg->log("dom", "del_domain", $domain);
+ $domain = strtolower($domain);
$this->lock();
- if (!$r = $this->get_domain_all($dom)) {
+ if (!$r = $this->get_domain_all($domain)) {
return false;
}
$this->unlock();
// 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
- $hooks->invoke("alternc_del_domain", array($dom));
- $hooks->invoke("alternc_del_mx_domain", array($dom));
+ $hooks->invoke("alternc_del_domain", array($domain));
+ $hooks->invoke("alternc_del_mx_domain", array($domain));
// New hook calls:
$hooks->invoke("hook_dom_del_domain", array($r["id"]));
$hooks->invoke("hook_dom_del_mx_domain", array($r["id"]));
// Now mark the domain for deletion:
- $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ?;", array($dom));
- $this->set_dns_action($dom, 'DELETE');
+ $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ?;", array($domain));
+ $this->set_dns_action($domain, 'DELETE');
return true;
}
- function domshort($dom, $sub = "") {
- return str_replace("-", "", str_replace(".", "", empty($sub) ? "" : "$sub.") . $dom);
+ function domshort($domain, $sub = "") {
+ 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.
*/
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);
// Locked ?
- if (!$this->islocked) {
+ if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false;
}
@@ -1037,10 +1030,10 @@ class m_dom {
*
*/
function get_domain_all($dom) {
- global $db, $msg, $cuid;
+ global $db, $msg, $cuid, $domislocked;
$msg->debug("dom", "get_domain_all", $dom);
// Locked ?
- if (!$this->islocked) {
+ if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
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));
// Pas de webmail, on le cochera si on le trouve.
$r["sub"] = array();
- $data = $db->fetchAll();
- foreach($data as $i=>$record) {
+ $i=0;
+ while ($record=$db->fetch()) {
$r["sub"][$i] = $record;
// 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]["dest"] = $record["valeur"];
$r["sub"][$i]["fqdn"] = ((!empty($r["sub"][$i]["name"])) ? $r["sub"][$i]["name"] . "." : "") . $r["name"];
+ $i++;
}
$db->free();
return $r;
@@ -1098,10 +1092,10 @@ class m_dom {
* Retourne FALSE si une erreur s'est produite.
*/
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);
// Locked ?
- if (!$this->islocked) {
+ if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false;
}
@@ -1263,10 +1257,10 @@ class m_dom {
* @return boolean true if the preference has been set
*/
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);
// Locked ?
- if (!$this->islocked) {
+ if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false;
}
@@ -1308,13 +1302,14 @@ class m_dom {
* de $type (url, ip, dossier...)
* @param string $https the HTTPS behavior : HTTP(redirect https to http),
* 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.
*/
- function set_sub_domain($dom, $sub, $type, $dest, $sub_domain_id = 0, $https) {
- global $db, $msg, $cuid, $bro;
+ function set_sub_domain($dom, $sub, $type, $dest, $sub_domain_id = 0, $https="") {
+ global $db, $msg, $cuid, $bro, $domislocked;
$msg->log("dom", "set_sub_domain", $dom . "/" . $sub . "/" . $type . "/" . $dest);
// Locked ?
- if (!$this->islocked) {
+ if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false;
}
@@ -1396,10 +1391,10 @@ class m_dom {
*
*/
function del_sub_domain($sub_domain_id) {
- global $db, $msg;
+ global $db, $msg, $domislocked;
$msg->log("dom", "del_sub_domain", $sub_domain_id);
// Locked ?
- if (!$this->islocked) {
+ if (!$domislocked) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false;
}
@@ -1442,11 +1437,11 @@ class m_dom {
* TRUE sinon.
*
*/
- function edit_domain($dom, $dns, $gesmx, $force = false, $ttl = 86400) {
- global $db, $msg, $hooks;
+ function edit_domain($dom, $dns, $gesmx, $force = false, $ttl = 3600) {
+ global $db, $msg, $hooks, $domislocked;
$msg->log("dom", "edit_domain", $dom . "/" . $dns . "/" . $gesmx);
// Locked ?
- if (!$this->islocked && !$force) {
+ if (!$domislocked && !$force) {
$msg->raise("ERROR", "dom", _("--- Program error --- No lock on the domains!"));
return false;
}
@@ -1765,15 +1760,20 @@ class m_dom {
* @access private
*/
function lock() {
- global $msg;
+ global $msg,$domislocked;
$msg->debug("dom", "lock");
- if ($this->islocked) {
+ if ($domislocked) {
$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);
}
- $this->islocked = true;
+ @touch(m_dom::fic_lock_cron);
+ $domislocked = true;
+ // extra safe :
+ register_shutdown_function(array("m_dom","unlock"),1);
return true;
}
@@ -1783,13 +1783,15 @@ class m_dom {
* return true
* @access private
*/
- function unlock() {
- global $msg;
+ function unlock($isshutdown=0) {
+ global $msg,$domislocked;
$msg->debug("dom", "unlock");
- if (!$this->islocked) {
+ if (!$isshutdown && !$domislocked) {
$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;
}
@@ -1892,199 +1894,103 @@ class m_dom {
/**
- * Return an array with all the needed parameters to generate conf
- * of a vhost.
- * If no parameters, return the parameters for ALL the vhost.
- * Optionnal parameters: id of the sub_domaines
- * */
- function generation_parameters($id = null, $only_apache = true) {
- global $db, $msg;
- $msg->log("dom", "generation_parameters");
- $params = "";
- /** 2016_05_18 : this comments was here before escaping the request... is there still something to do here ?
- * // 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 ";
+ * complex process to manage domain and subdomain updates
+ * Launched every minute by a cron as root
+ * should launch hooks for each domain or subdomain,
+ * so that apache & bind could do their job
+ */
+ function update_domains() {
+ global $db, $hooks;
+ if (posix_getuid()!=0) {
+ echo "FATAL: please lauch me as root\n";
+ exit();
}
- $query .= "
- order by
- m.login,
- sd.domaine,
- sd.sub;";
+ $this->lock();
+ // 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);
-
- $r = array();
+ // Search for things to do on DOMAINS:
+ $db->query("SELECT * FROM domaines WHERE dns_action!='OK';");
+ $alldoms=array();
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));
+ }
-
- /**
- * Return an array with all informations of the domains_type
- * used to generate Apache conf.
- * Die if templates missing.
- * Warning: an Apache domains_type must have 'only_dns' == TRUE
- *
- * */
- function generation_domains_type() {
- global $dom;
- $d = array();
- foreach ($dom->domains_type_lst() as $k => $v) {
- if ($v['only_dns'] == true) {
- continue;
+ if ($onedom["dns_action"]=="DELETE") {
+ $db->query("DELETE FROM domaines WHERE domaine=?;",array($onedom));
+ } else {
+ // we keep the highest result returned by hooks...
+ rsort($ret,SORT_NUMERIC); $returncode=$ret[0];
+ $db->query("UPDATE domaines SET dns_result=?, dns_action='OK' WHERE domaine=?;",array($returncode,$onedom["domaine"]));
+ }
}
- if (!$j = file_get_contents(ALTERNC_APACHE2_GEN_TMPL_DIR . '/' . strtolower($k) . '.conf')) {
- 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;
+ $hooks->invoke("hook_updatedomains_dns_post");
}
- $lst_by_type = $lst_sub[strtoupper($action)];
- foreach ($lst_by_type as $type => $lid_arr) {
- $script = "/etc/alternc/functions_hosting/hosting_" . strtolower($type) . ".sh";
- if (!@is_executable($script)) {
- continue;
- }
- foreach ($lid_arr as $lid) {
- $o = $sub_obj[$lid];
- $cmd = $script . " " . escapeshellcmd(strtolower($action)) . " ";
- $cmd .= escapeshellcmd($o['fqdn']) . " " . escapeshellcmd($o['valeur']);
-
- system($cmd);
- }
- } // 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']);
+ // Search for things to do on SUB-DOMAINS:
+ $db->query("SELECT sd.*, dt.only_dns FROM domaines_type dt, sub_domaines sd WHERE dt.name=sd.type AND sd.web_action!='OK';");
+ $alldoms=array();
+ $ignore=array();
+ $delete=array();
+ while ($db->next_record()) {
+ // only_dns=1 => weird, we should not have web_action SET to something else than OK ... anyway, skip it
+ if ($db->Record["only_dns"]) {
+ if ($db->Record["web_action"]=="DELETE") {
+ $delete[]=$db->Record["id"];
+ } else {
+ $ignore[]=$db->Record["id"];
+ }
} 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
- $tpl = $gdt[$p['type']] ['tpl'];
-
- // Replace needed vars
- $tpl = strtr($tpl, array(
- "%%LOGIN%%" => $p['login'],
- "%%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;
+ if ($subdom["web_action"]=="DELETE") {
+ $db->query("DELETE FROM sub_domaines WHERE id=?;",array($id));
+ } else {
+ // we keep the highest result returned by hooks...
+ rsort($ret,SORT_NUMERIC); $returncode=$ret[0];
+ $db->query("UPDATE sub_domaines SET web_result=?, web_action='OK' WHERE id=?;",array($returncode,$id));
+ }
}
-
- // Return the conf
- $ret.= "# Sub_id: " . $p['sub_id'] . "\n" . $tpl;
+ $hooks->invoke("hook_updatedomains_web_post");
}
-
- 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
*/
@@ -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
*/
function get_problems($domain) {
@@ -2160,6 +2059,8 @@ class m_dom {
_("Default mail server");
_("Default backup mail server");
_("AlternC panel access");
+ _("DKIM Key");
+ _("Email autoconfiguration");
}
} /* Class m_domains */
diff --git a/bureau/class/m_hooks.php b/bureau/class/m_hooks.php
index 956edc4c..15754de9 100644
--- a/bureau/class/m_hooks.php
+++ b/bureau/class/m_hooks.php
@@ -53,6 +53,11 @@ class m_hooks {
// existe on l'execute et on rajoute ce qu'elle a retourné dans
// un tableau
$val = array();
+ if (!$classes) {
+ // Leaving early if classes isn't set prevents PHP warnings.
+ // Happens frequently when running PHPUnit tests.
+ return $val;
+ }
foreach ($classes as $c) {
global $$c;
if (method_exists($$c, $hname)) {
diff --git a/bureau/class/m_lxc.php b/bureau/class/m_lxc.php
index ed91a883..1f31a3c6 100644
--- a/bureau/class/m_lxc.php
+++ b/bureau/class/m_lxc.php
@@ -99,8 +99,8 @@ class m_lxc implements vm {
}
}
- $msg = serialize($params);
- if (fwrite($fp, $msg . "\n") < 0) {
+ $message = serialize($params);
+ if (fwrite($fp, $message . "\n") < 0) {
$this->error[] = 'Unable to send data';
return FALSE;
}
@@ -135,22 +135,22 @@ class m_lxc implements vm {
$pass = $pass ? $pass : $mem->user['pass'];
$uid = $uid ? $uid : $mem->user['uid'];
- $msgg = array('action' => 'start', 'login' => $login, 'pass' => $pass, 'uid' => $uid);
- $msgg['mysql_host'] = $mysql->dbus->Host;
+ $message = array('action' => 'start', 'login' => $login, 'pass' => $pass, 'uid' => $uid);
+ $message['mysql_host'] = $mysql->dbus->Host;
- $res = $this->sendMessage($msgg);
+ $res = $this->sendMessage($message);
if ($res === FALSE) {
return $this->error;
} else {
$data = unserialize($res);
$error = (int) $data['error'];
$hostname = $data['hostname'];
- $msg = $data['msg'];
+ $message = $data['msg'];
$date_start = 'NOW()';
$uid = $mem->user['uid'];
if ($error != 0) {
- $msg->raise("ERROR", 'lxc', _($msg));
+ $msg->raise("ERROR", 'lxc', _($message));
return FALSE;
}
$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;
$login = $login ? $login : $mem->user['login'];
- $msgg = array('action' => 'get', 'login' => $login);
- $res = $this->sendMessage($msgg);
+ $message = array('action' => 'get', 'login' => $login);
+ $res = $this->sendMessage($message);
if (!$res) {
return FALSE;
}
diff --git a/bureau/class/m_mail.php b/bureau/class/m_mail.php
index b7f02735..dd809fbd 100644
--- a/bureau/class/m_mail.php
+++ b/bureau/class/m_mail.php
@@ -309,7 +309,7 @@ ORDER BY
}
$db->query("SELECT a.id, a.address, a.password, a.`enabled`, a.mail_action, d.domaine AS domain, m.quota, m.quota*1024*1024 AS quotabytes, q.quota_dovecot as used, NOT ISNULL(m.id) AS islocal, a.type, r.recipients, m.lastlogin, a.domain_id
FROM ((domaines d, address a LEFT JOIN mailbox m ON m.address_id=a.id) LEFT JOIN dovecot_quota q ON CONCAT(a.address,'@',d.domaine) = q.user) LEFT JOIN recipient r ON r.address_id=a.id
- WHERE " . $where . " AND d.id=a.domain_id " . $limit . " ;", $query_args);
+ WHERE " . $where . " AND d.id=a.domain_id ORDER BY a.address ASC " . $limit . " ;", $query_args);
if (!$db->next_record()) {
$msg->raise("ERROR", "mail", _("No email found for this query"));
return array();
@@ -466,12 +466,18 @@ ORDER BY
}
}
$db->query("SELECT domaine FROM domaines WHERE id= ? ;", array($dom_id));
- if ($db->next_record()) {
- $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ? AND type='txt' AND (sub='' AND valeur LIKE 'v=spf1 %') OR (sub='_dmarc' AND valeur LIKE 'v=dmarc1;%');", array($db->Record["domaine"]));
- $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ? AND (type='defmx' OR type='defmx2');", array($db->Record["domaine"]));
- $db->query("UPDATE domaines SET dns_action='UPDATE' WHERE id= ? ;", array($dom_id));
+ if (!$db->next_record()) {
+ return false;
}
-
+ $domain=$db->Record["domaine"];
+ $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ? AND (type='defmx' OR type='defmx2');", array($domain));
+
+ $this->del_dns_dmarc($domain);
+ $this->del_dns_spf($domain);
+ $this->del_dns_autoconf($domain);
+ $this->dkim_del($domain);
+
+ $db->query("UPDATE domaines SET dns_action='UPDATE' WHERE id= ? ;", array($dom_id));
return true;
}
@@ -912,6 +918,7 @@ ORDER BY
}
+ // ------------------------------------------------------------
/**
* hook function called by AlternC when a domain is created for
* the current user account using the SLAVE DOMAIN feature
@@ -928,6 +935,7 @@ ORDER BY
}
+ // ------------------------------------------------------------
/**
* hook function called by AlternC when a domain is created for
* the current user account
@@ -937,7 +945,7 @@ ORDER BY
* @access private
*/
function hook_dom_add_mx_domain($domain_id) {
- global $msg, $mem, $db;
+ global $msg, $mem, $db, $L_FQDN;
$msg->log("mail", "hook_dom_add_mx_domain", $domain_id);
$db->query("SELECT value FROM variable where name='mailname_bounce';");
@@ -947,26 +955,30 @@ ORDER BY
}
$mailname = $db->f("value");
// set spf & dmarc for this domain
- $db->query("SELECT domaine FROM domaines WHERE id= ?;", array($domain_id));
+ $db->query("SELECT domaine,compte FROM domaines WHERE id= ?;", array($domain_id));
if ($db->next_record()) {
+ $domaine=$db->Record["domaine"];
+ $compte=$db->Record["compte"];
+ $this->set_dns_autoconf($domaine,$compte);
if ($spf = variable_get("default_spf_value")) {
- $this->set_dns_spf($db->Record["domaine"], $spf);
+ $this->set_dns_spf($domaine, $spf);
}
if ($dmarc = variable_get("default_dmarc_value")) {
- $this->set_dns_dmarc($db->Record["domaine"], $dmarc);
+ $this->set_dns_dmarc($domaine, $dmarc);
}
}
return $this->create_alias($domain_id, 'postmaster', $mem->user['login'] . '@' . $mailname);
}
+ // ------------------------------------------------------------
/**
* hook function called by variables when a variable is changed
* @access private
*/
function hook_variable_set($name, $old, $new) {
global $msg, $db;
- $msg->log("mail", "hook_variable_set($name,$old,$new)");
+ $msg->log("mail", "hook_variable_set($name,$old,$new)");
if ($name == "default_spf_value") {
$new = trim($new);
@@ -991,7 +1003,44 @@ 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;
+ }
+
+
+ // ------------------------------------------------------------
+ /**
+ * delete the autoconf / autodiscover vhosts when removing a domain as MX
+ */
+ function del_dns_autoconf($domain) {
+ global $db, $L_FQDN, $cuid;
+ $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ? AND type='autodiscover' AND sub='autoconfig';", array($domain));
+ $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ? AND type='autodiscover' AND sub='autodiscover';", array($domain));
+ }
+
+ // ------------------------------------------------------------
/**
* 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.
@@ -999,7 +1048,8 @@ ORDER BY
* @access private
*/
function set_dns_spf($domain, $spf, $previous = -1, $uid = -1, $login = -1) {
- global $db, $cuid, $mem;
+ global $db, $cuid, $mem, $msg;
+ $msg->debug("mail","set_dns_spf($domain, $spf, $previous, $uid, $login)");
// defaults
if ($uid === -1) {
$uid = intval($cuid);
@@ -1021,7 +1071,18 @@ ORDER BY
$db->query("UPDATE domaines SET dns_action='UPDATE' WHERE domaine= ?;", array($domain));
}
+ // ------------------------------------------------------------
+ /**
+ * delete the SPF entries in the sub_domaine table for a domain
+ * called by del_domain or del_mx_domain by hooks :
+ */
+ function del_dns_spf($domain) {
+ global $db;
+ $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ? AND type='txt' AND sub='' AND valeur LIKE 'v=spf1 %';", array($domain));
+ }
+
+ // ------------------------------------------------------------
/**
* 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.
@@ -1029,7 +1090,8 @@ ORDER BY
* @access private
*/
function set_dns_dmarc($domain, $dmarc, $previous = -1, $uid = -1, $login = -1) {
- global $db, $cuid, $mem, $L_FQDN;
+ global $db, $cuid, $mem, $L_FQDN, $msg;
+ $msg->debug("mail","set_dns_dmarc($domain, $dmarc, $previous, $uid, $login)");
// defaults
if ($uid === -1) {
$uid = intval($cuid);
@@ -1055,5 +1117,151 @@ ORDER BY
}
+ // ------------------------------------------------------------
+ /**
+ * delete the DMARC entries in the sub_domaine table for a domain
+ * called by del_domain or del_mx_domain by hooks :
+ */
+ function del_dns_dmarc($domain) {
+ global $db;
+ $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ? AND type='txt' AND sub='' AND valeur LIKE 'v=dmarc1 %';", array($domain));
+ }
+
+
+ /** 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"]);
+ }
+ }
+
+
+ // ------------------------------------------------------------
+ /**
+ * 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) {
+ global $db;
+ $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 */
diff --git a/bureau/class/m_mem.php b/bureau/class/m_mem.php
index 67ea1a31..5dc387ab 100644
--- a/bureau/class/m_mem.php
+++ b/bureau/class/m_mem.php
@@ -41,7 +41,6 @@ class m_mem {
*/
var $local;
-
/**
* Password kind used in this class (hook for admin class)
*/
@@ -401,10 +400,14 @@ class m_mem {
$msg->raise("ERROR", "mem", _("You are not allowed to change your password."));
return false;
}
- if (!password_verify($oldpass, $this->user['pass'])) {
- $msg->raise("ERROR", "mem", _("The old password is incorrect"));
- return false;
+
+ if ($this->requires_old_password_for_change()) {
+ if (!password_verify($oldpass, $this->user['pass'])) {
+ $msg->raise("ERROR", "mem", _("The old password is incorrect"));
+ return false;
+ }
}
+
if ($newpass != $newpass2) {
$msg->raise("ERROR", "mem", _("The new passwords are differents, please retry"));
return false;
@@ -418,11 +421,12 @@ class m_mem {
$newpass = password_hash($newpass, PASSWORD_BCRYPT);
$db->query("UPDATE membres SET pass= ? WHERE uid= ?;", array($newpass, $cuid));
$msg->init_msgs();
+ setcookie('require_old_password', '', 1);
return true;
}
- /**
+ /**
* Change the administrator preferences of an admin account
* @param integer $admlist visualisation mode of the account list (0=large 1=short)
* @return boolean TRUE if the preferences has been changed, FALSE if not.
@@ -678,4 +682,264 @@ Cordially.
return true;
}
+ /**
+ * Sends a password-reset URL.
+ */
+ public function send_reset_url($email_or_login) {
+ global $msg, $L_FQDN, $L_HOSTING, $db;
+ // Look up user by email_or_login.
+ $db->query("SELECT * FROM membres WHERE login = ? OR mail = ? ;", array($email_or_login, $email_or_login));
+
+ $msg->log('mem', 'send_reset_url', 'Password reset requested for: ' . $email_or_login);
+ // Give user feedback, even if we don't have an account stored.
+ $msg->raise('INFO', 'mem', _('An e-mail with information on how to connect has been sent to the owner of the account if one exists'));
+
+ // It is possible here that a user could have multiple accounts for a
+ // single e-mail since 'mail' is not a uniqe key in the membres table.
+ // For the moment we'll just take the first account.
+ if (!$db->num_rows()) {
+ $msg->log('mem', 'send_reset_url', 'No member found with login or mail ' . $email_or_login);
+ return FALSE;
+ }
+ if ($db->num_rows()) {
+ $db->next_record();
+ // Get a reset URL for the current timestamp.
+ $url = $this->generate_reset_url($db->f('uid'));
+ $mail = $db->f('mail');
+ }
+ if (!$url || !$mail) {
+ return FALSE;
+ }
+ $duration = variable_get('password_reset_expiration', 86400, 'The number of seconds for which a password reset link is valid');
+ $duration_hours = ($duration / 3600.0) . ' ' . _('hours');
+ $message = sprintf(_('
+Hi,
+
+someone requested a password reset for your account at %s (%s).
+
+You may connect to your account and change your account by clicking on the following URL or copying it into your browser :
+
+%s
+
+This link may only be used once. You should change your password in your account settings once connected. This link will only be valid for %s, and no changes will be made if it is not used.
+'), $L_HOSTING, $L_FQDN, $url, $duration_hours);
+ mail($mail, "Password reset request on {$L_HOSTING}", $message, "From: postmaster@{$L_FQDN}\nReply-to: postmaster@{$L_FQDN}");
+ $msg->log('mem', 'send_reset_url', "Password reset e-mail sent for account {$uid} at {$mail}");
+ }
+
+ /**
+ * Generate a reset URL for an account given it's e-mail or login.
+ *
+ * @param $email_or_login
+ * A string with the email or login.
+ *
+ * @returns string|boolean
+ * A reset URL or FALSE in case of error.
+ */
+ function generate_reset_url($uid) {
+ global $db;
+ $db->query("SELECT * FROM membres WHERE uid = ? ;", array($uid));
+ if (!$db->num_rows()) {
+ return FALSE;
+ }
+ if ($db->num_rows()) {
+ $db->next_record();
+ // Get a reset URL for the current timestamp.
+ return $this->_get_reset_url(time(), $db->f('uid'), $db->f('login'), $db->f('pass'));
+ }
+ return FALSE;
+ }
+
+ /**
+ * Builds a full reset URL from the uid, login, password and timestamp.
+ *
+ * @returns string
+ * A full URL.
+ */
+ function _get_reset_url($timestamp, $uid, $login, $password) {
+ global $db, $L_FQDN;
+ $salt = variable_get('salt_password_reset', base64_encode(random_bytes(128)), 'The salt used when hasing password resets - change to invalidate all existing reset tokens') . $password;
+ $data = $timestamp . $uid . $login;
+ $token = hash_hmac('sha512', $data, $salt);
+ // @TODO: Not sure where the bureau's preferred protocol is stored, but
+ // since 3.5.0 https seems to be the default.
+ return 'https://' . $L_FQDN . '/reset.php?' . http_build_query(array(
+ 'uid' => $uid,
+ 'timestamp' => $timestamp,
+ 'token' => $token,
+ ));
+ }
+
+ /**
+ * Logs a user in from a one-time login link.
+ */
+ function temporary_login($uid, $timestamp, $token, $restrictip = 0, $authip_token = false) {
+ global $db, $msg, $cuid, $authip;
+ if (!$this->validate_reset_url($uid, $timestamp, $token)) {
+ return FALSE;
+ }
+ $msg->log("mem", "temporary_login", $username);
+ if ($msg->has_msgs("ERROR")) {
+ return FALSE;
+ }
+
+ $db->query("select * from membres where uid= ? ;", array($uid));
+ if ($db->num_rows() == 0) {
+ return FALSE;
+ }
+ $db->next_record();
+
+ // No password verification for temporary logins, the validation
+ // is in validate_reset_url instead.
+ if (!$db->f("enabled")) {
+ $msg->raise("ERROR", "mem", _("This account is locked, contact the administrator."));
+ return FALSE;
+ }
+
+ $this->user = $db->Record;
+ $cuid = $db->f("uid");
+ if (panel_islocked() && $cuid != 2000) {
+ $msg->raise("ALERT", "mem", _("This website is currently under maintenance, login is currently disabled."));
+ return FALSE;
+ }
+
+ // AuthIP
+ $allowed_ip = FALSE;
+ if ($authip_token) {
+ $allowed_ip = $this->authip_tokencheck($authip_token);
+ }
+
+ $aga = $authip->get_allowed('panel');
+ foreach ($aga as $k => $v) {
+ if ($authip->is_in_subnet(get_remote_ip(), $v['ip'], $v['subnet'])) {
+ $allowed = TRUE;
+ }
+ }
+
+ // Error if there is rules, the IP is not allowed and it's not in the whitelisted IP
+ if (sizeof($aga) > 1 && !$allowed_ip && !$authip->is_wl(get_remote_ip())) {
+ $msg->raise("ERROR", "mem", _("Your IP isn't allowed to connect"));
+ return FALSE;
+ }
+ // End AuthIP
+
+ if ($restrictip) {
+ $ip = get_remote_ip();
+ } else {
+ $ip = "";
+ }
+
+ // Close sessions that are more than 2 days old.
+ $db->query("DELETE FROM sessions WHERE DATE_ADD(ts,INTERVAL 2 DAY)query("insert into sessions (sid,ip,uid) values (?, ?, ?);", array($sess, $ip, $cuid));
+ setcookie("session", $sess, 0, "/");
+ $msg->init_msgs();
+
+ // Fill in $local.
+ $db->query("SELECT * FROM local WHERE uid= ? ;", array($cuid));
+ if ($db->num_rows()) {
+ $db->next_record();
+ $this->local = $db->Record;
+ }
+ $this->resetlast();
+
+ // Set a cookie parameter to allow password change without requiring
+ // previous one.
+ $db->query('select lastlogin, pass from membres where uid = ?;', array($uid));
+ if ($db->num_rows()) {
+ $db->next_record();
+ $cookie_data = $cuid . $db->f('lastlogin');
+ $salt = variable_get('salt_password_reset', base64_encode(random_bytes(128))) . $db->f('pass');
+ $c = setcookie('require_old_password', hash_hmac('sha512', $cookie_data, $salt), 0, '/');
+ if (!$c) {
+ $msg->log('mem', 'temporary_login', 'Failed to set cookie require_old_password');
+ }
+ }
+ return TRUE;
+ }
+
+ function requires_old_password_for_change() {
+ global $cuid, $db;
+ $cookie = $_COOKIE['require_old_password'];
+ if (!$cookie) {
+ return TRUE;
+ }
+ $db->query('select lastlogin, pass from membres where uid = ?;', array($cuid));
+ if ($db->num_rows()) {
+ $db->next_record();
+ $cookie_data = $cuid . $db->f('lastlogin');
+ $salt = variable_get('salt_password_reset', base64_encode(random_bytes(128))) . $db->f('pass');
+ if ($cookie == hash_hmac('sha512', $cookie_data, $salt)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+ /**
+ * Validates a reset URL that has been received.
+ */
+ function validate_reset_url($uid, $timestamp, $token) {
+ global $cuid, $db, $msg;
+ // Do not log a person in if they are logged in already.
+ if ($this->checkid(false)) {
+ $msg->raise('ERROR', 'mem', _('You are already logged in, you may not use a one-time login link'));
+ $msg->log('mem', 'validate_reset_url', 'Refused one-time log-in since the user is already connected');
+ return FALSE;
+ }
+
+ // The timestamp is older than the age limit - invalid.
+ $fail_message = _('The login-link has already been used or is expired');
+ $duration = variable_get('password_reset_expiration', 86400, 'The number of seconds for which a password reset link is valid');
+ if (time() - $timestamp >= $duration) {
+ $msg->raise('ERROR', 'mem', $fail_message);
+ $msg->log('mem', 'validate_reset_url', 'Refused one-time log-in since the time elapsed is greater than limit of ' . $duration);
+ return FALSE;
+ }
+
+ $db->query("SELECT * FROM membres WHERE uid = ? ;", array($uid));
+ if (!$db->num_rows()) {
+ $msg->raise('ERROR', 'mem', $fail_message);
+ $msg->log('mem', 'validate_reset_url', 'Refused one-time log-in since a user with ID ' . $uid. ' does not exist');
+ return FALSE;
+ }
+ $db->next_record();
+ $last_login = strtotime($db->f('lastlogin'));
+ // The timestamp is older than the most recent login - invalid.
+ if ($last_login >= time() || $last_login >= $timestamp) {
+ $msg->raise('ERROR', 'mem', $fail_message);
+ $msg->log('mem', 'validate_reset_url', "Refused one-time log-in since the most recent login was more recent than the timestamp in the log-in link. Last: {$last_login}, Timestamp: {$timestamp}");
+ return FALSE;
+ }
+
+ // The account is locked or cannot change pass - invalid.
+ if (!$db->f('enabled') || !$db->f('canpass')) {
+ $msg->raise('ERROR', 'mem', $fail_message);
+ $msg->log('mem', 'validate_reset_url', 'Refused one-time log-in since the user account is disabled or cannot change it\'s password.');
+ return FALSE;
+ }
+
+ // Using the current user info and timestamp the tokens generated
+ // do not match - invalid. (Eg. user password changed, salt changed).
+ $salt = variable_get('salt_password_reset', base64_encode(random_bytes(128))) . $db->f('pass');
+ $data = $timestamp . $uid . $db->f('login');
+ $ref_token = hash_hmac('sha512', $data, $salt);
+ if ($token != $ref_token) {
+ $msg->raise('ERROR', 'mem', $fail_message);
+ return FALSE;
+ }
+
+ $msg->raise('INFO', 'mem', _('You have used a one-time login link. Please set a new password now.'));
+ return TRUE;
+ }
+
} /* Class m_mem */
diff --git a/bureau/class/m_ssl.php b/bureau/class/m_ssl.php
index 0e73367d..6a7f6f9f 100644
--- a/bureau/class/m_ssl.php
+++ b/bureau/class/m_ssl.php
@@ -372,7 +372,34 @@ INSTR(CONCAT(sd.sub,IF(sd.sub!='','.',''),sd.domaine),'.')+1))=?
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 the list of certificates by order of preference
@@ -620,6 +647,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
@@ -635,7 +690,25 @@ SELECT ?,?,?, FROM_UNIXTIME(?), FROM_UNIXTIME(?), ?, ?, sslcsr FROM certificate
// get the first good certificate:
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
$CRTDIR = self::KEY_REPOSITORY . "/" . floor($cert["id"]/1000);
@mkdir($CRTDIR,0750,true);
@@ -667,16 +740,6 @@ SELECT ?,?,?, FROM_UNIXTIME(?), FROM_UNIXTIME(?), ?, ?, sslcsr FROM certificate
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;
}
diff --git a/bureau/locales/fr_FR/LC_MESSAGES/messages.po b/bureau/locales/fr_FR/LC_MESSAGES/messages.po
index b4bccefb..49697126 100644
--- a/bureau/locales/fr_FR/LC_MESSAGES/messages.po
+++ b/bureau/locales/fr_FR/LC_MESSAGES/messages.po
@@ -1601,24 +1601,20 @@ msgid "Quit"
msgstr "Fermer"
#: ../admin/bro_main.php:73
-#, fuzzy, php-format
msgid "The folder '%s' was successfully created"
-msgstr "L'utilisateur %s a été effacée avec succès"
+msgstr "Le dossier %s a été effacé avec succès"
#: ../admin/bro_main.php:79
-#, fuzzy, php-format
msgid "The file '%s' was successfully created"
-msgstr "L'Email a été modifié avec succès"
+msgstr "Le fihier été créé avec succès"
#: ../admin/bro_main.php:94
-#, fuzzy, php-format
msgid "The folder '%s' was successfully deleted"
-msgstr "L'utilisateur %s a été effacée avec succès"
+msgstr "Le dossier %s a été effacé avec succès"
#: ../admin/bro_main.php:96
-#, fuzzy, php-format
msgid "The file '%s' was successfully deleted"
-msgstr "L'adresse email %s a été effacée avec succès"
+msgstr "Le fichier %s a été effacé avec succès"
#: ../admin/bro_main.php:102
#, php-format
@@ -1663,39 +1659,32 @@ msgid "The file '%s' was successfully moved to '%s'"
msgstr "L'Email a été modifié avec succès"
#: ../admin/bro_main.php:145
-#, fuzzy
msgid "The files / folders were successfully moved"
-msgstr "Le répertoire protégé %s a été déprotégé avec succès"
+msgstr "Les fichiers / répertoires %s ont été déplacé avec succès"
#: ../admin/bro_main.php:153
-#, fuzzy, php-format
msgid "The folder '%s' was successfully renamed to '%s'"
-msgstr "L'Email a été modifié avec succès"
+msgstr "Le dossier '%s' a été renommé '%s' avec succès"
#: ../admin/bro_main.php:155
-#, fuzzy, php-format
msgid "The file '%s' was successfully renamed to '%s'"
-msgstr "L'Email a été modifié avec succès"
+msgstr "Le fichier '%s' a été renommé '%s' avec succès"
#: ../admin/bro_main.php:157
-#, fuzzy
msgid "The files / folders were successfully renamed"
-msgstr "Le compte AlternC a été renouvelé avec succès"
+msgstr "Les fichiers / répertoires ont été renommés avec succès"
#: ../admin/bro_main.php:162
-#, fuzzy, php-format
msgid "The file '%s' was successfully uploaded"
-msgstr "L'adresse email %s a été effacée avec succès"
+msgstr "Le fichier '%s' a été téléversé avec succès"
#: ../admin/bro_main.php:167
-#, fuzzy
msgid "The permissions were successfully set"
-msgstr "L'Email a été modifié avec succès"
+msgstr "Les permissions ont été appliquées avec succès"
#: ../admin/bro_main.php:175
-#, fuzzy, php-format
msgid "The extraction of the file '%s' succeeded"
-msgstr "Le mot de passe de l'utilisateur %s à été modifié avec succés"
+msgstr "L'extraction du fichier '%s' a été effectuée avec succés"
#: ../admin/bro_main.php:180 ../class/m_bro.php:74
msgid "File browser"
@@ -2713,12 +2702,10 @@ msgid "Folder %s is protected"
msgstr ""
#: ../admin/hta_doadduser.php:45
-#, fuzzy, php-format
msgid "The user %s was added to the protected folder %s"
-msgstr "Modification de l'utilisateur %s dans le répertoire protégé %s"
+msgstr "L'utilisateur %s a été ajouté au répertoire protégé %s"
#: ../admin/hta_dodeluser.php:39
-#, fuzzy, php-format
msgid "The user '%s' was successfully deleted"
msgstr "L'utilisateur %s a été effacée avec succès"
@@ -4273,9 +4260,8 @@ msgid "Create this new MySQL user"
msgstr "Créer ce nouvel utilisateur MySQL"
#: ../admin/sql_users_del.php:38 ../class/m_mysql.php:770
-#, fuzzy, php-format
msgid "The user '%s' has been successfully deleted"
-msgstr "L'utilisateur %s a été effacée avec succès"
+msgstr "L'utilisateur MySQL %s a été effacé avec succès"
#: ../admin/sql_users_del.php:49
msgid "MySQL users"
@@ -4294,14 +4280,12 @@ msgid "Yes, delete the MySQL user"
msgstr "Oui, effacer cet utilisateur MySQL"
#: ../admin/sql_users_doadd.php:41 ../admin/sql_users_doadd.php:50
-#, fuzzy, php-format
msgid "The user '%s' has been successfully created."
-msgstr "L'utilisateur %s a été effacée avec succès"
+msgstr "L'utilisateur %s a été ajouté avec succès"
#: ../admin/sql_users_dopassword.php:35
-#, fuzzy, php-format
msgid "Password changed for user '%s'."
-msgstr "Permettre le changement de mot de passe ?"
+msgstr "Mot de passe changé pour l'utilisateur '%s'."
#: ../admin/sql_users_dorights.php:49
msgid "The rights has been successfully applied to the user"
diff --git a/debian/alternc.cron.d b/debian/alternc.cron.d
index f324f260..0929f5fc 100644
--- a/debian/alternc.cron.d
+++ b/debian/alternc.cron.d
@@ -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 4 * * 0 alterncpanel /usr/lib/alternc/sqlbackup.sh -t weekly
-# Every 5 minutes, spool waiting domain changes
-*/5 * * * * root /usr/lib/alternc/update_domains.sh
+# Every minute, spool waiting domain changes
+* * * * * root /usr/lib/alternc/update_domains.php
# Every 5 minutes, do mails actions
*/5 * * * * root /usr/lib/alternc/update_mails.sh
diff --git a/debian/alternc.postinst b/debian/alternc.postinst
index 74c973c0..73e436d0 100644
--- a/debian/alternc.postinst
+++ b/debian/alternc.postinst
@@ -42,8 +42,9 @@ case "$1" in
# corriger les permissions du chroot
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"
VMAIL_HOME="$RET"
diff --git a/debian/control b/debian/control
index 166cd069..abb8b2e2 100644
--- a/debian/control
+++ b/debian/control
@@ -59,12 +59,13 @@ Depends: debianutils (>= 1.13.1)
, opendkim-tools
, dovecot-sieve
, dovecot-managesieved
- , default-mysql-client
+ , default-mysql-client | mysql-client | mariadb-client
, php5-curl | php7.0-curl
, quota
, pwgen
+ , lsb-release
, ${misc:Depends}
-Recommends: default-mysql-server
+Recommends: default-mysql-server | mysql-server | mariadb-server
, ntp
, unzip
, bzip2
@@ -148,8 +149,9 @@ Depends: debianutils (>= 1.13.1)
, opendkim-tools
, dovecot-sieve
, dovecot-managesieved
- , default-mysql-client
- , php5-curl
+ , default-mysql-client | mysql-client | mariadb-client
+ , php5-curl | php7.0-curl
+ , lsb-release
, ${misc:Depends}
Recommends:
quota
diff --git a/etc/alternc/templates/alternc/apache2.conf b/etc/alternc/templates/alternc/apache2.conf
index a8cdaef2..e6d8e1e9 100644
--- a/etc/alternc/templates/alternc/apache2.conf
+++ b/etc/alternc/templates/alternc/apache2.conf
@@ -14,6 +14,7 @@ AssignUserId www-data www-data
Options +FollowSymLinks
AllowOverride None
Require all denied
+ Satisfy Any
#### End security parameters
diff --git a/etc/alternc/templates/alternc/bureau.conf b/etc/alternc/templates/alternc/bureau.conf
index 6d677e87..d834648b 100644
--- a/etc/alternc/templates/alternc/bureau.conf
+++ b/etc/alternc/templates/alternc/bureau.conf
@@ -5,10 +5,6 @@
DocumentRoot /usr/share/alternc/panel/admin
ServerName %%fqdn%%
- # Mail autoconfig
- ServerAlias autoconfig.*
- ServerAlias autodiscover.*
-
RewriteEngine on
RewriteRule ^/admin/(.*) /$1 [R=301,L]
@@ -17,20 +13,6 @@
RewriteEngine On
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 ...
IncludeOptional /etc/alternc/apache-panel.d/*.conf
diff --git a/etc/alternc/templates/apache2/autodiscover.conf b/etc/alternc/templates/apache2/autodiscover.conf
new file mode 100644
index 00000000..a68a4120
--- /dev/null
+++ b/etc/alternc/templates/apache2/autodiscover.conf
@@ -0,0 +1,57 @@
+
+
+ DocumentRoot /usr/share/alternc/panel/admin
+
+ AssignUserId alterncpanel alterncpanel
+ SetEnv LOGIN "0000-panel"
+
+ ServerName %%fqdn%%
+
+ RewriteEngine On
+ # 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]
+ RewriteRule (.*) - [F]
+
+
+
+
+ DocumentRoot /usr/share/alternc/panel/admin
+
+ AssignUserId alterncpanel alterncpanel
+ SetEnv LOGIN "0000-panel"
+
+ ServerName %%fqdn%%
+
+ RewriteEngine On
+ # 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]
+ RewriteRule (.*) - [F]
+
+ SSLEngine On
+ SSLCertificateFile %%CRT%%
+ SSLCertificateKeyFile %%KEY%%
+ %%CHAINLINE%%
+
+
diff --git a/etc/alternc/templates/apache2/vhost-both.conf b/etc/alternc/templates/apache2/vhost-both.conf
index c47e5f1f..90b674e8 100644
--- a/etc/alternc/templates/apache2/vhost-both.conf
+++ b/etc/alternc/templates/apache2/vhost-both.conf
@@ -7,6 +7,7 @@
php_admin_value open_basedir "%%account_root%%:/usr/share/php/"
php_admin_value upload_tmp_dir %%account_root%%/tmp
+ php_admin_value sys_temp_dir %%account_root%%/tmp
php_admin_value sendmail_path '/usr/lib/alternc/sendmail "%%mail_account%%" '
php_admin_flag mail.add_x_header on
Options +MultiViews -FollowSymLinks +SymLinksIfOwnerMatch
@@ -21,6 +22,7 @@
php_admin_value open_basedir "%%account_root%%:/usr/share/php/"
php_admin_value upload_tmp_dir %%account_root%%/tmp
+ php_admin_value sys_temp_dir %%account_root%%/tmp
php_admin_value sendmail_path '/usr/lib/alternc/sendmail "%%mail_account%%" '
php_admin_flag mail.add_x_header on
Options +MultiViews -FollowSymLinks +SymLinksIfOwnerMatch
diff --git a/etc/alternc/templates/apache2/vhost-http.conf b/etc/alternc/templates/apache2/vhost-http.conf
index 5b631ba1..3fbacd0b 100644
--- a/etc/alternc/templates/apache2/vhost-http.conf
+++ b/etc/alternc/templates/apache2/vhost-http.conf
@@ -8,10 +8,12 @@
RewriteCond %{REQUEST_FILENAME} !/cgi-bin/
RewriteCond %{REQUEST_FILENAME} !/.well-known/acme-challenge/
RewriteRule ^/(.*)$ http://%%fqdn%%/$1 [R=301,L]
+
SSLEngine On
SSLCertificateFile %%CRT%%
SSLCertificateKeyFile %%KEY%%
%%CHAINLINE%%
+
ServerName %%fqdn%%
@@ -21,6 +23,7 @@
php_admin_value open_basedir "%%account_root%%:/usr/share/php/"
php_admin_value upload_tmp_dir %%account_root%%/tmp
+ php_admin_value sys_temp_dir %%account_root%%/tmp
php_admin_value sendmail_path '/usr/lib/alternc/sendmail "%%mail_account%%" '
php_admin_flag mail.add_x_header on
Options -MultiViews -FollowSymLinks +SymLinksIfOwnerMatch
diff --git a/etc/alternc/templates/apache2/vhost-https.conf b/etc/alternc/templates/apache2/vhost-https.conf
index 519be539..a3409057 100644
--- a/etc/alternc/templates/apache2/vhost-https.conf
+++ b/etc/alternc/templates/apache2/vhost-https.conf
@@ -17,6 +17,7 @@
php_admin_value open_basedir "%%account_root%%:/usr/share/php/"
php_admin_value upload_tmp_dir %%account_root%%/tmp
+ php_admin_value sys_temp_dir %%account_root%%/tmp
php_admin_value sendmail_path '/usr/lib/alternc/sendmail "%%mail_account%%" '
php_admin_flag mail.add_x_header on
Options +MultiViews -FollowSymLinks +SymLinksIfOwnerMatch
diff --git a/etc/alternc/templates/bind/slaveip.conf b/etc/alternc/templates/bind/slaveip.conf
index 7212d291..2b8aa971 100644
--- a/etc/alternc/templates/bind/slaveip.conf
+++ b/etc/alternc/templates/bind/slaveip.conf
@@ -5,6 +5,7 @@
acl "allslaves" {
{
127.0.0.1;
+ ::1;
//AUTO-SLAVES//
};
};
diff --git a/etc/alternc/templates/bind/templates/named.template b/etc/alternc/templates/bind/templates/named.template
index 9c7f7cff..13ed7fb7 100644
--- a/etc/alternc/templates/bind/templates/named.template
+++ b/etc/alternc/templates/bind/templates/named.template
@@ -1 +1 @@
-zone "@@DOMAINE@@" { type master; file "@@ZONE_FILE@@"; allow-query { any; }; };
+zone "@@DOMAIN@@" { type master; file "@@ZONE_FILE@@"; allow-query { any; }; };
diff --git a/install/alternc.install b/install/alternc.install
index b2671435..e77af4d9 100755
--- a/install/alternc.install
+++ b/install/alternc.install
@@ -76,6 +76,14 @@ fi
. /usr/lib/alternc/functions.sh
+# get the information on running Sysv or Systemd init & boot system
+if [ -e /run/systemd/system ]
+then
+ SYSTEMD=1
+else
+ SYSTEMD=0
+fi
+
# Lock the jobs !
lock_jobs
@@ -91,7 +99,7 @@ TEMPLATE_DIR="/etc/alternc/templates"
# Find needed configuration files (without the initial '/')
# replace this one unconditionnally
-CONFIG_FILES="etc/alternc/bureau.conf etc/apache2/envvars etc/alternc/apache2.conf etc/alternc/apache_logformat.conf etc/alternc/phpmyadmin.inc.php"
+CONFIG_FILES="etc/alternc/bureau.conf etc/apache2/envvars etc/alternc/apache2.conf etc/alternc/phpmyadmin.inc.php"
if [ -e /etc/bind/named.conf ]; then
CONFIG_FILES="$CONFIG_FILES etc/bind/named.conf.options"
@@ -365,9 +373,8 @@ do
fi
done
-# ensure dovecot, postfix, apache, can access ssl certificates:
+# ensure dovecot, postfix, can access ssl certificates:
adduser dovecot ssl-cert
-adduser www-data ssl-cert
adduser postfix ssl-cert
run-parts --arg=certificates /usr/lib/alternc/install.d
@@ -377,7 +384,6 @@ if [ -x /usr/sbin/apache2 ]; then
run-parts --arg=apache2 /usr/lib/alternc/install.d
a2enmod mpm_itk
- s="apache2"
# unused from AlternC 1.0, FIXME: remove it later
if [ -L /etc/apache2/mods-enabled/vhost_alias.load ]
then
@@ -410,7 +416,7 @@ if [ -x /usr/sbin/apache2 ]; then
a2enconf alternc
fi
- SERVICES="$SERVICES $s"
+ SERVICES="$SERVICES apache2"
fi
# Manage sudoers.d include appearing in Squeeze:
@@ -608,6 +614,9 @@ fi
chmod 640 /var/log/alternc/bureau.log /var/log/alternc/update_domains.log
chown alterncpanel:adm /var/log/alternc/bureau.log /var/log/alternc/update_domains.log
+# Launch a script that will populate AlternC variables as needed
+su - alterncpanel -s /bin/bash -c /usr/share/alternc/install/variables.php
+
# Creating admin user if needed
HAS_ROOT=`mysql --defaults-file=/etc/alternc/my.cnf -e "SELECT COUNT(*) FROM membres WHERE login = 'admin' OR login = 'root' and su = 1" | tail -1`
@@ -668,6 +677,16 @@ if [ "$(lsb_release -s -c)" == 'stretch' ] ; then
systemctl daemon-reload
fi
+if [ "$SYSTEMD" = "1" -a "$(lsb_release -s -c)" = "stretch" ] ; then
+ /lib/opendkim/opendkim.service.generate
+ # Without adding '-u opendkim' after the service file is generated, opendkim
+ # will run as root, which we do not want.
+ if [ "$(grep -c 'u opendkim' /etc/systemd/system/opendkim.service.d/override.conf)" == 0 ] ; then
+ sed -i -e 's/inet:8891@127.0.0.1/& -u opendkim/' /etc/systemd/system/opendkim.service.d/override.conf
+ fi
+ systemctl daemon-reload
+fi
+
# Add opendkim to service to restart
SERVICES="$SERVICES opendkim bind9"
diff --git a/install/mysql.sql b/install/mysql.sql
index e885d17e..0b648336 100644
--- a/install/mysql.sql
+++ b/install/mysql.sql
@@ -115,7 +115,7 @@ CREATE TABLE IF NOT EXISTS domaines (
noerase tinyint(4) NOT NULL default '0',
dns_action enum ('OK','UPDATE','DELETE') NOT NULL default 'UPDATE',
dns_result varchar(255) not null default '',
- zonettl int(10) unsigned NOT NULL default '86400',
+ zonettl int(10) unsigned NOT NULL default '3600',
PRIMARY KEY (id),
UNIQUE KEY (domaine)
) ENGINE=InnoDB;
@@ -479,16 +479,11 @@ CREATE TABLE IF NOT EXISTS `domaines_type` (
PRIMARY KEY ( `name` )
) ENGINE=InnoDB COMMENT = 'Type of domains allowed';
-INSERT IGNORE INTO `domaines_type` (name, description, target, entry, compatibility, only_dns, need_dns, advanced, enable, has_https_option) values
+INSERT IGNORE INTO `domaines_type` (name, description, target, entry, compatibility, only_dns, need_dns, advanced, enable,has_https_option) VALUES
-- Default vhost type to maintains compatibility across versions.
--- This is overloaded depending on the value of the https column in sub_domaines
('vhost', 'Locally hosted', 'DIRECTORY', '%SUB% IN A @@PUBLIC_IP@@', 'txt,defmx,defmx2,mx,mx2', false, false, false, 'ALL', true),
--- The following 3 types (vhost-http, vhost-https, vhost-both) are overloads for vhost
--- and are "disabled" to not be available from the interface, but still be valid domaine types
--- when checking in m_ssl::updateDomain.
-('vhost-http','Locally hosted with http->https', 'DIRECTORY', '%SUB% IN A @@PUBLIC_IP@@', 'txt,defmx,defmx2,mx,mx2', false, false, false, 'NONE', false),
-('vhost-https','Locally hosted with http->https', 'DIRECTORY', '%SUB% IN A @@PUBLIC_IP@@', 'txt,defmx,defmx2,mx,mx2', false, false, false, 'NONE', false),
-('vhost-both', 'Locally hosted with http and https', 'DIRECTORY', '%SUB% IN A @@PUBLIC_IP@@', 'txt,defmx,defmx2,mx,mx2', false, false, false, 'NONE', false),
+('dkim', 'DKIM Key', 'TXT', '%SUB% IN TXT "%TARGET%"', 'txt,defmx,defmx2,mx,mx2,url,ip,ipv6', true, true, true, 'ADMIN', false),
+('autodiscover', 'Email autoconfiguration', 'NONE', '%SUB% IN A @@PUBLIC_IP@@', 'txt,defmx,defmx2,mx,mx2', false, true, true, 'ADMIN', false),
('url', 'URL redirection', 'URL', '%SUB% IN A @@PUBLIC_IP@@', 'txt,defmx,defmx2', false, false, false, 'ALL', false),
('ip', 'IPv4 redirect', 'IP', '%SUB% IN A %TARGET%', 'url,ip,ipv6,txt,mx,mx2,defmx,defmx2', true, true, false, 'ALL', false),
('ipv6', 'IPv6 redirect', 'IPV6', '%SUB% IN AAAA %TARGET%', 'ip,ipv6,txt,mx,mx2,defmx,defmx2', true, true, true, 'ALL', false),
@@ -801,7 +796,6 @@ CREATE TABLE IF NOT EXISTS `certificates` (
--- make it re-exec-proof
-DELETE FROM alternc_status WHERE name='alternc_version';
-INSERT INTO alternc_status SET name='alternc_version',value='3.5.0.1.sql';
+-- make it re-exec-proof -- BUT don't overwrite existing value !
+INSERT IGNORE INTO alternc_status SET name='alternc_version',value='3.5.0.2.php';
diff --git a/install/upgrades/3.5.0.1.sql b/install/upgrades/3.5.0.1.sql
index 49fc7f44..f46a1ed4 100644
--- a/install/upgrades/3.5.0.1.sql
+++ b/install/upgrades/3.5.0.1.sql
@@ -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 ADD `lastloginsasl` DATETIME NOT NULL DEFAULT 0 AFTER `lastlogin`;
+ALTER TABLE `domaines` MODIFY `zonettl` INT(10) UNSIGNED NOT NULL default '3600';
-ALTER TABLE `membres` MODIFY `pass` varchar(255);
-ALTER TABLE `ftpusers` MODIFY `encrypted_password` varchar(255);
+-- upgrade to better hashes ($6$, 20000 loops) in membres and ftpusers
+ALTER TABLE `membres` MODIFY `pass` VARCHAR(255);
+ALTER TABLE `ftpusers` MODIFY `encrypted_password` VARCHAR(255);
-- upgrade to merge alternc-ssl into alternc + change the way we work on SSL
-
DROP TABLE IF EXISTS `certif_alias`;
ALTER TABLE `certificates`
@@ -28,7 +37,8 @@ ALTER TABLE `domaines_type`
UPDATE `domaines_type` SET `has_https_option`=1 WHERE name='vhost';
-- Backport old certif_hosts data to sub_domaines
-UPDATE `sub_domaines` LEFT JOIN `certif_hosts` ON `sub_domaines`.`id` = `certif_hosts`.`sub` SET `sub_domaines`.`certificate_id` = `certif_hosts`.`certif` WHERE 1;
+UPDATE `sub_domaines` LEFT JOIN `certif_hosts` ON `sub_domaines`.`id` = `certif_hosts`.`sub`
+ SET `sub_domaines`.`certificate_id` = `certif_hosts`.`certif`;
DROP TABLE IF EXISTS `certif_hosts`;
-- Set https status (http,https,both)
@@ -37,21 +47,22 @@ UPDATE `sub_domaines` SET `https` = "both" WHERE `type` LIKE '%-mixssl' AND http
UPDATE `sub_domaines` SET `https` = "http" WHERE https = '';
UPDATE `sub_domaines` SET `type` = REPLACE(`type`,'-ssl','');
UPDATE `sub_domaines` SET `type` = REPLACE(`type`,'-mixssl','');
--- Disable https status when domains_type don't provide this
-UPDATE `sub_domaines` SET `https` = '' WHERE type IN (select name FROM domaines_type WHERE has_https_option = 0);
+-- Disable https status when domains_type don't use it
+UPDATE `sub_domaines` SET `https` = '' WHERE type IN (SELECT name FROM domaines_type WHERE has_https_option = 0);
--- When two sudomain exists, we consider sub_domains with http and https feature
+-- When two subdomain exists, we consider sub_domains with http and https feature
UPDATE sub_domaines AS sd INNER JOIN
(SELECT MIN(id) id FROM `sub_domaines` GROUP BY domaine,sub,type HAVING count(id) > 1) sd1
ON sd.id = sd1.id
SET `https` = "both";
-- Delete duplicate lines
-DELETE sd1 FROM sub_domaines sd1, sub_domaines sd2 WHERE sd1.id > sd2.id AND sd1.domaine = sd2.domaine AND sd1.sub = sd2.sub AND sd1.type = sd2.type AND sd1.https <> '' AND sd2.https <> '';
+DELETE sd1 FROM sub_domaines sd1, sub_domaines sd2
+ WHERE sd1.id > sd2.id AND sd1.domaine = sd2.domaine AND sd1.sub = sd2.sub AND sd1.type = sd2.type
+ AND sd1.https <> '' AND sd2.https <> '';
-- we need to regenerate all vhost, they will be by AlternC.install
-- UPDATE `sub_domaines` SET `web_action` = 'UPDATE';
-
-- change some variable names :
UPDATE variable
@@ -72,6 +83,6 @@ DELETE FROM variable WHERE name IN (
'ftp_human_name'
);
--- we'd like to prepare IPv6 ;)
+-- we'd like to prepare for IPv6 ;)
ALTER TABLE `domaines_type` CHANGE `entry` `entry` TEXT DEFAULT '';
diff --git a/install/upgrades/3.5.0.2.php b/install/upgrades/3.5.0.2.php
new file mode 100644
index 00000000..22c83c15
--- /dev/null
+++ b/install/upgrades/3.5.0.2.php
@@ -0,0 +1,33 @@
+#!/usr/bin/php -q
+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)
+ );
+}
+
diff --git a/install/variables.php b/install/variables.php
new file mode 100644
index 00000000..f07cf92f
--- /dev/null
+++ b/install/variables.php
@@ -0,0 +1,17 @@
+#!/usr/bin/php
+object->purge();
- $this->assertEquals(0, $result);
+ $this->assertEquals(1, $result);
$expectedTable = $this->loadDataSet("actions-empty.yml")->getTable("actions");
$currentTable = $this->getConnection()->createQueryTable('actions', 'SELECT * FROM actions');
$this->assertTablesEqual($expectedTable, $currentTable);
diff --git a/phpunit/tests/bureau/class/m_domTest.php b/phpunit/tests/bureau/class/m_domTest.php
index 12892330..343cceea 100644
--- a/phpunit/tests/bureau/class/m_domTest.php
+++ b/phpunit/tests/bureau/class/m_domTest.php
@@ -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
diff --git a/phpunit/tests/bureau/class/m_mailTest.php b/phpunit/tests/bureau/class/m_mailTest.php
index c1bf6a03..d34b7c76 100644
--- a/phpunit/tests/bureau/class/m_mailTest.php
+++ b/phpunit/tests/bureau/class/m_mailTest.php
@@ -320,6 +320,9 @@ class m_mailTest extends AlterncTest
public function testCreate_alias()
{
// Test #1580
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
}
/**
diff --git a/src/fixperms.sh b/src/fixperms.sh
index bd39c977..7bf4bc49 100755
--- a/src/fixperms.sh
+++ b/src/fixperms.sh
@@ -22,50 +22,58 @@
# Purpose of file: Fix permission, ACL and ownership of AlternC's files
# ----------------------------------------------------------------------
#
+red () { echo -e "\e[31m$@ \e[0m" ; }
+usage () {
+ [[ -n "$@" ]] && red "$@\n"
+ cat<//
-# The f and d switch are used to fix a given file or directory under the user's base directory. They use the base directory to get the permissions they should use.
-# Be sure to have correct base directory permissions before attemplting to fix use those two switch
-
+ The u and l switch are used to fix a given user whole directory including his base directory ($ALTERNC_HTML///
+ The f and d switch are used to fix a given file or directory under the user's base directory. They use the base directory to get the permissions they should use.
+ Be sure to have correct base directory permissions before attemplting to fix use those two switch
+End-of-message
+ exit 1
+}
query="SELECT uid,login FROM membres ORDER BY login"
sub_dir=""
file=""
LOCK_FIXPERMS="/etc/alternc/disable_all_fixperms"
if [ -f "$LOCK_FIXPERMS" ] ; then
- (
- echo " ------------- "
- echo '/!\ WARNING /!\ '
- echo "The fixperms script is disabled"
- echo "To enable it, delete $LOCK_FIXPERMS "
- echo " ------------- "
- ) 1>&2
- exit 0
+
+ usage "
+------------------------------------
+/!\ WARNING /!\
+The fixperms script is disabled
+To enable it, delete $LOCK_FIXPERMS
+------------------------------------
+"
+
fi
-while getopts "l:u:f:d:" optname
+
+while getopts "hl:u:f:d:" optname
do
case "$optname" in
+ "h") usage
+ ;;
+
"l")
if [[ "$OPTARG" =~ ^[a-zA-Z0-9_]+$ ]] ; then
query="SELECT uid,login FROM membres WHERE login LIKE '$OPTARG' ORDER BY login"
else
- echo "Bad login provided"
- exit
+ usage "Bad login provided"
fi
;;
"u")
if [[ "$OPTARG" =~ ^[0-9]+$ ]] ; then
query="SELECT uid,login FROM membres WHERE uid LIKE '$OPTARG' ORDER BY login"
else
- echo "Bad uid provided"
- exit
+ usage "Bad uid provided"
fi
;;
"f")
@@ -79,17 +87,14 @@ do
echo $sub_dir
;;
"?")
- echo "Unknown option $OPTARG - stop processing"
- exit
+ usage "Unknown option $OPTARG - stop processing"
;;
":")
- echo "No argument value for option $OPTARG - stop processing"
- exit
+ usage "No argument value for option $OPTARG - stop processing"
;;
*)
# Should not occur
- echo "Unknown error while processing options"
- exit
+ usage "Unknown error while processing options"
;;
esac
done
diff --git a/src/functions_dns.sh b/src/functions_dns.sh
deleted file mode 100755
index 7ec2f602..00000000
--- a/src/functions_dns.sh
+++ /dev/null
@@ -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
-}
diff --git a/src/functions_hosting.sh b/src/functions_hosting.sh
deleted file mode 100644
index 61bd7207..00000000
--- a/src/functions_hosting.sh
+++ /dev/null
@@ -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
-}
-
diff --git a/src/generate_apache_conf.php b/src/generate_apache_conf.php
deleted file mode 100755
index 579d814e..00000000
--- a/src/generate_apache_conf.php
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/php -q
-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;
-
diff --git a/src/generate_bind_conf.php b/src/generate_bind_conf.php
deleted file mode 100755
index 4907007d..00000000
--- a/src/generate_bind_conf.php
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/php -q
-regenerate_conf($force);
-
diff --git a/src/rebuild_all_webconf.sh b/src/rebuild_all_webconf.sh
index cf7fcefa..176b2587 100755
--- a/src/rebuild_all_webconf.sh
+++ b/src/rebuild_all_webconf.sh
@@ -4,7 +4,6 @@
. /usr/lib/alternc/functions.sh
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"
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."
/usr/lib/alternc/update_domains.sh
-/usr/lib/alternc/generate_bind_conf.php --force
echo "Finish."
diff --git a/src/slave_dns b/src/slave_dns
index 0b20420e..b63d476c 100644
--- a/src/slave_dns
+++ b/src/slave_dns
@@ -1,35 +1,33 @@
-#!/bin/bash
+#!/usr/bin/php
+query("SELECT ip,class FROM slaveip;");
+$str="";
+while ($db->next_record()) {
+ $str.=" ".$db->Record["ip"]."/".$db->Record["class"].";\n";
+}
-# Get the slave IP. Remove the "newline" caracters
-val=$(mysql_query "SELECT concat(ip,'::',class,'; ') FROM slaveip;"|tr '\n' ' ')
+file_put_contents($TARGET, str_replace("//AUTO-SLAVES//",$str, file_get_contents($TPL) ) );
-# Add the slaves to the templates, re-add the missing "/" separator of subnet
-cat "$TPL" | sed -e "s/\/\/AUTO-SLAVES\/\//$val/g" -e "s/::/\//g" > "$TMP"
+chown($TARGET,"root");
+chgrp($TARGET,"bind");
+chmod($TARGET,0640);
-# Activate the new configuration
-mv "$TMP" "$TARGET"
-chown root:bind "$TARGET"
-chmod 640 "$TARGET"
+putenv("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
+passthru("rndc reconfig");
+
+unlink($FLAGFILE);
-invoke-rc.d bind9 reload
-# Remove FLAGSLAVE file
-rm -f "$FLAGFILE"
diff --git a/src/update_domains.php b/src/update_domains.php
new file mode 100644
index 00000000..8589e55e
--- /dev/null
+++ b/src/update_domains.php
@@ -0,0 +1,10 @@
+#!/usr/bin/php -q
+update_domains();
+
diff --git a/src/update_domains.sh b/src/update_domains.sh
index ac7cb98b..49e0def5 100755
--- a/src/update_domains.sh
+++ b/src/update_domains.sh
@@ -1,168 +1,4 @@
#!/bin/bash
-# Update domain next-gen by fufroma
-PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
-
-for CONFIG_FILE in \
- /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, if(length(sd.https)>0,concat_ws('-',sd.type,sd.https),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, if(length(sd.https)>0,concat_ws('-',sd.type,sd.https),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, if(length(sd.https)>0,concat_ws('-',sd.type,sd.https),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
+# This is now done using PHP-only scripting
+/usr/lib/alternc/update_domains.php