Alternc  3.2
Alternc logiel libre pour l'hébergement
 All Data Structures Namespaces Files Functions Variables Pages
m_dom.php
Go to the documentation of this file.
1 <?php
2 /*
3  ----------------------------------------------------------------------
4  AlternC - Web Hosting System
5  Copyright (C) 2000-2012 by the AlternC Development Team.
6  https://alternc.org/
7 ----------------------------------------------------------------------
8  LICENSE
9 
10  This program is free software; you can redistribute it and/or
11  modify it under the terms of the GNU General Public License (GPL)
12  as published by the Free Software Foundation; either version 2
13  of the License, or (at your option) any later version.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  To read the license please visit http://www.gnu.org/copyleft/gpl.html
21  ----------------------------------------------------------------------
22  Purpose of file: PHP Class that manage domain names installed on the server
23  ----------------------------------------------------------------------
24 */
25 
26 define('SLAVE_FLAG', "/var/run/alternc/refresh_slave");
27 
28 /**
29 * Classe de gestion des domaines de l'hébergé.
30 *
31 * Cette classe permet de gérer les domaines / sous-domaines, redirections
32 * dns et mx des domaines d'un membre hébergé.<br />
33 */
34 class m_dom {
35 
36  /** $domains : Cache des domaines du membre
37  * @access private
38  */
39  var $domains;
40 
41  /** $dns : Liste des dns trouvés par la fonction whois
42  * @access private
43  */
44  var $dns;
45 
46  /** Flag : a-t-on trouvé un sous-domaine Webmail pour ce domaine ?
47  * @access private
48  */
49  var $webmail;
50 
51  /**
52  * Système de verrouillage du cron
53  * Ce fichier permet de verrouiller le cron en attendant la validation
54  * du domaine par update_domains.sh
55  * @access private
56  */
57  var $fic_lock_cron="/var/run/alternc/cron.lock";
58 
59  /**
60  * Le cron a-t-il été bloqué ?
61  * Il faut appeler les fonctions privées lock et unlock entre les
62  * appels aux domaines.
63  * @access private
64  */
65  var $islocked=false;
66 
67  var $type_local = "VHOST";
68  var $type_url = "URL";
69  var $type_ip = "IP";
70  var $type_webmail = "WEBMAIL";
71  var $type_ipv6 = "IPV6";
72  var $type_cname = "CNAME";
73  var $type_txt = "TXT";
74  var $type_defmx = "DEFMX";
75  var $type_defmx2 = "DEFMX2";
76 
77  var $action_insert = "0";
78  var $action_update= "1";
79  var $action_delete = "2";
80 
82  /* ----------------------------------------------------------------- */
83  /**
84  * Constructeur
85  */
86  function m_dom() {
87  $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(array('desc'=>'Disabled','type'=>'boolean')));
88  variable_get('mailname_bounce', '%%FQDN%%','FQDN of the mail server, used to create vhost virtual mail_adress.', array(array('desc'=>'FQDN','type'=>'string')));
89  }
90 
91  function get_panel_url_list() {
92  global $db,$err;
93  $err->log("dom","get_panel_url_list");
94  $db->query("SELECT sd.id as sub_id, if(length(sd.sub)>0,concat_ws('.',sd.sub,sd.domaine),sd.domaine) as fqdn from sub_domaines sd where type = 'PANEL';");
95  $t=array();
96  while ($db->next_record()) {
97  $t[intval($db->f('sub_id'))] = $db->f('fqdn');
98  }
99  return $t;
100  }
101 
103  global $db,$err,$cuid;
104  $err->log("dom","get_sub_domain_by_name");
105  $fqdn=mysql_real_escape_string($fqdn);
106  $db->query("select sd.* from sub_domaines sd where if(length(sd.sub)>0,concat_ws('.',sd.sub,sd.domaine),sd.domaine) = '$fqdn';");
107  if (! $db->next_record()) return false;
108  return array('sub_id'=>intval($db->f('id')), 'member_id'=> intval($db->f('compte') ));
109  }
110 
111  function hook_menu() {
112  global $quota;
113  $obj = array(
114  'title' => _("Domains"),
115  'ico' => 'images/dom.png',
116  'link' => 'toggle',
117  'pos' => 20,
118  'links' => array(),
119  ) ;
120 
121  if ( $quota->cancreate("dom") ) {
122  $obj['links'][] =
123  array (
124  'ico' => 'images/new.png',
125  'txt' => _("Add a domain"),
126  'url' => "dom_add.php",
127  );
128  }
129 
130  foreach ($this->enum_domains() as $d) {
131  $obj['links'][] =
132  array (
133  'txt' => htmlentities($d),
134  'url' => "dom_edit.php?domain=".urlencode($d),
135  );
136  }
137 
138  return $obj;
139  }
140 
141 
142 
143  /* ----------------------------------------------------------------- */
144  /**
145  * Retourne un tableau contenant les types de domaines
146  *
147  * @return array retourne un tableau indexé contenant la liste types de domaines
148  * authorisé. Retourne FALSE si une erreur s'est produite.
149  */
150  function domains_type_lst() {
151  global $db,$err,$cuid;
152  $err->log("dom","domains_type_lst");
153  $db->query("select * from domaines_type order by advanced;");
154  $this->domains_type_lst=false;
155  while ($db->next_record()) {
156  $this->domains_type_lst[strtolower($db->Record["name"])] = $db->Record;
157  }
158  return $this->domains_type_lst;
159  }
160 
162  global $db,$err,$cuid;
163  $err->log("dom","domains_type_target_values");
164  $db->query("desc domaines_type;");
165  $r = array();
166  while ($db->next_record()) {
167  if ($db->f('Field') == 'enable') {
168  $tab = explode(",", substr($db->f('Type'), 5, -1));
169  foreach($tab as $t) { $r[]=substr($t,1,-1); }
170  }
171  }
172  return $r;
173  }
174 
175  function domains_type_target_values($type=null) {
176  global $db,$err,$cuid;
177  $err->log("dom","domains_type_target_values");
178  if (is_null($type)) {
179  $db->query("desc domaines_type;");
180  $r = array();
181  while ($db->next_record()) {
182  if ($db->f('Field') == 'target') {
183  $tab = explode(",", substr($db->f('Type'), 5, -1));
184  foreach($tab as $t) { $r[]=substr($t,1,-1); }
185  }
186  }
187  return $r;
188  } else {
189  $db->query("select target from domaines_type where name='$type';");
190  if (! $db->next_record()) return false;
191  return $db->f('target');
192  }
193  }
194 
195  function import_manual_dns_zone($zone, $domain, $detect_redirect=true, $save=false) {
196  global $err;
197  if ($save) {
198  if (! $this->import_manual_dns_prep_zone($domain) ) {
199  $err->raise('dom', _("Err: failed to prepare the zone"));
200  return false;
201  }
202  }
203 
204  $val = array();
205  foreach (explode("\n", $zone) as $z) {
206  $z=trim($z);
207  if (empty($z)) continue;
208  $val[] = $this->import_manual_dns_entry($z,$domain,$detect_redirect,$save);
209  }
210  return $val;
211  }
212 
213  function import_manual_dns_entry($zone, $domain, $detect_redirect=true, $save=false) {
214  global $cuid, $err;
215  $err->log("dom","import_manual_dns_entry");
216  $zone=trim($zone);
217  if (empty($zone)) return false;
218 
219  $domain=trim($domain);
220  if ( empty($domain) ) {
221  $err->raise("dom", _("Missing domain name"));
222  return false;
223  }
224 
225  $val = array(
226  'status' => 'err', // can be 'ok', 'err', 'warn'
227  'comment' => 'no val',
228  'entry_old' => $zone,
229  'entry_new' => array('domain'=>$domain),
230  );
231 
232  // Examples:
233  // ; hello comment
234  if ( preg_match('/^;/', $zone, $ret) ) {
235  $val['status'] = 'ok';
236  $val['comment'] = 'Just a comment, do not import';
237  } else
238  // Examples:
239  // $TTL 86400'
240  if ( preg_match('/^\$TTL\h+(?P<ttl>[\dMHDmhd]+)/', $zone, $ret) ) {
241  $val['status'] = 'ok';
242  $val['comment'] = 'Set TTL to '.$ret['ttl'];
243  $val['entry_new']['type'] = 'set_ttl';
244  $val['entry_new']['value'] = $ret['ttl'];
245  } else
246 
247  // Examples:
248  // @ IN AAAA 127.2.1.5
249  // reseau IN AAAA 145.214.44.55
250  if ( preg_match('/^(?P<sub>[\w\.@\-]*)\h*(?P<ttl>\d*)\h*IN\h+AAAA\h+(?P<target>[0-9A-F:]{2,40})/i', $zone, $ret) ) {
251 
252  // Check if it is just a redirect
253  if ( substr($ret['sub'], -1) == '.' ) { // if ending by a "." it is allready a FQDN
254  $url="http://".$ret['sub'];
255  } else {
256  if ( $ret['sub'] == '@' || empty($ret['sub']) ) {
257  $url="http://".$domain;
258  } else {
259  $url="http://".$ret['sub'].".".$domain;
260  }
261  }
262  if ( $detect_redirect && $dst_url = $this->is_it_a_redirect($url) ) {
263  $val['status'] = 'warn';
264  $val['comment'] = "Became a redirect to $dst_url";
265  $val['entry_new']['type'] = 'URL';
266  $val['entry_new']['sub'] = $ret['sub'];
267  $val['entry_new']['value'] = $dst_url;
268  } else {
269  $val['status'] = 'ok';
270  $val['comment'] = "Create entry AAAA with ".$ret['sub']." go to ".$ret['target']." with ttl ".$ret['ttl'];
271  $val['entry_new']['type'] = 'IPV6';
272  $val['entry_new']['sub'] = $ret['sub'];
273  $val['entry_new']['value'] = $ret['target'];
274  }
275  } else
276 
277 
278  // Examples:
279  // @ IN A 127.2.1.5
280  // reseau IN A 145.214.44.55
281  if ( preg_match('/^(?P<sub>[\w\.@\-]*)\h*(?P<ttl>\d*)\h*IN\h+A\h+(?P<target>\d+\.\d+\.\d+\.\d+)/i', $zone, $ret) ) {
282  // Check if it is just a redirect
283  if ( substr($ret['sub'], -1) == '.' ) { // if ending by a "." it is allready a FQDN
284  $url="http://".$ret['sub'];
285  } else {
286  if ( $ret['sub'] == '@' || empty($ret['sub']) ) {
287  $url="http://".$domain;
288  } else {
289  $url="http://".$ret['sub'].".".$domain;
290  }
291  }
292  if ( $detect_redirect && $dst_url = $this->is_it_a_redirect($url) ) {
293  $val['status'] = 'warn';
294  $val['comment'] = "Became a redirect to $dst_url";
295  $val['entry_new']['type'] = 'URL';
296  $val['entry_new']['sub'] = $ret['sub'];
297  $val['entry_new']['value'] = $dst_url;
298  } else {
299  $val['status'] = 'ok';
300  $val['comment'] = "Create entry A with ".$ret['sub']." go to ".$ret['target']." with ttl ".$ret['ttl'];
301  $val['entry_new']['type'] = 'IP';
302  $val['entry_new']['sub'] = $ret['sub'];
303  $val['entry_new']['value'] = $ret['target'];
304  }
305  } else
306 
307  // Examples:
308  // @ IN NS ns.example.tld.
309  // ns 3600 IN NS 145.214.44.55
310  if ( preg_match('/^(?P<sub>[\-\w\.@]*)\h*(?P<ttl>\d*)\h*IN\h+NS\h+(?P<target>[\w\.\-]+)/i', $zone, $ret) ) {
311  if ( empty($ret['sub']) || $ret['sub'] == '@' ) {
312  $val['status'] = 'warn';
313  $val['comment'] = "Won't migrate it, there will get a new value";
314  } else {
315  $val['status'] = 'ok';
316  $val['comment'] = "Create entry NS with ".$ret['sub']." go to ".$ret['target']." with ttl ".$ret['ttl'];
317  $val['entry_new']['type'] = 'FIXME-NS';
318  $val['entry_new']['sub'] = $ret['sub'];
319  $val['entry_new']['value'] = $ret['target'];
320  }
321  } else
322 
323  // Examples:
324  // agenda IN CNAME ghs.google.com.
325  // www 3600 IN CNAME @
326  if ( preg_match('/^(?P<sub>[\-\w\.@]*)\h*(?P<ttl>\d*)\h*IN\h+CNAME\h+(?P<target>[@\w+\.\-]+)/i', $zone, $ret) ) {
327  if ( substr($ret['sub'], -1) == '.' ) { // if ending by a "." it is allready a FQDN
328  $url="http://".$ret['sub'];
329  } else {
330  if ( $ret['sub'] == '@' || empty($ret['sub']) ) {
331  $url="http://".$domain;
332  } else {
333  $url="http://".$ret['sub'].".".$domain;
334  }
335  }
336  if ( $detect_redirect && $dst_url = $this->is_it_a_redirect($url) ) {
337  $val['status'] = 'warn';
338  $val['comment'] = "Became a redirect to $dst_url";
339  $val['entry_new']['type'] = 'URL';
340  $val['entry_new']['sub'] = $ret['sub'];
341  $val['entry_new']['value'] = $dst_url;
342  } else {
343  $val['status'] = 'ok';
344  $val['comment'] = "Create entry CNAME with ".$ret['sub']." go to ".$ret['target']." with ttl ".$ret['ttl'];
345  $val['entry_new']['type'] = 'CNAME';
346  $val['entry_new']['sub'] = $ret['sub'];
347  $val['entry_new']['value'] = $ret['target'];
348  }
349  } else
350 
351  // Examples:
352  // @ IN MX 10 aspmx.l.google.com.
353  // arf 3600 IN MX 20 pouet.fr.
354  if ( preg_match('/^(?P<sub>[\-\w\.@]*)\h*(?P<ttl>\d*)\h*IN\h+MX\h+(?P<weight>\d+)\h+(?P<target>[@\w+\.\-]+)/i', $zone, $ret) ) {
355  $val['status'] = 'warn';
356  $val['comment'] = "Create entry MX with ".$ret['sub']." go to ".$ret['target']." with ttl ".$ret['ttl']." and weight 5 (initial weight was ".$ret['weight'].")";
357  $val['entry_new']['type'] = 'MX';
358  $val['entry_new']['sub'] = $ret['sub'];
359  $val['entry_new']['value'] = $ret['target'];
360  } else
361 
362  // Examples:
363  // _sip._tcp IN SRV 1 100 5061 sip.example.tld.
364  if ( preg_match('/^(?P<sub>[\_\w\.@\-]+)\h+(?P<ttl>\d*)\h*IN\h+SRV\h+/i', $zone, $ret) ) {
365  $val['status']='err';
366  $val['comment'] = "Please add yourself the entry $zone";
367  } else
368 
369  // Examples:
370  // @ IN TXT "google-site-verification=jjjjjjjjjjjjjjjjjjjjjjjjsdsdjlksjdljdslgNj5"
371  if ( preg_match('/^(?P<sub>[\_\w\.@\-]*)\h*(?P<ttl>\d*)\h*IN\h+TXT\h+\"(?P<target>.+)\"/i', $zone, $ret) ) {
372  $val['status']='ok';
373  $val['comment'] = "Create TXT entry with ".$ret['sub']." go to ".$ret['target'];
374  $val['entry_new']['type'] = 'TXT';
375  $val['entry_new']['sub'] = $ret['sub'];
376  $val['entry_new']['value'] = $ret['target'];
377  } else {
378 
379  // WTF can it be ?
380  $val['comment'] = "Unknow: $zone";
381  }
382 
383  if ($save) {
384  return $this->import_manual_dns_entry_doit($val);
385  }
386 
387  return $val;
388  }
389 
390  private function import_manual_dns_entry_doit($entry) {
391  global $err;
392  $entry['did_it'] = 0;
393  if ( $entry['status'] == 'err' ) {
394  return $entry;
395  }
396 
397  $val=$entry['entry_new'];
398 
399  if (empty($val['type'])) return false;
400 
401  switch($val['type']) {
402  case "set_ttl":
403  $entry['did_it'] = $this->set_ttl($this->get_domain_byname($val['domain']), $val['value']);
404  return $entry;
405  break;
406  }
407 
408  // If it is a know domains type
409  if (! array_key_exists( strtolower($val['type']), $this->domains_type_lst() ) ) {
410  echo "what is this shit ?\n";
411  print_r($entry);
412  return $entry;
413  }
414 
415  // If the subdomain is @, we want an empty subdomain
416  if ($val['sub'] == '@') $val['sub'] = '';
417 
418  $this->lock();
419  $entry['did_it'] = $this->set_sub_domain($val['domain'], $val['sub'], $val['type'], $val['value']);
420  $this->unlock();
421 
422  return $entry;
423  }
424 
426  global $err;
427  // Prepare a domain to be importer :
428  // * create the domain
429  // * delete all automatic subdomain
430  // * set no mx
431  $this->lock();
432 
433  // function add_domain($domain,$dns,$noerase=0,$force=0,$isslave=0,$slavedom="")
434  if (! $this->add_domain($domain, true, false, 1) ) {
435  $err->raise('dom', "Error adding domain");
436  return false;
437  }
438 
439  // Set no mx
440  $this->edit_domain($domain, true, false);
441 
442  $d = $this->get_domain_all($domain);
443  foreach( $d['sub'] as $sd) {
444  $this->del_sub_domain($sd['id']);
445  }
446 
447  $this->unlock();
448 
449  return true;
450  }
451 
452  // Take an URL, and return FALSE is there is no redirection,
453  // and the target URL if there is one (HTTP CODE 301 & 302)
454  // CURL is needed
455  function is_it_a_redirect($url) {
456  try {
457  $params = array('http' => array(
458  'method' => 'HEAD',
459  'ignore_errors' => true
460  ));
461 
462  $context = stream_context_create($params);
463  $fp = @fopen($url, 'rb', false, $context);
464  $result = @stream_get_contents($fp);
465 
466  if ($result === false) {
467  throw new Exception("Could not read data from {$url}");
468  return false;
469  }
470  if ( strstr($http_response_header[0], '301') || strstr($http_response_header[0], '302')) {
471  // This is a redirection
472  if ( preg_match( '/Location:\h+(?P<target>[\-\w:\/.\?\=.]+)/', implode("\n",$http_response_header), $ret ) ) {
473  // check if it is a redirection to himself
474  preg_match('/\/\/(?P<host>[\w\.\-]+)\//', ( substr($url,-1)=='/'?$url:$url.'/') , $original_cname);
475  preg_match('/\/\/(?P<host>[\w\.\-]+)\//', $ret['target'], $target_url);
476  if ( isset($target_url['host']) && ( $target_url['host'] == $original_cname['host'] ) ) { // if it's a redirection to himself (sub pages, http to https...)
477  return false; // do not do a redirection (we must point to the server)
478  }
479 
480  // If it is a redirection to a sub directory
481  // (we know it is a redirection to a sub directory because it's not a complete URI)
482  if ( substr($ret['target'],0,4) != 'http' ) {
483  return 'http://'.$original_cname['host'].'/'.$ret['target'];
484  }
485  return $ret['target'];
486  }
487  } else { // it isn't a redirection
488  return false;
489  }
490  } catch (Exception $e) {
491  return false;
492  }
493  }
494 
495  function domains_type_regenerate($name) {
496  global $db,$err,$cuid;
497  $name=mysql_real_escape_string($name);
498  $db->query("update sub_domaines set web_action='UPDATE' where lower(type) = lower('$name') ;");
499  $db->query("update domaines d, sub_domaines sd set d.dns_action = 'UPDATE' where lower(sd.type)=lower('$name');");
500  return true;
501  }
502 
503  function domains_type_get($name) {
504  global $db,$err,$cuid;
505  $name=mysql_real_escape_string($name);
506  $db->query("select * from domaines_type where name='$name' ;");
507  $db->next_record();
508  return $db->Record;
509  }
510 
511  function domains_type_del($name) {
512  global $db,$err,$cuid;
513  $name=mysql_real_escape_string($name);
514  $db->query("delete domaines_type where name='$name';");
515  return true;
516  }
517 
518  function domains_type_update($name, $description, $target, $entry, $compatibility, $enable, $only_dns, $need_dns,$advanced,$create_tmpdir,$create_targetdir) {
519  global $err,$cuid,$db;
520  // The name MUST contain only letter and digits, it's an identifier after all ...
521  if (!preg_match("#^[a-z0-9]+$#",$name)) {
522  $err->raise("dom", _("The name MUST contain only letter and digits"));
523  return false;
524  }
525  $name=mysql_real_escape_string($name); $description=mysql_real_escape_string($description); $target=mysql_real_escape_string($target);
526  $entry=mysql_real_escape_string($entry); $compatibility=mysql_real_escape_string($compatibility); $enable=mysql_real_escape_string($enable);
527  $only_dns=intval($only_dns); $need_dns=intval($need_dns); $advanced=intval($advanced); $create_tmpdir=intval($create_tmpdir); $create_targetdir=intval($create_targetdir);
528  $db->query("UPDATE domaines_type SET description='$description', target='$target', entry='$entry', compatibility='$compatibility', enable='$enable', need_dns=$need_dns, only_dns=$only_dns, advanced='$advanced',create_tmpdir=$create_tmpdir,create_targetdir=$create_targetdir where name='$name';");
529  return true;
530  }
531 
532  function sub_domain_change_status($sub_id,$status) {
533  global $db,$err,$cuid;
534  $err->log("dom","sub_domain_change_status");
535  $sub_id=intval($sub_id);
536  $status=strtoupper($status);
537  if (! in_array($status,array('ENABLE', 'DISABLE'))) return false;
538 
539  $jh = $this->get_sub_domain_all($sub_id);
540  if ($status == 'ENABLE') { // check compatibility with existing sub_domains
541  if (! $this->can_create_subdomain($jh['domain'], $jh['name'], $jh['type'], $sub_id) ) {
542  $err->raise("dom", _("The parameters for this subdomain and domain type are invalid. Please check for subdomain entries incompatibility"));
543  return false;
544  }
545  }
546 
547  $db->query("update sub_domaines set enable='$status' where id = '".intval($sub_id)."';");
548  $this->set_dns_action($jh['domain'], 'UPDATE');
549 
550  return true;
551  }
552 
553  /* ----------------------------------------------------------------- */
554  /**
555  * Retourne un tableau contenant les domaines d'un membre.
556  * Par défaut le membre connecté
557  *
558  * @return array retourne un tableau indexé contenant la liste des
559  * domaines hébergés sur le compte courant. Retourne FALSE si une
560  * erreur s'est produite.
561  */
562  function enum_domains($uid=-1) {
563  global $db,$err,$cuid;
564  $err->log("dom","enum_domains");
565  if ($uid == -1) { $uid = $cuid; }
566  $db->query("SELECT * FROM domaines WHERE compte='{$uid}' ORDER BY domaine ASC;");
567  $this->domains=array();
568  if ($db->num_rows()>0) {
569  while ($db->next_record()) {
570  $this->domains[]=$db->f("domaine");
571  }
572  }
573  return $this->domains;
574  }
575 
577  global $db,$err,$classes,$cuid;
578  $err->log("dom","del_domaini_canl",$dom);
579  $dom=strtolower($dom);
580  $db->query("UPDATE sub_domaines SET web_action='UPDATE' WHERE domaine='$dom';");
581  $this->set_dns_action($dom, 'UPDATE');
582 
583  # TODO : some work with domain sensitive classes
584 
585  return true;
586  }
587 
588  /* ----------------------------------------------------------------- */
589  /**
590  * Efface un domaine du membre courant, et tous ses sous-domaines
591  *
592  * Cette fonction efface un domaine et tous ses sous-domaines, ainsi que
593  * les autres services attachés à celui-ci. Elle appelle donc les autres
594  * classe. Chaque classe peut déclarer une fonction del_dom qui sera
595  * appellée lors de la destruction d'un domaine.
596  *
597  * @param string $dom nom de domaine à effacer
598  * @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
599  */
600  function del_domain($dom) {
601  global $db,$err,$classes,$cuid,$hooks;
602  $err->log("dom","del_domain",$dom);
603  $dom=strtolower($dom);
604 
605  $this->lock();
606  if (!$r=$this->get_domain_all($dom)) {
607  return false;
608  }
609  $this->unlock();
610 
611  // Call Hooks to delete the domain and the MX management:
612  // TODO : the 2 calls below are using an OLD hook call, FIXME: remove them when unused
613  $hooks->invoke("alternc_del_domain",array($dom));
614  $hooks->invoke("alternc_del_mx_domain",array($dom));
615  // New hook calls:
616  $hooks->invoke("hook_dom_del_domain",array($r["id"]));
617  $hooks->invoke("hook_dom_del_mx_domain",array($r["id"]));
618 
619  // Now mark the domain for deletion:
620  $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine='$dom';");
621  $this->set_dns_action($dom, 'DELETE');
622 
623  return true;
624  }
625 
626  function domshort($dom, $sub="") {
627  return str_replace("-","",str_replace(".","",empty($sub)?"":"$sub.").$dom );
628  }
629 
630  /* ----------------------------------------------------------------- */
631  /**
632  * Installe un domaine sur le compte courant.
633  *
634  * <p>Si le domaine existe déjà ou est interdit, ou est celui du serveur,
635  * l'installation est refusée. Si l'hébergement DNS est demandé, la fonction
636  * checkhostallow vérifiera que le domaine peut être installé conformément
637  * aux demandes des super-admin.
638  * Si le dns n'est pas demandé, le domaine peut être installé s'il est en
639  * seconde main d'un tld (exemple : test.eu.org ou test.com, mais pas
640  * toto.test.org ou test.test.asso.fr)</p>
641  * <p>Chaque classe peut définir une fonction add_dom($dom) qui sera
642  * appellée lors de l'installation d'un nouveau domaine.</p>
643  *
644  * @param string $dom nom fqdn du domaine à installer
645  * @param integer $dns 1 ou 0 pour héberger le DNS du domaine ou pas.
646  * @param integer $noerase 1 ou 0 pour rendre le domaine inamovible ou non
647  * @param integer $force 1 ou 0, si 1, n'effectue pas les tests de DNS.
648  * force ne devrait être utilisé que par le super-admin.
649  $ @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
650  */
651  function add_domain($domain,$dns,$noerase=0,$force=0,$isslave=0,$slavedom="") {
652  global $db,$err,$quota,$classes,$L_MX,$L_FQDN,$tld,$cuid,$bro,$hooks;
653  $err->log("dom","add_domain",$domain);
654 
655  // Locked ?
656  if (!$this->islocked) {
657  $err->raise("dom",_("--- Program error --- No lock on the domains!"));
658  return false;
659  }
660  // Verifie que le domaine est rfc-compliant
661  $domain=strtolower($domain);
663  if ($t) {
664  $err->raise("dom",_("The domain name is syntaxically incorrect"));
665  return false;
666  }
667  // Interdit les domaines clés (table forbidden_domains) sauf en cas FORCE
668  $db->query("SELECT domain FROM forbidden_domains WHERE domain='$domain'");
669  if ($db->num_rows() && !$force) {
670  $err->raise("dom",_("The requested domain is forbidden in this server, please contact the administrator"));
671  return false;
672  }
673  if ($domain==$L_FQDN || $domain=="www.$L_FQDN") {
674  $err->raise("dom",_("This domain is the server's domain! You cannot host it on your account!"));
675  return false;
676  }
677  $db->query("SELECT compte FROM domaines WHERE domaine='$domain';");
678  if ($db->num_rows()) {
679  $err->raise("dom",_("The domain already exist"));
680  return false;
681  }
682  $db->query("SELECT compte FROM `sub_domaines` WHERE sub != \"\" AND concat( sub, \".\", domaine )='$domain' OR domaine='$domain';");
683  if ($db->num_rows()) {
684  $err->raise("dom",_("The domain already exist"));
685  return false;
686  }
687  $this->dns=$this->whois($domain);
688  if (!$force) {
689  $v=checkhostallow($domain,$this->dns);
690  if ($v==-1) {
691  $err->raise("dom",_("The last member of the domain name is incorrect or cannot be hosted in that server"));
692  return false;
693  }
694  if ($dns && $v==-2) {
695  $err->raise("dom",_("The domain cannot be found in the whois database"));
696  return false;
697  }
698  if ($dns && $v==-3) {
699  $err->raise("dom",_("The domain cannot be found in the whois database"));
700  return false;
701  }
702 
703  if ($dns) $dns="1"; else $dns="0";
704 
705  // mode 5 : force DNS to NO.
706  if ($tld[$v]==5) $dns=0;
707  // It must be a real domain (no subdomain)
708  if (!$dns) {
710  if ($v) {
711  $err->raise("dom",_("The requested domain is forbidden in this server, please contact the administrator"));
712  return false;
713  }
714  }
715  }
716  // Check the quota :
717  if (!$quota->cancreate("dom")) {
718  $err->raise("dom",_("Your domain quota is over, you cannot create more domain names"));
719  return false;
720  }
721  if ($noerase) $noerase="1"; else $noerase="0";
722  if ($dns) $gesmx="1"; else $gesmx="0"; // do not host mx by default if not hosting the DNS
723  $db->query("INSERT INTO domaines (compte,domaine,gesdns,gesmx,noerase,dns_action) VALUES ('$cuid','$domain','$dns','$gesmx','$noerase','UPDATE');");
724  if (!($id=$db->lastid())) {
725  $err->raise("dom",_("An unexpected error occured when creating the domain"));
726  return false;
727  }
728 
729  if ($isslave) {
730  $isslave=true;
731  $db->query("SELECT domaine FROM domaines WHERE compte='$cuid' AND domaine='$slavedom';");
732  $db->next_record();
733  if (!$db->Record["domaine"]) {
734  $err->raise("dom",_("Domain '%s' not found"),$slavedom);
735  $isslave=false;
736  }
737  // Point to the master domain :
738  $this->create_default_subdomains($domain, $slavedom);
739  }
740  if (!$isslave) {
742  }
743 
744  // TODO: Old hooks, FIXME: when unused remove them
745  $hooks->invoke("alternc_add_domain",array($domain));
746  if ($isslave) {
747  $hooks->invoke("alternc_add_slave_domain",array($domain));
748  }
749  // New Hooks:
750  $hooks->invoke("hook_dom_add_domain",array($id));
751  if ($gesmx) $hooks->invoke("hook_dom_add_mx_domain",array($id));
752  if ($isslave) {
753  $hooks->invoke("hook_dom_add_slave_domain",array($id, $slavedom));
754  }
755  return true;
756  }
757 
758  function create_default_subdomains($domain,$target_domain=""){
759  global $db,$err;
760  $err->log("dom","create_default_subdomains",$domain);
761  $query="SELECT sub, domain_type, domain_type_parameter FROM default_subdomains WHERE (concerned = 'SLAVE' or concerned = 'BOTH') and enabled=1;";
762  if(empty($target_domain)) {
763  $query="SELECT sub, domain_type, domain_type_parameter FROM default_subdomains WHERE (concerned = 'MAIN' or concerned = 'BOTH') and enabled=1;";
764  }
765  $domaindir=$this->domdefaultdir($domain);
766  $db->query($query);
767  $jj=array();
768  while ($db->next_record()) {
769  $jj[]=Array("domain_type_parameter"=>$db->f('domain_type_parameter'),"sub"=>$db->f('sub'), "domain_type"=>$db->f('domain_type'));
770  }
771  $src_var=array("%%SUB%%","%%DOMAIN%%","%%DOMAINDIR%%", "%%TARGETDOM%%");
772  foreach($jj as $j){
773  $trg_var=array($j['sub'],$domain,$domaindir,$target_domain);
774  $domain_type_parameter=str_ireplace($src_var,$trg_var,$j['domain_type_parameter']);
775  $this->set_sub_domain($domain, $j['sub'], strtolower($j['domain_type']), $domain_type_parameter);
776  }
777  }
778 
779  function domdefaultdir($domain) {
780  global $bro,$cuid;
781  $dest_root = $bro->get_userid_root($cuid);
782  # return $dest_root."/www/".$this->domshort($domain);
783  return "/www/".$this->domshort($domain);
784  }
785 
786  function dump_axfr($domain, $ns='localhost') {
787  exec('/usr/bin/dig AXFR "'.escapeshellcmd($domain).'" @"'.escapeshellcmd($ns).'"', $axfr);
788  return $axfr;
789  }
790 
791 
793  global $db,$err;
794  $err->log("dom","lst_default_subdomains");
795  $c=array();
796  $db->query("select * from default_subdomains;");
797 
798  while($db->next_record()) {
799  $c[]=array('id'=>$db->f('id'),
800  'sub'=>$db->f('sub'),
801  'domain_type'=>$db->f('domain_type'),
802  'domain_type_parameter'=>$db->f('domain_type_parameter'),
803  'concerned'=>$db->f('concerned'),
804  'enabled'=>$db->f('enabled')
805  ) ;
806  }
807 
808  return $c;
809  }
810 
811 
812  function update_default_subdomains($arr) {
813  global $err;
814  $err->log("dom","update_default_subdomains");
815  $ok=true;
816  foreach ($arr as $a) {
817  if (! isset($a['id'])) $a['id']=null;
818  if(!empty($a['sub']) || !empty($a['domain_type_parameter'])){
819 
820  if (! isset($a['enabled'])) $a['enabled']=0;
821  if (! $this->update_one_default($a['domain_type'],$a['sub'], $a['domain_type_parameter'], $a['concerned'], $a['enabled'],$a['id']) ) {
822  $ok=false;
823  }
824  }
825  }
826  return $ok;
827  }
828 
829  function update_one_default($domain_type,$sub,$domain_type_parameter,$concerned,$enabled,$id=null){
830  global $db,$err;
831  $err->log("dom","update_one_default");
832 
833  if($id==null)
834  $db->query("INSERT INTO default_subdomains values ('','".addslashes($sub)."','".addslashes($domain_type)."','".addslashes($domain_type_parameter)."','".addslashes($concerned)."','".addslashes($enabled)."');");
835  else
836  $db->query("UPDATE default_subdomains set sub='".addslashes($sub)."', domain_type='".addslashes($domain_type)."',domain_type_parameter='".addslashes($domain_type_parameter)."',concerned='".addslashes($concerned)."',enabled='".addslashes($enabled)."' where id=".addslashes($id).";");
837  return true;
838  //update
839 
840 
841  }
842 
843  function del_default_type($id){
844  global $err,$db;
845  $err->log("dom","del_default_type");
846 
847  if(!$db->query("delete from default_subdomains where id=$id;")){
848  $err->raise("dom",_("Could not delete default type"));
849  return false;
850  }
851 
852  return true;
853 
854 
855  }
856 
857  /* ----------------------------------------------------------------- */
858  /**
859  * Retourne les entrées DNS du domaine $domain issues du WHOIS.
860  *
861  * Cette fonction effectue un appel WHOIS($domain) sur Internet,
862  * et extrait du whois les serveurs DNS du domaine demandé. En fonction
863  * du TLD, on sait (ou pas) faire le whois correspondant.
864  * Actuellement, les tld suivants sont supportés :
865  * .com .net .org .be .info .ca .cx .fr .biz .name
866  *
867  * @param string $domain Domaine fqdn dont on souhaite les serveurs DNS
868  * @return array Retourne un tableau indexé avec les NOMS fqdn des dns
869  * du domaine demandé. Retourne FALSE si une erreur s'est produite.
870  *
871  */
872  function whois($domain) {
873  global $db,$err;
874  $err->log("dom","whois",$domain);
875  // pour ajouter un nouveau TLD, utiliser le code ci-dessous.
876  // echo "whois : $domain<br />";
877  preg_match("#.*\.([^\.]*)#",$domain,$out);
878  $ext=$out[1];
879  // pour ajouter un nouveau TLD, utiliser le code ci-dessous.
880  // echo "ext: $ext<br />";
881 
882  $serveur="";
883  if (($fp=@fsockopen("whois.iana.org", 43))>0) {
884  fputs($fp, "$domain\r\n");
885  $found = false;
886  $state=0;
887  while (!feof($fp)) {
888  $ligne = fgets($fp,128);
889  if (preg_match('#^whois:#', $ligne)) { $serveur=preg_replace('/whois:\ */','',$ligne,1); }
890  }
891  }
892  $serveur=str_replace(array(" ","\n"),"",$serveur);
893 
894  $egal="";
895  switch($ext) {
896  case "net":
897  $egal="=";
898  break;
899  case "name":
900  $egal="domain = ";
901  break;
902  }
903  // pour ajouter un nouveau TLD, utiliser le code ci-dessous.
904  // echo "serveur : $serveur <br />";
905  if (($fp=@fsockopen($serveur, 43))>0) {
906  fputs($fp, "$egal$domain\r\n");
907  $found = false;
908  $state=0;
909  while (!feof($fp)) {
910  $ligne = fgets($fp,128);
911  // pour ajouter un nouveau TLD, utiliser le code ci-dessous.
912  // echo "| $ligne<br />";
913  switch($ext) {
914  case "org":
915  case "com":
916  case "net":
917  case "info":
918  case "biz":
919  case "name":
920  case "cc":
921  if (preg_match("#Name Server:#", $ligne)) {
922  $found = true;
923  $tmp=strtolower(str_replace(chr(10), "",str_replace(chr(13),"",str_replace(" ","", str_replace("Name Server:","", $ligne)))));
924  if ($tmp)
925  $server[]=$tmp;
926  }
927  break;
928  case "cx":
929  $ligne = str_replace(chr(10), "",str_replace(chr(13),"",str_replace(" ","", $ligne)));
930  if ($ligne=="" && $state==1)
931  $state=2;
932  if ($state==1)
933  $server[]=strtolower($ligne);
934  if ($ligne=="Nameservers:" && $state==0) {
935  $state=1;
936  $found = true;
937  }
938  break;
939  case "eu":
940  case "be":
941  $ligne=preg_replace("/^ *([^ ]*) \(.*\)$/","\\1",trim($ligne));
942  if($found)
943  $tmp = trim($ligne);
944  if ($tmp)
945  $server[]=$tmp;
946  if ($ligne=="Nameservers:") {
947  $state=1;
948  $found=true;
949  }
950  break;
951  case "im":
952  if (preg_match('/Name Server:/', $ligne)) {
953  $found = true;
954  // weird regexp (trailing garbage after name server), but I could not make it work otherwise
955  $tmp = strtolower(preg_replace('/Name Server: ([^ ]+)\..$/',"\\1", $ligne));
956  $tmp = preg_replace('/[^-_a-z0-9\.]/', '', $tmp);
957  if ($tmp)
958  $server[]=$tmp;
959  }
960  break;
961  case "it":
962  if (preg_match("#nserver:#", $ligne)) {
963  $found=true;
964  $tmp=strtolower(preg_replace("/nserver:\s*[^ ]*\s*([^\s]*)$/","\\1", $ligne));
965  if ($tmp)
966  $server[]=$tmp;
967  }
968  break;
969  case "fr":
970  case "re":
971  if (preg_match("#nserver:#", $ligne)) {
972  $found=true;
973  $tmp=strtolower(preg_replace("#nserver:\s*([^\s]*)\s*.*$#","\\1", $ligne));
974  if ($tmp)
975  $server[]=$tmp;
976  }
977  break;
978  case "ca":
979  case "ws";
980  if (preg_match('#Name servers#', $ligne)) {
981  // found the server
982  $state = 1;
983  } elseif ($state) {
984  if (preg_match('#^[^%]#', $ligne) && $ligne = preg_replace('#[[:space:]]#', "", $ligne)) {
985  // first non-whitespace line is considered to be the nameservers themselves
986  $found = true;
987  $server[] = $ligne;
988  }
989  }
990  break;
991  case "coop":
992  if (preg_match('#Host Name:\s*([^\s]+)#', $ligne, $matches)) {
993  $found = true;
994  $server[] = $matches[1];
995  }
996  } // switch
997  } // while
998  fclose($fp);
999  } else {
1000  $err->raise("dom",_("The Whois database is unavailable, please try again later"));
1001  return false;
1002  }
1003 
1004  if ($found) {
1005  return $server;
1006  } else {
1007  $err->raise("dom",_("The domain cannot be found in the Whois database"));
1008  return false;
1009  }
1010  } // whois
1011 
1012 
1013  /* ----------------------------------------------------------------- */
1014  /**
1015  * vérifie la presence d'un champs mx valide sur un serveur DNS
1016  * $domaine est le domaine dont on veux véririfer les MX
1017  * $ref_domaine est le domaine avec lequel on veux comparer les MX
1018  * si $ref_domaine == false, on prend les MX par default
1019  *
1020  */
1021  function checkmx($domaine,$ref_domain=false) {
1022  global $L_DEFAULT_MX, $L_DEFAULT_SECONDARY_MX ;
1023 
1024  if ( $ref_domain ) {
1025  getmxrr($ref_domain, $ref_mx);
1026  } else {
1027  $ref_mx = array($L_DEFAULT_MX, $L_DEFAULT_SECONDARY_MX);
1028  }
1029 
1030  if (empty($ref_mx)) {
1031  // No reference mx
1032  return 3;
1033  }
1034 
1035  //récupére les champs mx
1036  if (!getmxrr($domaine,$mxhosts)) {
1037  //aucun hôte mx spécifié
1038  return 1;
1039  }
1040 
1041  if ( empty($mxhosts) ) {
1042  // no mx on the target domaine
1043  return 1;
1044  }
1045 
1046  $intersect = array_intersect($mxhosts, $ref_mx);
1047 
1048  if ( empty($intersect) ) {
1049  // no shared mx server
1050  return 2;
1051  }
1052 
1053  return 0;
1054  } //checkmx
1055 
1056 
1057  /* ----------------------------------------------------------------- */
1058  /**
1059  * retourne TOUTES les infos d'un domaine
1060  *
1061  * @param string $dom Domaine dont on souhaite les informations
1062  * @return array Retourne toutes les infos du domaine sous la forme d'un
1063  * tableau associatif comme suit :<br /><pre>
1064  * $r["name"] = Nom fqdn
1065  * $r["dns"] = Gestion du dns ou pas ?
1066  * $r["mx"] = Valeur du champs MX si "dns"=true
1067  * $r["mail"] = Heberge-t-on le mail ou pas ? (si "dns"=false)
1068  * $r["nsub"] = Nombre de sous-domaines
1069  * $r["sub"] = tableau associatif des sous-domaines
1070  * $r["sub"][0-(nsub-1)]["name"] = nom du sous-domaine (NON-complet)
1071  * $r["sub"][0-(nsub-1)]["dest"] = Destination (url, ip, local ...)
1072  * $r["sub"][0-(nsub-1)]["type"] = Type (0-n) de la redirection.
1073  * </pre>
1074  * Retourne FALSE si une erreur s'est produite.
1075  *
1076  */
1077  function get_domain_all($dom) {
1078  global $db,$err,$cuid;
1079  $err->log("dom","get_domain_all",$dom);
1080  // Locked ?
1081  if (!$this->islocked) {
1082  $err->raise("dom",_("--- Program error --- No lock on the domains!"));
1083  return false;
1084  }
1085  $t=checkfqdn($dom);
1086  if ($t) {
1087  $err->raise("dom",_("The domain name is syntaxically incorrect"));
1088  return false;
1089  }
1090  $r["name"]=$dom;
1091  $db->query("SELECT * FROM domaines WHERE compte='$cuid' AND domaine='$dom'");
1092  if ($db->num_rows()==0) {
1093  $err->raise("dom",sprintf(_("Domain '%s' not found"),$dom));
1094  return false;
1095  }
1096  $db->next_record();
1097  $r["id"]=$db->Record["id"];
1098  $r["dns"]=$db->Record["gesdns"];
1099  $r["dns_action"]=$db->Record["dns_action"];
1100  $r["dns_result"]=$db->Record["dns_result"];
1101  $r["mail"]=$db->Record["gesmx"];
1102  $r["zonettl"]=$db->Record["zonettl"];
1103  $r['noerase']=$db->Record['noerase'];
1104  $db->free();
1105  $db->query("SELECT COUNT(*) AS cnt FROM sub_domaines WHERE compte='$cuid' AND domaine='$dom'");
1106  $db->next_record();
1107  $r["nsub"]=$db->Record["cnt"];
1108  $db->free();
1109  #$db->query("SELECT sd.*, dt.description AS type_desc, dt.only_dns FROM sub_domaines sd, domaines_type dt WHERE compte='$cuid' AND domaine='$dom' AND UPPER(dt.name)=UPPER(sd.type) ORDER BY sd.sub,sd.type");
1110  $db->query("SELECT sd.*, dt.description AS type_desc, dt.only_dns FROM sub_domaines sd LEFT JOIN domaines_type dt on UPPER(dt.name)=UPPER(sd.type) WHERE compte='$cuid' AND domaine='$dom' ORDER BY sd.sub,sd.type ;");
1111  // Pas de webmail, on le cochera si on le trouve.
1112  $r["sub"]=array();
1113  for($i=0;$i<$r["nsub"];$i++) {
1114  $db->next_record();
1115  $r["sub"][$i]=array();
1116  $r["sub"][$i]["id"]=$db->Record["id"];
1117  $r["sub"][$i]["name"]=$db->Record["sub"];
1118  $r["sub"][$i]["dest"]=$db->Record["valeur"];
1119  $r["sub"][$i]["type"]=$db->Record["type"];
1120  $r["sub"][$i]["enable"]=$db->Record["enable"];
1121  $r["sub"][$i]["type_desc"]=$db->Record["type_desc"];
1122  $r["sub"][$i]["only_dns"]=$db->Record["only_dns"];
1123  $r["sub"][$i]["web_action"]=$db->Record["web_action"];
1124  $r["sub"][$i]["fqdn"]= ((!empty($r["sub"][$i]["name"]))?$r["sub"][$i]["name"].".": "").$r["name"] ;
1125  }
1126  $db->free();
1127  return $r;
1128  } // get_domain_all
1129 
1130 
1131  /* ----------------------------------------------------------------- */
1132  /**
1133  * Retourne TOUTES les infos d'un sous domaine du compte courant.
1134  *
1135  * @param integer sub_domain_id id du subdomain
1136  * @return arrray Retourne un tableau associatif contenant les
1137  * informations du sous-domaine demandé.<pre>
1138  * $r["name"]= nom du sous-domaine (NON-complet)
1139  * $r["dest"]= Destination (url, ip, local ...)
1140  * </pre>
1141  * $r["type"]= Type (0-n) de la redirection.
1142  * Retourne FALSE si une erreur s'est produite.
1143  */
1144  function get_sub_domain_all($sub_domain_id) {
1145  global $db,$err,$cuid;
1146  $err->log("dom","get_sub_domain_all",$sub_domain_id);
1147  // Locked ?
1148  if (!$this->islocked) {
1149  $err->raise("dom",_("--- Program error --- No lock on the domains!"));
1150  return false;
1151  }
1152  $db->query("select sd.*, dt.description as type_desc, dt.only_dns from sub_domaines sd, domaines_type dt where compte='$cuid' and sd.id='$sub_domain_id' and upper(dt.name)=upper(sd.type);");
1153  if ($db->num_rows()==0) {
1154  $err->raise("dom",_("The sub-domain does not exist"));
1155  return false;
1156  }
1157  $db->next_record();
1158  $r=array();
1159  $r["id"]=$db->Record["id"];
1160  $r["name"]=$db->Record["sub"];
1161  $r["domain"]=$db->Record["domaine"];
1162  $r["dest"]=$db->Record["valeur"];
1163  $r["enable"]=$db->Record["enable"];
1164  $r["type"]=$db->Record["type"];
1165  $r["type_desc"]=$db->Record["type_desc"];
1166  $r["only_dns"]=$db->Record["only_dns"];
1167  $r["web_action"]=$db->Record["web_action"];
1168  $db->free();
1169  return $r;
1170  } // get_sub_domain_all
1171 
1172  function check_type_value($type, $value) {
1173  global $db,$err,$cuid;
1174 
1175  // check the type we can have in domaines_type.target
1176  switch ($this->domains_type_target_values($type)) {
1177  case 'NONE':
1178  if (empty($value) or is_null($value)) {return true;}
1179  break;
1180  case 'URL':
1181  if ( $value == strval($value)) {
1182  if(filter_var($value, FILTER_VALIDATE_URL)){
1183  return true;
1184  }else{
1185  $err->raise("dom",_("invalid url"));
1186  return false;
1187  }
1188  }
1189  break;
1190  case 'DIRECTORY':
1191  if (substr($value,0,1)!="/") {
1192  $value="/".$value;
1193  }
1194  if (!checkuserpath($value)) {
1195  $err->raise("dom",_("The folder you entered is incorrect or does not exist"));
1196  return false;
1197  }
1198  return true;
1199  break;
1200  case 'IP':
1201  if (checkip($value)) {
1202  return true;
1203  }else{
1204  $err->raise("dom",_("The ip address is invalid"));
1205  return false;
1206  }
1207  break;
1208  case 'IPV6':
1209  if (checkipv6($value)) {
1210  return true;
1211  }else{
1212  $err->raise("dom",_("The ip address is invalid"));
1213  return false;
1214  }
1215  break;
1216  case 'DOMAIN':
1217  if (checkcname($value)) {
1218  return true;
1219  }else{
1220  $err->raise("dom",_("The name you entered is incorrect"));
1221  return false;
1222  }
1223  break;
1224  case 'TXT':
1225  if ( $value == strval($value)) {
1226  return true;
1227  }else{
1228  $err->raise("dom",_("The TXT value you entered is incorrect"));
1229  return false;
1230  }
1231  break;
1232  default:
1233  $err->raise("dom",_("Invalid domain type selected, please check"));
1234  return false;
1235  break;
1236  }
1237  return false;
1238  } //check_type_value
1239 
1240 
1241  /* ----------------------------------------------------------------- */
1242  /**
1243  * Check the compatibility of the POSTed parameters with the chosen
1244  * domain type
1245  *
1246  * @param string $dom FQDN of the domain name
1247  * @param string $sub SUBdomain
1248  * @return boolean tell you if the subdomain can be installed there
1249  */
1250  function can_create_subdomain($dom,$sub,$type,$sub_domain_id='null') {
1251  global $db,$err,$cuid;
1252  $err->log("dom","can_create_subdomain",$dom."/".$sub);
1253 
1254  // Get the compatibility list for this domain type
1255  $db->query("select upper(compatibility) as compatibility from domaines_type where upper(name)=upper('$type');");
1256  if (!$db->next_record()) return false;
1257  $compatibility_lst = explode(",",$db->f('compatibility'));
1258 
1259  // Get the list of type of subdomains already here who have the same name
1260  $db->query("select * from sub_domaines where sub='$sub' and domaine='$dom' and not id = $sub_domain_id and web_action != 'DELETE' and enabled not in ('DISABLED', 'DISABLE') ");
1261  #$db->query("select * from sub_domaines where sub='$sub' and domaine='$dom';");
1262  while ($db->next_record()) {
1263  // And if there is a domain with a incompatible type, return false
1264  if (! in_array(strtoupper($db->f('type')),$compatibility_lst)) return false;
1265  }
1266 
1267  // All is right, go ! Create ur domain !
1268  return true;
1269  }
1270 
1271  /* ----------------------------------------------------------------- */
1272  /**
1273  * Modifier les information du sous-domaine demandé.
1274  *
1275  * <b>Note</b> : si le sous-domaine $sub.$dom n'existe pas, il est créé.<br />
1276  * <b>Note : TODO</b> : vérification de concordance de $dest<br />
1277  *
1278  * @param string $dom Domaine dont on souhaite modifier/ajouter un sous domaine
1279  * @param string $subk Sous domaine à modifier / créer
1280  * @param integer $type Type de sous-domaine (local, ip, url ...)
1281  * @param string $action Action : vaut "add" ou "edit" selon que l'on
1282  * Crée (add) ou Modifie (edit) le sous-domaine
1283  * @param string $dest Destination du sous-domaine, dépend de la valeur
1284  * de $type (url, ip, dossier...)
1285  * @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
1286  */
1287  function set_sub_domain($dom,$sub,$type,$dest, $sub_domain_id=null) {
1288  global $db,$err,$cuid,$bro;
1289  $err->log("dom","set_sub_domain",$dom."/".$sub."/".$type."/".$dest);
1290  // Locked ?
1291  if (!$this->islocked) {
1292  $err->raise("dom",_("--- Program error --- No lock on the domains!"));
1293  return false;
1294  }
1295  $dest=trim($dest);
1296  $sub=trim(trim($sub),".");
1297  $dom=strtolower($dom);
1298  $sub=strtolower($sub);
1299 
1300  // if (!(($sub == '*') || ($sub=="") || (preg_match('/([a-z0-9][\.\-a-z0-9]*)?[a-z0-9]/', $sub)))) {
1301  $fqdn=checkfqdn($sub);
1302  // Special cases : * (all subdomains at once) and '' empty subdomain are allowed.
1303  if (($sub != '*' && $sub!='') && !($fqdn==0 || $fqdn==4)) {
1304  $err->raise("dom",_("There is some forbidden characters in the sub domain (only A-Z 0-9 and - are allowed)"));
1305  return false;
1306  }
1307 
1308  if (! $this->check_type_value($type,$dest)) {
1309  //plutot verifier si la chaine d'erreur est vide avant de raise sinon sa veut dire que l(erruer est deja remonté
1310  #$err->raise("dom",_("Invalid domain type selected, please check"));
1311  return false;
1312  }
1313 
1314  // On a épuré $dir des problèmes eventuels ... On est en DESSOUS du dossier de l'utilisateur.
1315  if ($t=checkfqdn($dom)) {
1316  $err->raise("dom",_("The domain name is syntaxically incorrect"));
1317  return false;
1318  }
1319 
1320  if (! $this->can_create_subdomain($dom,$sub,$type,$sub_domain_id)) {
1321  $err->raise("dom", _("The parameters for this subdomain and domain type are invalid. Please check for subdomain entries incompatibility"));
1322  return false;
1323  }
1324 
1325  if (! is_null($sub_domain_id )) { // It's not a creation, it's an edit. Delete the old one
1326  $this->del_sub_domain($sub_domain_id);
1327  }
1328 
1329  // Re-create the one we want
1330  if (! $db->query("replace into sub_domaines (compte,domaine,sub,valeur,type,web_action) values ('$cuid','$dom','$sub','$dest','$type','UPDATE');") ) {
1331  echo "query failed: ".$db->Error;
1332  return false;
1333  }
1334 
1335  // Create TMP dir and TARGET dir if needed by the domains_type
1336  $dest_root = $bro->get_userid_root($cuid);
1337  $domshort=$this->domshort($dom,$sub);
1338  $db->query("select create_tmpdir, create_targetdir from domaines_type where name = '$type';");
1339  $db->next_record();
1340  if ($db->f('create_tmpdir')) {
1341  if (! is_dir($dest_root . "/tmp")) {
1342  if(!@mkdir($dest_root . "/tmp",0777,true)){
1343  $err->raise("dom",_("Cannot write to the destination folder"));
1344  }
1345  }
1346  }
1347  if ($db->f('create_targetdir')) {
1348  $dirr=$dest_root.$dest;
1349  $dirr=str_replace('//','/',$dirr);
1350 
1351  if (! is_dir($dirr)) {
1352  $old = umask(0);
1353  if(!@mkdir($dirr,0770,true)){
1354  $err->raise("dom",_("Cannot write to the destination folder"));
1355  }
1356  umask($old);
1357  }
1358  }
1359 
1360  // Tell to update the DNS file
1361  $db->query("update domaines set dns_action='UPDATE' where domaine='$dom';");
1362 
1363  return true;
1364  } // set_sub_domain
1365 
1366 
1367  /* ----------------------------------------------------------------- */
1368  /**
1369  * Supprime le sous-domaine demandé
1370  *
1371  * @param string $dom Domaine dont on souhaite supprimer un sous-domaine
1372  * @param string $sub Sous-domaine que l'on souhaite supprimer
1373  * @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
1374  *
1375  */
1376  function del_sub_domain($sub_domain_id) {
1377  global $db,$err,$cuid;
1378  $err->log("dom","del_sub_domain",$sub_domain_id);
1379  // Locked ?
1380  if (!$this->islocked) {
1381  $err->raise("dom",_("--- Program error --- No lock on the domains!"));
1382  return false;
1383  }
1384  if (!$r=$this->get_sub_domain_all($sub_domain_id)) {
1385  $err->raise("dom",_("The sub-domain does not exist"));
1386  return false;
1387  } else {
1388  $db->query("update sub_domaines set web_action='DELETE' where id='$sub_domain_id'; ");
1389  $db->query("update domaines set dns_action='UPDATE' where domaine='".$r['domain']."';");
1390  }
1391  return true;
1392  } // del_sub_domain
1393 
1394 
1395  function set_ttl($dom_id, $ttl) {
1396  global $err;
1397  $err->log("dom","set_ttl","$dom_id / $ttl");
1398  $this->lock();
1399  $domaine = $this->get_domain_byid($dom_id);
1400  $d = $this->get_domain_all($domaine);
1401 
1402  $j = $this->edit_domain($domaine, $d['dns'], $d['mail'], 0, $ttl);
1403  $this->unlock();
1404  return $j;
1405  }
1406 
1407  /* ----------------------------------------------------------------- */
1408  /**
1409  * Modifie les information du domaine précisé.
1410  *
1411  * @param string $dom Domaine du compte courant que l'on souhaite modifier
1412  * @param integer $dns Vaut 1 ou 0 pour héberger ou pas le DNS du domaine
1413  * @param integer $gesmx Héberge-t-on le emails du domaines sur ce serveur ?
1414  * @param boolean $force Faut-il passer les checks DNS ou MX ? (admin only)
1415  * @return boolean appelle $mail->add_dom ou $ma->del_dom si besoin, en
1416  * fonction du champs MX. Retourne FALSE si une erreur s'est produite,
1417  * TRUE sinon.
1418  *
1419  */
1420  function edit_domain($dom,$dns,$gesmx,$force=0,$ttl=86400) {
1421  global $db,$err,$L_MX,$classes,$cuid,$hooks;
1422  $err->log("dom","edit_domain",$dom."/".$dns."/".$gesmx);
1423  // Locked ?
1424  if (!$this->islocked && !$force) {
1425  $err->raise("dom",_("--- Program error --- No lock on the domains!"));
1426  return false;
1427  }
1428  if ($dns == 1 && !$force) {
1429  $this->dns=$this->whois($dom);
1430  $v=checkhostallow($dom,$this->dns);
1431  if ($v==-1) {
1432  $err->raise("dom",_("The last member of the domain name is incorrect or cannot be hosted in that server"));
1433  return false;
1434  }
1435  if ($dns && $v==-2) {
1436  $err->raise("dom",_("The domain cannot be found in the Whois database"));
1437  return false;
1438  }
1439  if ($dns && $v==-3) {
1440  $err->raise("dom",_("The DNS of this domain do not match the server's DNS. Please change your domain's DNS before you install it again"));
1441  return false;
1442  }
1443  }
1444 
1445  # Can't have ttl == 0. There is also a check in function_dns
1446  if ( $ttl == 0 ) { $ttl = 86400; }
1447 
1448  $t=checkfqdn($dom);
1449  if ($t) {
1450  $err->raise("dom",_("The domain name is syntaxically incorrect"));
1451  return false;
1452  }
1453  if (!$r=$this->get_domain_all($dom)) {
1454  // Le domaine n'existe pas, Failure
1455  $err->raise("dom",_("The domain name %s does not exist"),$dom);
1456  return false;
1457  }
1458  if ($dns!="1") $dns="0";
1459  // On vérifie que des modifications ont bien eu lieu :)
1460  if ($r["dns"]==$dns && $r["mail"]==$gesmx && $r["zonettl"]==$ttl) {
1461  $err->raise("dom",_("No change has been requested..."));
1462  return true;
1463  }
1464 
1465  //si gestion mx uniquement, vérification du dns externe
1466  if ($dns=="0" && $gesmx=="1" && !$force) {
1467  $vmx = $this->checkmx($dom);
1468  if ($vmx == 1) {
1469  $err->raise("dom",_("There is no MX record pointing to this server, and you are asking us to host the mail here. Make sure to update your MX entries or no mail will be received"));
1470  }
1471 
1472  if ($vmx == 2) {
1473  // Serveur non spécifié parmi les champx mx
1474  $err->raise("dom",_("There is no MX record pointing to this server, and you are asking us to host the mail here. Make sure to update your MX entries or no mail will be received"));
1475  }
1476  }
1477 
1478  if ($gesmx && !$r["mail"]) {
1479  $hooks->invoke("hook_dom_add_mx_domain",array($r["id"]));
1480  }
1481 
1482  if (!$gesmx && $r["mail"]) { // on a dissocié le MX : on détruit donc l'entree dans LDAP
1483  $hooks->invoke("hook_dom_del_mx_domain",array($r["id"]));
1484  }
1485 
1486  $db->query("UPDATE domaines SET gesdns='$dns', gesmx='$gesmx', zonettl='$ttl' WHERE domaine='$dom'");
1487  $dom->set_dns_action($dom, 'UPDATE');
1488 
1489  return true;
1490  } // edit_domain
1491 
1492 
1493  /****************************/
1494  /* Slave dns ip managment */
1495  /****************************/
1496 
1497 
1498  /* ----------------------------------------------------------------- */
1499  /** Return the list of ip addresses and classes that are allowed access to domain list
1500  * through AXFR Transfers from the bind server.
1501  */
1502  function enum_slave_ip() {
1503  global $db,$err;
1504  $db->query("SELECT * FROM slaveip;");
1505  if (!$db->next_record()) {
1506  return false;
1507  }
1508  do {
1509  $res[]=$db->Record;
1510  } while ($db->next_record());
1511  return $res;
1512  }
1513 
1514 
1515  /* ----------------------------------------------------------------- */
1516  /** Add an ip address (or a ip class) to the list of allowed slave ip access list.
1517  */
1518  function add_slave_ip($ip,$class="32") {
1519  global $db,$err;
1520  if (!checkip($ip)) {
1521  $err->raise("dom",_("The IP address you entered is incorrect"));
1522  return false;
1523  }
1524  $class=intval($class);
1525  if ($class<8 || $class>32) $class=32;
1526  $db->query("SELECT * FROM slaveip WHERE ip='$ip' AND class='$class';");
1527  if ($db->next_record()) {
1528  $err->raise("err",_("The requested domain is forbidden in this server, please contact the administrator"));
1529  return false;
1530  }
1531  $db->query("INSERT INTO slaveip (ip,class) VALUES ('$ip','$class');");
1532  $f=fopen(SLAVE_FLAG,"w");
1533  fputs($f,"yopla");
1534  fclose($f);
1535  return true;
1536  }
1537 
1538 
1539  /* ----------------------------------------------------------------- */
1540  /** Remove an ip address (or a ip class) from the list of allowed slave ip access list.
1541  */
1542  function del_slave_ip($ip) {
1543  global $db,$err;
1544  if (!checkip($ip)) {
1545  $err->raise("dom",_("The IP address you entered is incorrect"));
1546  return false;
1547  }
1548  $db->query("DELETE FROM slaveip WHERE ip='$ip'");
1549  $f=fopen(SLAVE_FLAG,"w");
1550  fputs($f,"yopla");
1551  fclose($f);
1552  return true;
1553  }
1554 
1555 
1556  /* ----------------------------------------------------------------- */
1557  /** Check for a slave account
1558  */
1559  function check_slave_account($login,$pass) {
1560  global $db,$err;
1561  $db->query("SELECT * FROM slaveaccount WHERE login='$login' AND pass='$pass';");
1562  if ($db->next_record()) {
1563  return true;
1564  }
1565  return false;
1566  }
1567 
1568 
1569  /* ----------------------------------------------------------------- */
1570  /** Out (echo) the complete hosted domain list :
1571  */
1572  function echo_domain_list($integrity=false) {
1573  global $db,$err;
1574  $db->query("SELECT domaine FROM domaines WHERE gesdns=1 ORDER BY domaine");
1575  $tt="";
1576  while ($db->next_record()) {
1577  #echo $db->f("domaine")."\n";
1578  $tt.=$db->f("domaine")."\n";
1579  }
1580  echo $tt;
1581  if ($integrity) {
1582  echo md5($tt)."\n";
1583  }
1584  return true;
1585  }
1586 
1587 
1588  /* ----------------------------------------------------------------- */
1589  /** Returns the complete hosted domain list :
1590  */
1591  function get_domain_list($uid=-1) {
1592  global $db,$err;
1593  $uid=intval($uid);
1594  $res=array();
1595  if ($uid!=-1) {
1596  $sql=" AND compte='$uid' ";
1597  }
1598  $db->query("SELECT domaine FROM domaines WHERE gesdns=1 $sql ORDER BY domaine");
1599  while ($db->next_record()) {
1600  $res[]=$db->f("domaine");
1601  }
1602  return $res;
1603  }
1604 
1606  global $db,$err;
1607  $res=array();
1608  $db->query("SELECT domaine, gesdns, gesmx, dns_action, zonettl FROM domaines ORDER BY domaine");
1609  while ($db->next_record()) {
1610  $res[$db->f("domaine")] = array(
1611  "gesdns" => $db->f("gesdns"),
1612  "gesmx" => $db->f("gesmx"),
1613  "dns_action" => $db->f("dns_action"),
1614  "zonettl" => $db->f("zonettl"),
1615  );
1616  }
1617  return $res;
1618  }
1619 
1620 
1621  /* ----------------------------------------------------------------- */
1622  /** Returns the name of a domain for the current user, from it's domain_id
1623  * @param $dom_id integer the domain_id to search for
1624  * @return string the domain name, or false with an error raised.
1625  */
1626  function get_domain_byid($dom_id) {
1627  global $db,$err,$cuid;
1628  $dom_id=intval($dom_id);
1629  $db->query("SELECT domaine FROM domaines WHERE id=$dom_id AND compte=$cuid;");
1630  if ($db->next_record()) {
1631  $domain=$db->f("domaine");
1632  if (!$domain) {
1633  $err->raise("dom",_("This domain is not installed in your account"));
1634  return false;
1635  } else {
1636  return $domain;
1637  }
1638  } else {
1639  $err->raise("dom",_("This domain is not installed in your account"));
1640  return false;
1641  }
1642  }
1643 
1644 
1645  /* ----------------------------------------------------------------- */
1646  /** Returns the id of a domain for the current user, from it's domain name
1647  * @param $domain string the domain name to search for
1648  * @return integer the domain id, or false with an error raised.
1649  */
1651  global $db,$err,$cuid;
1652  $domain=trim($domain);
1653  $db->query("SELECT id FROM domaines WHERE domaine='".addslashes($domain)."' AND compte=$cuid;");
1654  if ($db->next_record()) {
1655  $id=$db->f("id");
1656  if (!$id) {
1657  $err->raise("dom",_("This domain is not installed in your account"));
1658  return false;
1659  } else {
1660  return $id;
1661  }
1662  } else {
1663  $err->raise("dom",_("This domain is not installed in your account"));
1664  return false;
1665  }
1666  }
1667 
1668 
1669  /* ----------------------------------------------------------------- */
1670  /** Count all domains, for all users
1671  */
1672  function count_domains_all() {
1673  global $db,$err,$cuid;
1674  $db->query("SELECT COUNT(*) AS count FROM domaines;");
1675  if ($db->next_record()) {
1676  return $db->f('count');
1677  } else {
1678  return 0;
1679  }
1680  }
1681 
1682 
1683  /* ----------------------------------------------------------------- */
1684  /** Return the list of allowed slave accounts
1685  */
1686  function enum_slave_account() {
1687  global $db,$err;
1688  $db->query("SELECT * FROM slaveaccount;");
1689  $res=array();
1690  while ($db->next_record()) {
1691  $res[]=$db->Record;
1692  }
1693  if (!count($res)) return false;
1694  return $res;
1695  }
1696 
1697 
1698  /* ----------------------------------------------------------------- */
1699  /** Add a slave account that will be allowed to access the domain list
1700  */
1701  function add_slave_account($login,$pass) {
1702  global $db,$err;
1703  $db->query("SELECT * FROM slaveaccount WHERE login='$login'");
1704  if ($db->next_record()) {
1705  $err->raise("dom",_("The specified slave account already exists"));
1706  return false;
1707  }
1708  $db->query("INSERT INTO slaveaccount (login,pass) VALUES ('$login','$pass')");
1709  return true;
1710  }
1711 
1712 
1713  /* ----------------------------------------------------------------- */
1714  /** Remove a slave account
1715  */
1716  function del_slave_account($login) {
1717  global $db,$err;
1718  $db->query("DELETE FROM slaveaccount WHERE login='$login'");
1719  return true;
1720  }
1721 
1722 
1723  /*************/
1724  /* Private */
1725  /*************/
1726 
1727 
1728  /* ----------------------------------------------------------------- */
1729  /** Try to lock a domain
1730  * @access private
1731  */
1732  function lock() {
1733  global $db,$err;
1734  $err->log("dom","lock");
1735  if ($this->islocked) {
1736  $err->raise("dom",_("--- Program error --- Lock already obtained!"));
1737  }
1738  while (file_exists($this->fic_lock_cron)) {
1739  sleep(2);
1740  }
1741  $this->islocked=true;
1742  return true;
1743  }
1744 
1745 
1746  /* ----------------------------------------------------------------- */
1747  /** Unlock the cron for domain management
1748  * return true
1749  * @access private
1750  */
1751  function unlock() {
1752  global $db,$err;
1753  $err->log("dom","unlock");
1754  if (!$this->islocked) {
1755  $err->raise("dom",_("--- Program error --- No lock on the domains!"));
1756  }
1757  $this->islocked=false;
1758  return true;
1759  }
1760 
1761 
1762  /* ----------------------------------------------------------------- */
1763  /** Declare that a domain's emails are hosted in this server :
1764  * This adds 2 MX entries in this domain (if required)
1765  */
1766  function hook_dom_add_mx_domain($dom_id) {
1767  global $err;
1768  $domain = $this->get_domain_byid($dom_id);
1769  $err->log("dom","hook_dom_add_mx_domain");
1770  $this->set_sub_domain($domain, '', $this->type_defmx, '');
1771  if (! empty($GLOBALS['L_DEFAULT_SECONDARY_MX'])) {
1772  $this->set_sub_domain($domain, '', $this->type_defmx2, '');
1773  }
1774  return true;
1775  }
1776 
1777 
1778  /* ----------------------------------------------------------------- */
1779  /**
1780  * Delete an account (all his domains)
1781  */
1783  global $err;
1784  $err->log("dom","alternc_del_member");
1785  $li=$this->enum_domains();
1786  foreach($li as $dom) {
1787  $this->del_domain($dom);
1788  }
1789  return true;
1790  }
1791 
1792 
1793  /* ----------------------------------------------------------------- */
1794  /** Returns the used quota for the $name service for the current user.
1795  * @param $name string name of the quota
1796  * @return integer the number of service used or false if an error occured
1797  * @access private
1798  */
1799  function hook_quota_get() {
1800  global $db,$err,$cuid;
1801  $err->log("dom","get_quota");
1802  $q=Array("name"=>"dom", "description"=>_("Domain name"), "used"=>0);
1803  $db->query("SELECT COUNT(*) AS cnt FROM domaines WHERE compte='$cuid'");
1804  if ($db->next_record() ) {
1805  $q['used']=$db->f("cnt");
1806  }
1807  return $q;
1808  }
1809 
1810 
1811 /*---------------------------------------------------------------------*/
1812 /** Returns the global domain(s) configuration(s) of a particular user
1813  * No parameters needed
1814  **/
1815  function alternc_export_conf() {
1816  global $db,$err;
1817  $err->log("dom","export");
1818  $this->enum_domains();
1819  foreach ($this->domains as $d) {
1820  $str=" <domaines>\n";
1821  $str.=" <nom>".$d."</nom>\n";
1822  $this->lock();
1823  $s=$this->get_domain_all($d);
1824  $this->unlock();
1825  if(empty($s["dns"])){
1826  $s["dns"]="non";
1827  }else{
1828  $s["dns"]="oui";
1829  }
1830  $str.=" <dns>".$s["dns"]."</dns>\n";
1831 
1832  if(empty($s["mx"])){
1833  $s["mx"]="non";
1834  }else{
1835  $s["mx"]="oui";
1836  }
1837 
1838  $str.=" <mx>".$s["mx"]."</mx>\n";
1839 
1840  if(empty($s["mail"])){
1841  $s["mail"]="non";
1842  }
1843  $str.=" <mail>".$s["mail"]."</mail>\n";
1844  if (is_array($s["sub"])) {
1845  foreach ($s["sub"] as $sub) {
1846  $str.=" <subdomain>\n";
1847  $str.=" <enabled>".$sub["enable"]." </enabled>\n";
1848  $str.=" <destination>".$sub["dest"]." </destination>\n";
1849  $str.=" <type>".$sub["type"]." </type>\n";
1850  $str.=" </subdomain>\n";
1851  }
1852 
1853  }
1854  $str.=" </domaines>\n";
1855  }
1856  return $str;
1857  }
1858 
1859 
1860 /**
1861  * Return an array with all the needed parameters to generate conf
1862  * of a vhost.
1863  * If no parameters, return the parameters for ALL the vhost.
1864  * Optionnal parameters: id of the sub_domaines
1865  *
1866  **/
1867 function generation_parameters($id=null, $only_apache=true) {
1868  global $db,$err;
1869  $err->log("dom","generation_parameters");
1870  $params="";
1871  if (! is_null($id) && intval($id)==$id ) {
1872  $id=intval($id);
1873  $params=" AND sd.id = $id ";
1874  }
1875  if ($only_apache) {
1876  $params.=" and dt.only_dns is false ";
1877  }
1878 // BUG BUG BUG FIXME
1879 // Suppression de comptes -> membres existe pas -> domaines a supprimer ne sont pas lister
1880  $db->query("
1881 select
1882  sd.id as sub_id,
1883  lower(sd.type) as type,
1884  m.login,
1885  m.uid as uid,
1886  if(length(sd.sub)>0,concat_ws('.',sd.sub,sd.domaine),sd.domaine) as fqdn,
1887  concat_ws('@',m.login,v.value) as mail,
1888  sd.valeur
1889 from
1890  sub_domaines sd left join membres m on sd.compte=m.uid,
1891  variable v,
1892  domaines_type dt
1893 where
1894  v.name='mailname_bounce'
1895  and lower(dt.name) = lower(sd.type)
1896  $params
1897 order by
1898  m.login,
1899  sd.domaine,
1900  sd.sub
1901 ;");
1902  $r = array();
1903  while ($db->next_record()) {
1904  $r[ $db->Record['sub_id'] ] = $db->Record;
1905  }
1906  return $r;
1907 }
1908 
1909 /**
1910  * Return an array with all informations of the domains_type
1911  * used to generate Apache conf.
1912  * Die if templates missing.
1913  * Warning: an Apache domains_type must have 'only_dns' == TRUE
1914  *
1915  **/
1917  global $dom;
1918  $d= array();
1919  foreach ($dom->domains_type_lst() as $k => $v) {
1920  if ( $v['only_dns'] == true ) continue;
1921  if (! $j = file_get_contents(ALTERNC_APACHE2_GEN_TMPL_DIR.'/'.strtolower($k).'.conf') ) {
1922  die("Error: missing file for $k");
1923  }
1924  $d[$k] = $v;
1925  $d[$k]['tpl'] = $j;
1926  }
1927  return $d;
1928 }
1929 
1930 // Launch old fashionned hooks as there was in AlternC 1.0
1931 function generate_conf_oldhook($action, $lst_sub, $sub_obj=null) {
1932  if (is_null($sub_obj)) $sub_obj=$this->generation_parameters(null, false);
1933 
1934  if (!isset($lst_sub[strtoupper($action)]) || empty( $lst_sub[strtoupper($action)] )) {
1935  return false;
1936  }
1937 
1938  $lst_by_type = $lst_sub[strtoupper($action)] ;
1939 
1940  foreach ( $lst_by_type as $type => $lid_arr) {
1941  $script = "/etc/alternc/functions_hosting/hosting_".strtolower($type).".sh";
1942  if (! @is_executable($script) ) {
1943  continue;
1944  }
1945  foreach ($lid_arr as $lid ) {
1946  $o = $sub_obj[$lid];
1947  $cmd = $script." ".escapeshellcmd(strtolower($action))." ";
1948  $cmd .= escapeshellcmd($o['fqdn'])." ".escapeshellcmd($o['valeur']);
1949 
1950  system($cmd);
1951  }
1952  } // foreach $lst_by_type
1953 }
1954 
1955 /**
1956  * Generate apache configuration.
1957  * Die if a specific FQDN have 2 vhost conf.
1958  *
1959  **/
1960 function generate_apacheconf($p = null) {
1961  // Get the parameters
1962  $lst = $this->generation_parameters($p);
1963 
1964  $gdt = $this->generation_domains_type();
1965 
1966  // Initialize duplicate check
1967  $check_dup = array();
1968 
1969  $ret='';
1970  foreach ($lst as $p ) {
1971  // Check if duplicate
1972  if ( in_array($p['fqdn'], $check_dup) ) {
1973  die("Error: duplicate fqdn : ".$p['fqdn']);
1974  } else {
1975  $check_dup[] = $p['fqdn'];
1976  }
1977 
1978  // Get the needed template
1979  $tpl = $gdt[ $p['type'] ] ['tpl'];
1980 
1981  // Replace needed vars
1982  $tpl = strtr($tpl, array(
1983  "%%LOGIN%%"=> $p['login'],
1984  "%%fqdn%%"=> $p['fqdn'],
1985  "%%document_root%%"=> getuserpath($p['login']).$p['valeur'],
1986  "%%account_root%%"=> getuserpath($p['login']),
1987  "%%redirect%%"=> $p['valeur'],
1988  "%%UID%%"=> $p['uid'],
1989  "%%GID%%"=> $p['uid'],
1990  "%%mail_account%%"=> $p['mail'],
1991  "%%user%%"=> "FIXME",
1992  ));
1993 
1994  // Security check
1995  if ( $p['uid'] < 1999 ) { // if UID is not an AlternC uid
1996  $ret.= "# ERROR: Sub_id: ".$p['sub_id']."- The uid seem to be dangerous\n";
1997  continue;
1998  }
1999 
2000  // Return the conf
2001  $ret.= "# Sub_id: ".$p['sub_id']."\n".$tpl;
2002  }
2003 
2004  return $ret;
2005 }
2006 
2007  // Return an array with the list of id of sub_domains waiting for an action
2008  function generation_todo() {
2009  global $db,$err;
2010  $err->log("dom","generation_todo");
2011  $db->query("select id as sub_id, web_action, type from sub_domaines where web_action !='ok';");
2012  $r = array();
2013  while ($db->next_record()) {
2014  $r[ strtoupper($db->Record['web_action']) ][ strtoupper($db->Record['type']) ][] = $db->f('sub_id');
2015  }
2016  return $r;
2017  }
2018 
2019  function subdomain_modif_are_done($sub_domain_id, $action) {
2020  global $db;
2021  $sub_domain_id=intval($sub_domain_id);
2022  switch (strtolower($action)) {
2023  case "delete":
2024  $sql="DELETE FROM sub_domaines WHERE id =$sub_domain_id;";
2025  break;
2026  default:
2027  $sql="UPDATE sub_domaines SET web_action='OK' WHERE id='$sub_domain_id'; ";
2028  }
2029  $db->query($sql);
2030  return true;
2031  }
2032 
2033  function set_dns_action($domain, $dns_action) {
2034  global $db;
2035  $db->query("UPDATE domaines SET dns_action='".mysql_escape_string($dns_action)."' WHERE domaine='".mysql_escape_string($domain)."'; ");
2036  return true;
2037  }
2038 
2039  function set_dns_result($domain, $dns_result) {
2040  global $db;
2041  $db->query("UPDATE domaines SET dns_result='".mysql_escape_string($dns_result)."' WHERE domaine='".mysql_escape_string($domain)."'; ");
2042  return true;
2043  }
2044 
2045  /* ----------------------------------------------------------------- */
2046  /** hook function called by AlternC-upnp to know which open
2047  * tcp or udp ports this class requires or suggests
2048  * @return array a key => value list of port protocol name mandatory values
2049  * @access private
2050  */
2051  function hook_upnp_list() {
2052  return array(
2053  "dns-tcp" => array("port" => 53, "protocol" => "tcp", "mandatory" => 1),
2054  "dns-udp" => array("port" => 53, "protocol" => "udp", "mandatory" => 1),
2055  );
2056  }
2057 
2058  // List if there is problems in the domains.
2059  // Problems can appear when editing domains type properties
2060  function get_problems($domain) {
2061  $this->lock();
2062  $da = $this->get_domain_all($domain);
2063  $this->unlock();
2064 
2065  $errors = array();
2066  // Check if there is more than 1 apache conf
2067  // by subdomain
2068  $tmp = array();
2069  foreach ( $da['sub'] as $sub ) {
2070  if ( ! $sub['only_dns'] ) {
2071  if (!isset($tmp[$sub['fqdn']])) {
2072  $tmp[$sub['fqdn']] = 0;
2073  }
2074  $tmp[$sub['fqdn']]++;
2075  if ($tmp[$sub['fqdn']] >= 2 ) {
2076  $errors[$sub['fqdn']]=sprintf(_("Problem on %s: there is more than 1 web configuration going to be generated for this sub-domain."), $sub['fqdn']);
2077  }
2078  }
2079  }
2080 
2081  // Check if we know each type of subdomain
2082  // Example: we may not know WEBMAIL if we upgrade from a previous setup
2083  foreach ( $da['sub'] as $sub ) {
2084  if (is_null($sub['type_desc'])) {
2085  $errors[$sub['fqdn']]=sprintf(_("Problem on %s: we do not know domain's type <b>%s</b>."),$sub['fqdn'], $sub['type']);
2086  }
2087  }
2088 
2089  // TODO: add a full compatibility check.
2090 
2091  return $errors;
2092  }
2093 
2094  function default_domain_type() {
2095  // This function is only used to allow translation of default domain types:
2096  _("Locally hosted");
2097  _("URL redirection");
2098  _("IPv4 redirect");
2099  _("Webmail access");
2100  _("Squirrelmail Webmail access");
2101  _("Roundcube Webmail access");
2102  _("IPv6 redirect");
2103  _("CNAME DNS entry");
2104  _("TXT DNS entry");
2105  _("MX DNS entry");
2106  _("secondary MX DNS entry");
2107  _("Default mail server");
2108  _("Default backup mail server");
2109  _("AlternC panel access");
2110  }
2111 
2112 } /* Class m_domains */