source: alternc/branches/stable-1.0/bureau/class/m_dom.php @ 3079

Revision 3079, 41.0 KB checked in by fufroma, 22 months ago (diff)

alternc-slavedns ne pouvait pas fonctionner
whois de alternc réparé

Line 
1<?php
2/*
3 $Id: m_dom.php,v 1.27 2006/02/17 18:34:30 olivier Exp $
4 ----------------------------------------------------------------------
5 LICENSE
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License (GPL)
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 To read the license please visit http://www.gnu.org/copyleft/gpl.html
18 ----------------------------------------------------------------------
19 Original Author of file: Benjamin Sonntag
20 Purpose of file: PHP Class that manage domain names installed on the server
21 ----------------------------------------------------------------------
22*/
23
24define('SLAVE_FLAG', "/var/run/alternc/refresh_slave");
25
26/**
27* Classe de gestion des domaines de l'hébergé.
28*
29* Cette classe permet de gérer les domaines / sous-domaines, redirections
30* dns et mx des domaines d'un membre hébergé.<br />
31* Copyleft {@link http://alternc.net/ AlternC Team}
32*
33* @copyright    AlternC-Team 2002-11-01 http://alternc.net/
34*
35*/
36class m_dom {
37
38  /** $domains : Cache des domaines du membre
39   * @access private
40   */
41  var $domains;
42
43  /** $dns : Liste des dns trouvés par la fonction whois
44   * @access private
45   */
46  var $dns;
47
48  /** Flag : a-t-on trouvé un sous-domaine Webmail pour ce domaine ?
49   * @access private
50   */
51  var $webmail;
52
53  /**
54   * Système de verrouillage du cron
55   * Ce fichier permet de verrouiller le cron en attendant la validation
56   * du domaine par update_domains.sh
57   * @access private
58   */
59  var $fic_lock_cron="/var/run/alternc/cron.lock";
60
61  /**
62   * Le cron a-t-il été bloqué ?
63   * Il faut appeler les fonctions privées lock et unlock entre les
64   * appels aux domaines.
65   * @access private
66   */
67  var $islocked=false;
68
69  var $type_local = "VHOST";
70  var $type_url = "URL";
71  var $type_ip = "IP";
72  var $type_webmail = "WEBMAIL";
73  var $type_ipv6 = "IPV6";
74  var $type_cname = "CNAME";
75  var $type_txt = "TXT";
76  var $type_defmx = "DEFMX";
77  var $type_defmx2 = "DEFMX2";
78
79  var $action_insert = "0";
80  var $action_update= "1";
81  var $action_delete = "2";
82
83  /* ----------------------------------------------------------------- */
84  /**
85   * Constructeur
86   */
87  function m_dom() {
88  }
89
90  /* ----------------------------------------------------------------- */
91  /**
92   * Quota name
93   */
94  function alternc_quota_names() {
95    return "dom";
96  }
97  /* ----------------------------------------------------------------- */
98  /**
99   * Retourne un tableau contenant les types de domaines
100   *
101   * @return array retourne un tableau indexé contenant la liste types de domaines
102   *  authorisé. Retourne FALSE si une erreur s'est produite.
103   */
104  function domains_type_lst() {
105    global $db,$err,$cuid;
106    $err->log("dom","domains_type_lst");
107    $db->query("select * from domaines_type order by advanced;");
108    $this->domains_type_lst=false;
109    while ($db->next_record()) {
110      $this->domains_type_lst[strtolower($db->Record["name"])] = $db->Record;
111    }
112    return $this->domains_type_lst;
113  }
114
115  function domains_type_enable_values() {
116    global $db,$err,$cuid;
117    $err->log("dom","domains_type_target_values");
118    $db->query("desc domaines_type;");
119    $r = array();
120    while ($db->next_record()) {
121      if ($db->f('Field') == 'enable') {
122        $tab = explode(",", substr($db->f('Type'), 5, -1));
123        foreach($tab as $t) { $r[]=substr($t,1,-1); }
124      }
125    }
126    return $r;
127  }
128
129  function domains_type_target_values($type=null) {
130    global $db,$err,$cuid;
131    $err->log("dom","domains_type_target_values");
132    if (is_null($type)) {
133      $db->query("desc domaines_type;");
134      $r = array();
135      while ($db->next_record()) {
136        if ($db->f('Field') == 'target') {
137          $tab = explode(",", substr($db->f('Type'), 5, -1));
138          foreach($tab as $t) { $r[]=substr($t,1,-1); }
139        }
140      }
141      return $r;
142    } else {
143      $db->query("select target from domaines_type where name='$type';");
144      if (! $db->next_record()) return false;
145      return $db->f('target');
146    }
147  }
148
149  function domains_type_regenerate($name) {
150    global $db,$err,$cuid; 
151    $name=mysql_real_escape_string($name);
152    $db->query("update sub_domaines set web_action='UPDATE' where lower(type) = lower('$name') ;");
153    $db->query("update domaines d, sub_domaines sd set d.dns_action = 'UPDATE' where lower(sd.type)=lower('$name');");
154    return true;
155  }
156
157  function domains_type_get($name) {
158    global $db,$err,$cuid; 
159    $name=mysql_real_escape_string($name);
160    $db->query("select * from domaines_type where name='$name' ;");
161    $db->next_record();
162    return $db->Record;
163  }
164
165  function domains_type_del($name) {
166    global $db,$err,$cuid;
167    $name=mysql_real_escape_string($name);
168    $db->query("delete domaines_type where name='$name';");
169    return true;
170  }
171
172  function domains_type_disable($id) {
173    global $db,$err,$cuid;
174    $id=intval($id);
175    $db->query("update domaines_type set enable=false where id=$id;");
176    return true;
177  }
178
179  function domains_type_enable($id) {
180    global $db,$err,$cuid;
181    $id=intval($id);
182    $db->query("update domaines_type set enable=true where id=$id;");
183    return true;
184  }
185
186  function domains_type_update($name, $description, $target, $entry, $compatibility, $enable, $only_dns, $need_dns,$advanced) {
187    global $err,$cuid,$db;
188    $id=intval($id);
189    $name=mysql_real_escape_string($name);
190    $description=mysql_real_escape_string($description);
191    $target=mysql_real_escape_string($target);
192    $entry=mysql_real_escape_string($entry);
193    $compatibility=mysql_real_escape_string($compatibility);
194    $enable=mysql_real_escape_string($enable);
195    $only_dns=intval($only_dns);
196    $need_dns=intval($need_dns);
197    $advanced=intval($advanced);
198    $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' where name='$name';");
199    return true;
200  }   
201
202  function sub_domain_change_status($domain,$sub,$type,$value,$status) {
203    global $db,$err,$cuid;
204    $err->log("dom","sub_domain_change_status");
205    $status=strtoupper($status);
206    if (! in_array($status,array('ENABLE', 'DISABLE'))) return false;
207
208    $db->query("update sub_domaines set enable='$status' where domaine='$domain' and sub='$sub' and lower(type)=lower('$type') and valeur='$value'");
209
210    return true;
211  } 
212
213  /* ----------------------------------------------------------------- */
214  /**
215   * Retourne un tableau contenant les domaines d'un membre.
216   *
217   * @return array retourne un tableau indexé contenant la liste des
218   *  domaines hébergés sur le compte courant. Retourne FALSE si une
219   *  erreur s'est produite.
220   */
221  function enum_domains() {
222    global $db,$err,$cuid;
223    $err->log("dom","enum_domains");
224    $db->query("select * from domaines where compte='$cuid' order by domaine asc;");
225    $this->domains=array();
226    if ($db->num_rows()>0) {
227      while ($db->next_record()) {
228      $this->domains[]=$db->f("domaine");
229      }
230    }
231    return $this->domains;
232  }
233
234  function del_domain_cancel($dom) {
235    global $db,$err,$classes,$cuid;
236    $err->log("dom","del_domaini_canl",$dom);
237    $dom=strtolower($dom);
238    $db->query("UPDATE sub_domaines SET web_action='UPDATE'  WHERE domaine='$dom';");
239    $db->query("UPDATE domaines SET dns_action='UPDATE'  WHERE domaine='$dom';");
240
241    # TODO : some work with domain sensitive classes
242
243    return true;
244  }
245
246  /* ----------------------------------------------------------------- */
247  /**
248   *  Efface un domaine du membre courant, et tous ses sous-domaines
249   *
250   * Cette fonction efface un domaine et tous ses sous-domaines, ainsi que
251   * les autres services attachés à celui-ci. Elle appelle donc les autres
252   * classe. Chaque classe peut déclarer une fonction del_dom qui sera
253   * appellée lors de la destruction d'un domaine.
254   *
255   * @param string $dom nom de domaine à effacer
256   * @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
257   */
258  function del_domain($dom) {
259    global $db,$err,$classes,$cuid;
260    $err->log("dom","del_domain",$dom);
261    $dom=strtolower($dom);
262    $db->query("SELECT * FROM domaines WHERE domaine='$dom';");
263    if ($db->num_rows()==0) {
264      $err->raise("dom",1,$dom);
265      return false;
266    }
267    $db->next_record();
268    if ($db->f("compte")!=$cuid) {
269      $err->raise("dom",2,$dom);
270      return false;
271    }
272    $db->query("UPDATE sub_domaines SET web_action='DELETE'  WHERE domaine='$dom';");
273    $db->query("UPDATE domaines SET dns_action='DELETE'  WHERE domaine='$dom';");
274
275    // DEPENDANCE :
276    // Lancement de del_dom sur les classes domain_sensitive :
277    // Declenchons les autres classes.
278    foreach($classes as $c) {
279      if (method_exists($GLOBALS[$c],"alternc_del_domain")) {
280          $GLOBALS[$c]->alternc_del_domain($dom);
281      }
282    }
283    foreach($classes as $c) {
284      if (method_exists($GLOBALS[$c],"alternc_del_mx_domain")) {
285          $GLOBALS[$c]->alternc_del_mx_domain($dom);
286      }
287    }
288    return true;
289  }
290
291  /* ----------------------------------------------------------------- */
292  /**
293   *  Installe un domaine sur le compte courant.
294   *
295   * <p>Si le domaine existe déjà ou est interdit, ou est celui du serveur,
296   * l'installation est refusée. Si l'hébergement DNS est demandé, la fonction
297   * checkhostallow vérifiera que le domaine peut être installé conformément
298   * aux demandes des super-admin.
299   * Si le dns n'est pas demandé, le domaine peut être installé s'il est en
300   * seconde main d'un tld (exemple : test.eu.org ou test.com, mais pas
301   * toto.test.org ou test.test.asso.fr)</p>
302   * <p>Chaque classe peut définir une fonction add_dom($dom) qui sera
303   * appellée lors de l'installation d'un nouveau domaine.</p>
304   *
305   * @param string $dom nom fqdn du domaine à installer
306   * @param integer $dns 1 ou 0 pour héberger le DNS du domaine ou pas.
307   * @param integer $noerase 1 ou 0 pour rendre le domaine inamovible ou non
308   * @param integer $force 1 ou 0, si 1, n'effectue pas les tests de DNS.
309   *  force ne devrait être utilisé que par le super-admin.
310   $ @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
311  */
312  function add_domain($domain,$dns,$noerase=0,$force=0,$isslave=0,$slavedom="") {
313    global $db,$err,$quota,$classes,$L_MX,$L_FQDN,$tld,$cuid,$bro;
314    $err->log("dom","add_domain",$domain);
315
316    // Locked ?
317    if (!$this->islocked) {
318      $err->raise("dom",3);
319      return false;
320    }
321    // Verifie que le domaine est rfc-compliant
322    $domain=strtolower($domain);
323    $t=checkfqdn($domain);
324    if ($t) {
325      $err->raise("dom",3+$t);
326      return false;
327    }
328    // Interdit les domaines clés (table forbidden_domains) sauf en cas FORCE
329    $db->query("select domain from forbidden_domains where domain='$domain'");
330    if ($db->num_rows() && !$force) {
331      $err->raise("dom",22);
332      return false;
333    }
334    if ($domain==$L_FQDN || $domain=="www.$L_FQDN") {
335      $err->raise("dom",18);
336      return false;
337    }
338    $db->query("SELECT compte FROM domaines WHERE domaine='$domain';");
339    if ($db->num_rows()) {
340      $err->raise("dom",8);
341      return false;
342    }
343    $db->query("SELECT compte FROM `sub_domaines` WHERE sub != \"\" AND concat( sub, \".\", domaine )='$domain' OR domaine='$domain';");
344    if ($db->num_rows()) {
345      $err->raise("dom",8);
346      return false;
347    }
348    $this->dns=$this->whois($domain);
349    if (!$force) {
350      $v=checkhostallow($domain,$this->dns);
351      if ($v==-1) {
352        $err->raise("dom",7);   // TLD interdit
353        return false;
354      }
355      if ($dns && $v==-2) {
356        $err->raise("dom",12);   // Domaine non trouvé dans le whois
357        return false;
358      }
359      if ($dns && $v==-3) {
360        $err->raise("dom",23);   // Domaine non trouvé dans le whois
361        return false;
362      }
363
364      if ($dns) $dns="1"; else $dns="0";
365
366      // mode 5 : force DNS to NO.
367      if ($tld[$v]==5) $dns=0;
368      // It must be a real domain (no subdomain)
369      if (!$dns) {
370         $v=checkhostallow_nodns($domain);
371         if ($v) {
372           $err->raise("dom",22);
373           return false;
374         }
375      }
376    }
377    // Check the quota :
378    if (!$quota->cancreate("dom")) {
379      $err->raise("dom",10);
380      return false;
381    }
382    if ($noerase) $noerase="1"; else $noerase="0";
383    $db->query("insert into domaines (compte,domaine,gesdns,gesmx,noerase,dns_action) values ('$cuid','$domain','$dns','1','$noerase','UPDATE');");
384
385    if ($isslave) {
386      $isslave=true;
387      $db->query("SELECT domaine FROM domaines WHERE compte='$cuid' AND domaine='$slavedom';");
388      $db->next_record();
389      if (!$db->Record["domaine"]) {
390        $err->raise("dom",1,$slavedom);
391        $isslave=false;
392      }
393      // Point to the master domain :
394      $this->set_sub_domain($domain, '',     $this->type_url, 'http://www.'.$slavedom);
395      $this->set_sub_domain($domain, 'www',  $this->type_url, 'http://www.'.$slavedom);
396      $this->set_sub_domain($domain, 'mail', $this->type_url, 'http://mail.'.$slavedom);     
397    }
398    if (!$isslave) {
399      // Creation du repertoire dans www
400      $dest_root = $bro->get_userid_root($cuid);
401      $domshort=str_replace("-","",str_replace(".","",$domain));
402     
403      if (! is_dir($dest_root . "/". $domshort)) {
404        mkdir($dest_root . "/". $domshort);
405      }
406     
407      // Creation des 3 sous-domaines par défaut : Vide, www et mail
408      $this->set_sub_domain($domain, '',     $this->type_url,     'http://www.'.$domain);
409      $this->set_sub_domain($domain, 'www',  $this->type_local,   '/'. $domshort);
410      $this->set_sub_domain($domain, 'mail', $this->type_webmail, '');
411    }
412
413    // DEPENDANCE :
414    // Lancement de add_dom sur les classes domain_sensitive :
415    // Declenchons les autres classes.   
416    foreach($classes as $c) {
417      if (method_exists($GLOBALS[$c],"alternc_add_domain")) {
418        $GLOBALS[$c]->alternc_add_domain($domain);
419      }
420    }
421    foreach($classes as $c) {
422      if (method_exists($GLOBALS[$c],"alternc_add_mx_domain")) {
423        $GLOBALS[$c]->alternc_add_mx_domain($domain);
424      }
425    }
426    if ($isslave) {
427      foreach($classes as $c) {
428        if (method_exists($GLOBALS[$c],"alternc_add_slave_domain")) {
429          $GLOBALS[$c]->alternc_add_slave_domain($domain,$slavedom);
430        }
431      } 
432    }
433    return true;
434  }
435
436  /* ----------------------------------------------------------------- */
437  /**
438   * Retourne les entrées DNS du domaine $domain issues du WHOIS.
439   *
440   * Cette fonction effectue un appel WHOIS($domain) sur Internet,
441   * et extrait du whois les serveurs DNS du domaine demandé. En fonction
442   * du TLD, on sait (ou pas) faire le whois correspondant.
443   * Actuellement, les tld suivants sont supportés :
444   * .com .net .org .be .info .ca .cx .fr .biz .name
445   *
446   * @param string $domain Domaine fqdn dont on souhaite les serveurs DNS
447   * @return array Retourne un tableau indexé avec les NOMS fqdn des dns
448   *   du domaine demandé. Retourne FALSE si une erreur s'est produite.
449   *
450   */
451  function whois($domain) {
452    global $db,$err;
453    $err->log("dom","whois",$domain);
454    // pour ajouter un nouveau TLD, utiliser le code ci-dessous.
455    //  echo "whois : $domain<br />";
456    preg_match("#.*\.([^\.]*)#",$domain,$out);
457    $ext=$out[1];
458    // pour ajouter un nouveau TLD, utiliser le code ci-dessous.
459    //  echo "ext: $ext<br />";
460
461    if (($fp=@fsockopen("whois.iana.org", 43))>0) {
462      fputs($fp, "$domain\r\n");
463      $found = false;
464      $state=0;
465      while (!feof($fp)) {
466        $ligne = fgets($fp,128);
467        if (preg_match('#^whois:#', $ligne)) { $serveur=preg_replace('/whois:\ */','',$ligne,1); }
468      }
469    }
470                $serveur=str_replace(array(" ","\n"),"",$serveur);
471
472    $egal="";
473    switch($ext) {
474    case "net":
475      $egal="=";
476      break;
477    case "name":
478      $egal="domain = ";
479      break;
480    }
481    // pour ajouter un nouveau TLD, utiliser le code ci-dessous.
482    //  echo "serveur : $serveur <br />";
483    if (($fp=@fsockopen($serveur, 43))>0) {
484      fputs($fp, "$egal$domain\r\n");
485      $found = false;
486      $state=0;
487      while (!feof($fp)) {
488  $ligne = fgets($fp,128);
489  // pour ajouter un nouveau TLD, utiliser le code ci-dessous.
490  //  echo "| $ligne<br />";
491  switch($ext) {
492  case "org":
493  case "com":
494  case "net":
495  case "info":
496  case "biz":
497  case "name":
498  case "cc":
499    if (preg_match("#Name Server:#", $ligne)) {
500      $found = true;
501      $tmp=strtolower(str_replace(chr(10), "",str_replace(chr(13),"",str_replace(" ","", str_replace("Name Server:","", $ligne)))));
502      if ($tmp)
503        $server[]=$tmp;
504    }
505    break;
506  case "cx":
507    $ligne = str_replace(chr(10), "",str_replace(chr(13),"",str_replace(" ","", $ligne)));
508    if ($ligne=="" && $state==1)
509      $state=2;
510    if ($state==1)
511      $server[]=strtolower($ligne);
512    if ($ligne=="Nameservers:" && $state==0) {
513      $state=1;
514      $found = true;
515    }
516    break;
517        case "eu":
518  case "be":
519          $ligne=preg_replace("/^ *([^ ]*) \(.*\)$/","\\1",trim($ligne));
520          if($found)
521             $tmp = trim($ligne);
522          if ($tmp)
523             $server[]=$tmp;
524          if ($ligne=="Nameservers:") {
525            $state=1;
526            $found=true;
527          }
528          break;
529    case "im":
530          if (preg_match('/Name Server:/', $ligne)) {
531            $found = true;
532            // weird regexp (trailing garbage after name server), but I could not make it work otherwise
533            $tmp = strtolower(preg_replace('/Name Server: ([^ ]+)\..$/',"\\1", $ligne));
534            $tmp = preg_replace('/[^-_a-z0-9\.]/', '', $tmp);
535            if ($tmp)
536              $server[]=$tmp;
537          }
538          break;
539    case "it":
540          if (preg_match("#nserver:#", $ligne)) {
541            $found=true;
542            $tmp=strtolower(preg_replace("/nserver:\s*[^ ]*\s*([^\s]*)$/","\\1", $ligne));
543            if ($tmp)
544              $server[]=$tmp;
545          }
546          break;
547  case "fr":
548  case "re":
549          if (preg_match("#nserver:#", $ligne)) {
550            $found=true;
551            $tmp=strtolower(preg_replace("#nserver:\s*([^\s]*)\s*.*$#","\\1", $ligne));
552            if ($tmp)
553              $server[]=$tmp;
554          }
555          break;
556  case "ca":
557  case "ws";
558    if (preg_match('#Name servers#', $ligne)) {
559          // found the server
560      $state = 1;
561    } elseif ($state) {
562      if (preg_match('#^[^%]#', $ligne) && $ligne = preg_replace('#[[:space:]]#', "", $ligne)) {
563      // first non-whitespace line is considered to be the nameservers themselves
564      $found = true;
565      $server[] = $ligne;
566    }
567    }
568    break;
569        case "coop":
570          if (preg_match('#Host Name:\s*([^\s]+)#', $ligne, $matches)) {
571            $found = true;
572            $server[] = $matches[1];
573          }
574  } // switch
575      } // while
576      fclose($fp);
577    } else {
578      $err->raise("dom",11);
579      return false;
580    }
581
582    if ($found) {
583      return $server;
584    } else {
585      $err->raise("dom",12);
586      return false;
587    }
588  } // whois
589
590  /* ----------------------------------------------------------------- */
591  /**
592   *  vérifie la presence d'un champs mx valide sur un serveur DNS
593   *
594  */
595 
596  function checkmx($domaine,$mx) {
597    //initialise variables
598    $mxhosts = array();
599   
600    //récupére les champs mx
601    if (!getmxrr($domaine,$mxhosts)) {
602      //aucune hôte mx spécifié
603      return 1;
604    }
605    else {
606      //vérifie qu'un des hôtes est bien sur alternc
607      $bolmx = 0;
608      //décompose les différents champ MX coté alternc
609      $arrlocalmx = split(",",$mx);
610      //parcours les différents champ MX retournés
611      foreach($mxhosts as $mxhost) {
612        foreach($arrlocalmx as $localmx) {
613          if ($mxhost==$localmx) {
614            $bolmx = 1;
615          }
616        }
617      }
618      //définition de l'erreur selon reponse du parcours de mxhosts
619      if ($bolmx == 0) {
620        //aucun des champs MX ne correspond au serveur
621        return 2;         
622      }
623      else {
624        //un champ mx correct a été trouvé
625        return 0;
626      }
627    }
628  } //checkmx
629
630
631  /* ----------------------------------------------------------------- */
632  /**
633   *  retourne TOUTES les infos d'un domaine
634   *
635   * @param string $dom Domaine dont on souhaite les informations
636   * @return array Retourne toutes les infos du domaine sous la forme d'un
637   * tableau associatif comme suit :<br /><pre>
638   *  $r["name"] =  Nom fqdn
639   *  $r["dns"]  =  Gestion du dns ou pas ?
640   *  $r["mx"]   =  Valeur du champs MX si "dns"=true
641   *  $r["mail"] =  Heberge-t-on le mail ou pas ? (si "dns"=false)
642   *  $r["nsub"] =  Nombre de sous-domaines
643   *  $r["sub"]  =  tableau associatif des sous-domaines
644   *  $r["sub"][0-(nsub-1)]["name"] = nom du sous-domaine (NON-complet)
645   *  $r["sub"][0-(nsub-1)]["dest"] = Destination (url, ip, local ...)
646   *  $r["sub"][0-(nsub-1)]["type"] = Type (0-n) de la redirection.
647   *  </pre>
648   *  Retourne FALSE si une erreur s'est produite.
649   *
650   */
651  function get_domain_all($dom) {
652    global $db,$err,$cuid;
653    $err->log("dom","get_domain_all",$dom);
654    // Locked ?
655    if (!$this->islocked) {
656      $err->raise("dom",3);
657      return false;
658    }
659    $t=checkfqdn($dom);
660    if ($t) {
661      $err->raise("dom",3+$t);
662      return false;
663    }
664    $r["name"]=$dom;
665    $db->query("select * from domaines where compte='$cuid' and domaine='$dom'");
666    if ($db->num_rows()==0) {
667      $err->raise("dom",1,$dom);
668      return false;
669    }
670    $db->next_record();
671    $r["dns"]=$db->Record["gesdns"];
672    $r["dns_action"]=$db->Record["dns_action"];
673    $r["dns_result"]=$db->Record["dns_result"];
674    $r["mail"]=$db->Record["gesmx"];
675    $r["mx"]=$db->Record["mx"];
676    $r['noerase']=$db->Record['noerase'];
677    $db->free();
678    $db->query("select count(*) as cnt from sub_domaines where compte='$cuid' and domaine='$dom'");
679    $db->next_record();
680    $r["nsub"]=$db->Record["cnt"];
681    $db->free();
682    $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");
683    // Pas de webmail, on le cochera si on le trouve.
684    $this->webmail=0;
685    for($i=0;$i<$r["nsub"];$i++) {
686      $db->next_record();
687      $r["sub"][$i]=array();
688      $r["sub"][$i]["name"]=$db->Record["sub"];
689      $r["sub"][$i]["dest"]=$db->Record["valeur"];
690      $r["sub"][$i]["type"]=$db->Record["type"];
691      $r["sub"][$i]["enable"]=$db->Record["enable"];
692      $r["sub"][$i]["type_desc"]=$db->Record["type_desc"];
693      $r["sub"][$i]["only_dns"]=$db->Record["only_dns"];
694      $r["sub"][$i]["web_action"]=$db->Record["web_action"];
695/*
696      if ($db->Record["type"]==3) { // Webmail
697  $this->webmail=1;
698  $r["sub"][$i]["dest"]=_("Webmail access");
699      }
700*/
701    }
702    $db->free();
703    return $r;
704  } // get_domain_all
705
706
707  /* ----------------------------------------------------------------- */
708  /**
709   * Retourne TOUTES les infos d'un sous domaine du compte courant.
710   *
711   * @param string $dom Domaine fqdn concerné
712   * @param string $sub Sous-domaine dont on souhaite les informations
713   * @return arrray Retourne un tableau associatif contenant les
714   *  informations du sous-domaine demandé.<pre>
715   *  $r["name"]= nom du sous-domaine (NON-complet)
716   *  $r["dest"]= Destination (url, ip, local ...)
717   *  </pre>
718   *  $r["type"]= Type (0-n) de la redirection.
719   *  Retourne FALSE si une erreur s'est produite.
720   */
721  function get_sub_domain_all($dom,$sub, $type="", $value='') {
722    global $db,$err,$cuid;
723    $err->log("dom","get_sub_domain_all",$dom."/".$sub);
724    // Locked ?
725    if (!$this->islocked) {
726      $err->raise("dom",3);
727      return false;
728    }
729    $t=checkfqdn($dom);
730    if ($t) {
731      $err->raise("dom",3+$t);
732      return false;
733    }
734/*
735    if ( ! empty($value)) {
736        $type = " and valeur=\"".mysql_real_escape_string($value)."\"";
737    }
738    if ( ! empty($type)) {
739        $type = " and type=\"".mysql_real_escape_string($type)."\"";
740    }
741*/
742    $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 sub='$sub' and ( length('$type')=0 or type='$type') and (length('$value')=0 or '$value'=valeur) and upper(dt.name)=upper(sd.type);");
743    if ($db->num_rows()==0) {
744      $err->raise("dom",14);
745      return false;
746    }
747    $db->next_record();
748    $r=array();
749    $r["name"]=$db->Record["sub"];
750    $r["dest"]=$db->Record["valeur"];
751    $r["enable"]=$db->Record["enable"];
752    $r["type_desc"]=$db->Record["type_desc"];
753    $r["only_dns"]=$db->Record["only_dns"];
754    $r["web_action"]=$db->Record["web_action"];
755    $db->free();
756    return $r;
757  } // get_sub_domain_all
758
759
760  function check_type_value($type, $value) {
761    global $db,$err,$cuid;
762
763    // check the type we can have in domaines_type.target
764
765    switch ($this->domains_type_target_values($type)) {
766      case 'NONE':
767        if (empty($value) or is_null($value)) {return true;}
768        break;
769      case 'URL': 
770        if ( $value == strval($value)) {return true;}
771        break;
772      case 'DIRECTORY': 
773        if (substr($value,0,1)!="/") {
774          $value="/".$value;
775        }
776        if (!checkuserpath($value)) {
777          $err->raise("dom",21);
778        return false;
779        }
780        return true;
781        break;
782      case 'IP': 
783        if (checkip($value)) {return true;}
784        break;
785      case 'IPV6': 
786        if (checkipv6($value)) {return true;}
787        break;
788      case 'DOMAIN': 
789        if (checkcname($value)) {return true;}
790        break;
791      case 'TXT':
792        if ( $value == strval($value)) {return true;}
793        break;
794      default:
795        return false;
796        break;
797    }
798    return false;
799  } //check_type_value
800
801
802  function can_create_subdomain($dom,$sub,$type,$type_old='', $value_old='') {
803    global $db,$err,$cuid;
804    $err->log("dom","can_create_subdomain",$dom."/".$sub);
805
806    # Get the compatibility list for this domain type
807    $db->query("select upper(compatibility) as compatibility from domaines_type where upper(name)=upper('$type');");
808    if (!$db->next_record()) return false;
809    $compatibility_lst = explode(",",$db->f('compatibility'));
810
811    # Get the list of type of subdomains already here who have the same name
812    $db->query("select * from sub_domaines where sub='$sub' and domaine='$dom' and not (type='$type_old' and valeur='$value_old') and web_action != 'DELETE'");
813    #$db->query("select * from sub_domaines where sub='$sub' and domaine='$dom';");
814    while ($db->next_record()) {
815      # And if there is a domain with a incompatible type, return false
816      if (! in_array(strtoupper($db->f('type')),$compatibility_lst)) return false;
817    }
818   
819    # All is right, go ! Create ur domain !
820    return true;
821  }
822
823  //  /* ----------------------------------------------------------------- */
824  /**
825   * Modifier les information du sous-domaine demandé.
826   *
827   * <b>Note</b> : si le sous-domaine $sub.$dom n'existe pas, il est créé.<br />
828   * <b>Note : TODO</b> : vérification de concordance de $dest<br />
829   *
830   * @param string $dom Domaine dont on souhaite modifier/ajouter un sous domaine
831   * @param string $subk Sous domaine à modifier / créer
832   * @param integer $type Type de sous-domaine (local, ip, url ...)
833   * @param string $action Action : vaut "add" ou "edit" selon que l'on
834   *  Crée (add) ou Modifie (edit) le sous-domaine
835   * @param string $dest Destination du sous-domaine, dépend de la valeur
836   *  de $type (url, ip, dossier...)
837   * @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
838   */
839   // TODO : j'ai viré le type action, valider que plus personne ne l'utilise (quatrieme argument)
840  function set_sub_domain($dom,$sub,$type,$dest, $type_old=null,$sub_old=null,$value_old=null) {
841    global $db,$err,$cuid;
842    $err->log("dom","set_sub_domain",$dom."/".$sub."/".$type."/".$dest);
843    // Locked ?
844    if (!$this->islocked) {
845      $err->raise("dom",3);
846      return false;
847    }
848    $dest=trim($dest);
849    $sub=trim(trim($sub),".");
850    $dom=strtolower($dom);
851    $sub=strtolower($sub);
852
853    //    if (!(($sub == '*') || ($sub=="") || (preg_match('/([a-z0-9][\.\-a-z0-9]*)?[a-z0-9]/', $sub)))) {
854    $fqdn=checkfqdn($sub);
855    // Special cases : * (all subdomains at once) and '' empty subdomain are allowed.
856    if (($sub != '*' && $sub!='') && !($fqdn==0 || $fqdn==4)) {
857      $err->raise("dom",24);
858      return false;
859    }
860
861    if (! $this->check_type_value($type,$dest)) {
862      # TODO have a real err code
863      $err->raise("dom",667);
864      return false;
865    }
866
867    // On a épuré $dir des problèmes eventuels ... On est en DESSOUS du dossier de l'utilisateur.
868    if ($t=checkfqdn($dom)) {
869      $err->raise("dom",3+$t);
870      return false;
871    }
872
873    if (! $this->can_create_subdomain($dom,$sub,$type,$type_old,$value_old)) {
874      # TODO have a real error code
875      $err->raise("dom", 654);
876      return false;
877    }
878
879    if (! is_null($type_old )) { // It's not a creation, it's an edit. Delete the old one
880      $db->query("update sub_domaines set web_action='DELETE' where domaine='$dom' and sub='$sub' and upper(type)=upper('$type_old') and valeur='$value_old';");
881    }
882
883    // Re-create the one we want
884    if (! $db->query("insert into sub_domaines (compte,domaine,sub,valeur,type,web_action) values ('$cuid','$dom','$sub','$dest','$type','UPDATE');") ) {
885      echo "query failed: ".$db->Error;
886      return false;
887    }
888
889    // Tell to update the DNS file
890    $db->query("update domaines set dns_action='UPDATE' where domaine='$dom';");
891
892    return true;
893  } // set_sub_domain
894
895
896  /* ----------------------------------------------------------------- */
897  /**
898   *  Supprime le sous-domaine demandé
899   *
900   * @param string $dom Domaine dont on souhaite supprimer un sous-domaine
901   * @param string $sub Sous-domaine que l'on souhaite supprimer
902   * @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
903   *
904   */
905  function del_sub_domain($dom,$sub,$type,$value='') {
906    global $db,$err,$cuid;
907    $err->log("dom","del_sub_domain",$dom."/".$sub);
908    // Locked ?
909    if (!$this->islocked) {
910      $err->raise("dom",3);
911      return false;
912    }
913    $t=checkfqdn($dom);
914    if ($t) {
915      $err->raise("dom",3+$t);
916      return false;
917    }
918    if (!$r=$this->get_sub_domain_all($dom,$sub,$type)) {
919      // Le sous-domaine n'existe pas, erreur
920      $err->raise("dom",14);
921      return false;
922    } else {
923      // OK, on valide :
924      $db->query("update sub_domaines set web_action='DELETE' where domaine='$dom' and sub='$sub' and type='$type' and ( length('$value')=0 or valeur='$value') ");
925      $db->query("update domaines set dns_action='UPDATE' where domaine='$dom';");
926    }
927    return true;
928  } // del_sub_domain
929
930  /* ----------------------------------------------------------------- */
931  /**
932   * Modifie les information du domaine précisé.
933   *
934   * @param string $dom Domaine du compte courant que l'on souhaite modifier
935   * @param integer $dns Vaut 1 ou 0 pour héberger ou pas le DNS du domaine
936   * @param integer $gesmx Héberge-t-on le emails du domaines sur ce serveur ?
937   * @param boolean $force Faut-il passer les checks DNS ou MX ? (admin only)
938   * @return boolean appelle $mail->add_dom ou $ma->del_dom si besoin, en
939   *  fonction du champs MX. Retourne FALSE si une erreur s'est produite,
940   *  TRUE sinon.
941   *
942   */
943  function edit_domain($dom,$dns,$gesmx,$force=0) {
944    global $db,$err,$L_MX,$classes,$cuid;
945    $err->log("dom","edit_domain",$dom."/".$dns."/".$gesmx);
946    // Locked ?
947    if (!$this->islocked && !$force) {
948      $err->raise("dom",3);
949      return false;
950    }
951    if ($dns == 1 && !$force) {
952      $this->dns=$this->whois($dom);
953      $v=checkhostallow($dom,$this->dns);
954      if ($v==-1) {
955        $err->raise("dom",7);   // TLD interdit
956        return false;
957      }
958      if ($dns && $v==-2) {
959        $err->raise("dom",12);  // Domaine non trouvé dans le whois
960        return false;
961      }
962      if ($dns && $v==-3) {
963        $err->raise("dom",23);  // Domaine non trouvé dans le whois
964        return false;
965      }
966    }
967    $t=checkfqdn($dom);
968    if ($t) {
969      $err->raise("dom",3+$t);
970      return false;
971    }
972    if (!$r=$this->get_domain_all($dom)) {
973      // Le domaine n'existe pas, Failure
974      $err->raise("dom",4,$dom);
975      return false;
976    }
977    if ($dns!="1") $dns="0";
978    // On vérifie que des modifications ont bien eu lieu :)
979    if ($r["dns"]==$dns && $r["mail"]==$gesmx) {
980      $err->raise("dom",15);
981      return false;
982    }
983     
984    //si gestion mx uniquement, vérification du dns externe
985    if ($dns=="0" && $gesmx=="1" && !$force) {
986      $vmx = $this->checkmx($dom,$mx);
987      if ($vmx == 1) {
988        // Aucun champ mx de spécifié sur le dns
989        $err->raise("dom",25);
990        return false;
991      }
992     
993      if ($vmx == 2) {
994        // Serveur non spécifié parmi les champx mx
995        $err->raise("dom",25);
996        return false;
997      }
998    }
999     
1000    // OK, des modifs ont été faites, on valide :
1001    // DEPENDANCE :
1002    if ($gesmx && !$r["mail"]) { // on a associé le MX : on cree donc l'entree dans MySQL
1003      // Lancement de add_dom sur les classes domain_sensitive :
1004      foreach($classes as $c) {
1005        if (method_exists($GLOBALS[$c],"alternc_add_mx_domain")) {
1006          $GLOBALS[$c]->alternc_add_mx_domain($dom);
1007        }
1008      }
1009    }
1010   
1011    if (!$gesmx && $r["mail"]) { // on a dissocié le MX : on détruit donc l'entree dans LDAP
1012      // Lancement de del_dom sur les classes domain_sensitive :
1013      foreach($classes as $c) {
1014        if (method_exists($GLOBALS[$c],"alternc_del_mx_domain")) {
1015          $GLOBALS[$c]->alternc_del_mx_domain($dom);
1016        }
1017      }
1018    }
1019   
1020    $db->query("UPDATE domaines SET gesdns='$dns', gesmx='$gesmx' WHERE domaine='$dom'");
1021    $db->query("UPDATE domaines set dns_action='UPDATE' where domaine='$dom';");
1022   
1023    return true;
1024  } // edit_domain
1025 
1026
1027
1028  /****************************/
1029  /*  Slave dns ip managment  */
1030  /****************************/
1031  /* ----------------------------------------------------------------- */
1032  /**
1033   * Return the list of ip addresses and classes that are allowed access to domain list
1034   * through AXFR Transfers from the bind server.
1035   */
1036  function enum_slave_ip() {
1037  global $db,$err;
1038  $db->query("SELECT * FROM slaveip;");
1039  if (!$db->next_record()) {
1040    return false;
1041  }
1042  do {
1043    $res[]=$db->Record;
1044  } while ($db->next_record());
1045  return $res;
1046  }
1047
1048  /* ----------------------------------------------------------------- */
1049  /**
1050   * Add an ip address (or a ip class) to the list of allowed slave ip access list.
1051   */
1052  function add_slave_ip($ip,$class="32") {
1053  global $db,$err;
1054  if (!checkip($ip)) {
1055    $err->raise("dom",19);
1056    return false;
1057  }
1058  $class=intval($class);
1059  if ($class<8 || $class>32) $class=32;
1060  $db->query("SELECT * FROM slaveip WHERE ip='$ip' AND class='$class';");
1061  if ($db->next_record()) {
1062    $err->raise("err",22);
1063    return false;
1064  }
1065  $db->query("INSERT INTO slaveip (ip,class) VALUES ('$ip','$class');");
1066  $f=fopen(SLAVE_FLAG,"w");
1067  fputs($f,"yopla");
1068  fclose($f); 
1069  return true;
1070  }
1071
1072  /* ----------------------------------------------------------------- */
1073  /**
1074   * Remove an ip address (or a ip class) from the list of allowed slave ip access list.
1075   */
1076  function del_slave_ip($ip) {
1077  global $db,$err;
1078  if (!checkip($ip)) {
1079    $err->raise("dom",19);
1080    return false;
1081  }
1082  $db->query("DELETE FROM slaveip WHERE ip='$ip'");
1083  $f=fopen(SLAVE_FLAG,"w");
1084  fputs($f,"yopla");
1085  fclose($f); 
1086  return true;
1087  }
1088
1089
1090
1091  /* ----------------------------------------------------------------- */
1092  /**
1093   * Check for a slave account
1094   */
1095  function check_slave_account($login,$pass) {
1096  global $db,$err;
1097  $db->query("SELECT * FROM slaveaccount WHERE login='$login' AND pass='$pass';");
1098  if ($db->next_record()) { 
1099    return true;
1100  }
1101  return false;
1102  }
1103
1104  /* ----------------------------------------------------------------- */
1105  /**
1106   * Out (echo) the complete hosted domain list :
1107   */
1108  function echo_domain_list() {
1109  global $db,$err;
1110  $db->query("SELECT domaine FROM domaines WHERE gesdns=1 ORDER BY domaine");
1111  while ($db->next_record()) {
1112    echo $db->f("domaine")."\n";
1113  }
1114  return true;
1115  }
1116
1117
1118  /* ----------------------------------------------------------------- */
1119  /**
1120   * Returns the complete hosted domain list :
1121   */
1122  function get_domain_list($uid=-1) {
1123  global $db,$err;
1124  $uid=intval($uid);
1125  $res=array();
1126  if ($uid!=-1) {
1127    $sql=" AND compte='$uid' ";
1128  }
1129  $db->query("SELECT domaine FROM domaines WHERE gesdns=1 $sql ORDER BY domaine");
1130  while ($db->next_record()) {
1131    $res[]=$db->f("domaine");
1132  }
1133  return $res;
1134  }
1135
1136
1137  /* ----------------------------------------------------------------- */
1138  /**
1139   * Return the list of allowed slave accounts
1140   */
1141  function enum_slave_account() {
1142  global $db,$err;
1143  $db->query("SELECT * FROM slaveaccount;");
1144  $res=array();
1145  while ($db->next_record()) {
1146    $res[]=$db->Record;
1147  }
1148  if (!count($res)) return false;
1149  return $res;
1150  }
1151
1152  /* ----------------------------------------------------------------- */
1153  /**
1154   * Add a slave account that will be allowed to access the domain list
1155   */
1156  function add_slave_account($login,$pass) {
1157  global $db,$err;
1158  $db->query("SELECT * FROM slaveaccount WHERE login='$login'");
1159  if ($db->next_record()) {
1160    $err->raise("err",23);
1161    return false;
1162  }
1163  $db->query("INSERT INTO slaveaccount (login,pass) VALUES ('$login','$pass')");
1164  return true;
1165  }
1166
1167  /* ----------------------------------------------------------------- */
1168  /**
1169   * Remove a slave account
1170   */
1171  function del_slave_account($login) {
1172  global $db,$err;
1173  $db->query("DELETE FROM slaveaccount WHERE login='$login'");
1174  return true;
1175  }
1176
1177  /*************/
1178  /*  Private  */
1179  /*************/
1180
1181
1182  /* ----------------------------------------------------------------- */
1183  /**
1184   * Lock tente de verrouiller le fichier lock du cron. Si tout va bien (toujours?)
1185   * retourne True, sinon retourne False
1186   * NOTE : le systeme de lock est asymétrique, si on a un fichier CRONLOCK, on
1187   * attends (que le cron ait fini son execution).
1188   * @access private
1189   */
1190  function lock() {
1191    global $db,$err;
1192    $err->log("dom","lock");
1193    if ($this->islocked) {
1194      $err->raise("dom",17);
1195    }
1196    while (file_exists($this->fic_lock_cron)) {
1197      sleep(2);
1198    }
1199    $this->islocked=true;
1200    return true;
1201  }
1202
1203  /* ----------------------------------------------------------------- */
1204  /**
1205   * unlock déverrouille le fichier lock du cron. Si tout va bien (toujours?)
1206   * retourne True, sinon retourne False
1207   * NOTE : actuellement, vu le système de lock asymetrique, on ne fait rien ;)
1208   * @access private
1209   */
1210  function unlock() {
1211    global $db,$err;
1212    $err->log("dom","unlock");
1213    if (!$this->islocked) {
1214      $err->raise("dom",3);
1215    }
1216    $this->islocked=false;
1217    return true;
1218  }
1219
1220
1221  /* ----------------------------------------------------------------- */
1222  /**
1223   * Declare that a domain's emails are hosted in this server :
1224   * This adds 2 MX entries in this domain (if required)
1225   */
1226  function alternc_add_mx_domain($domain) {
1227    global $err;
1228    $err->log("dom","alternc_add_mx_domain");
1229    $this->set_sub_domain($domain, '', $this->type_defmx, '');
1230    if (! empty($GLOBALS['L_DEFAULT_SECONDARY_MX'])) {
1231      $this->set_sub_domain($domain, '', $this->type_defmx2, '');
1232    }
1233    return true;
1234  }
1235
1236
1237  /* ----------------------------------------------------------------- */
1238  /**
1239   * Efface un compte (tous ses domaines)
1240   */
1241  function alternc_del_member() {
1242    global $err;
1243    $err->log("dom","alternc_del_member");
1244    $li=$this->enum_domains();
1245    foreach($li as $dom) {
1246      $this->del_domain($dom);
1247    }
1248    return true;
1249  }
1250
1251
1252  /* ----------------------------------------------------------------- */
1253  /**
1254   * Returns the used quota for the $name service for the current user.
1255   * @param $name string name of the quota
1256   * @return integer the number of service used or false if an error occured
1257   * @access private
1258   */
1259  function alternc_get_quota($name) {
1260    global $db,$err,$cuid;
1261    if ($name=="dom") {
1262      $err->log("dom","get_quota");
1263      $db->query("SELECT COUNT(*) AS cnt FROM domaines WHERE compte='$cuid'");
1264      $db->next_record();
1265      return $db->f("cnt");
1266    } else return false;
1267  }
1268
1269
1270  /* ----------------------------------------------------------------- */
1271  /**
1272   * Exporte toutes les informations domaine du compte.
1273   * @access private
1274   * EXPERIMENTAL 'sid' function ;)
1275   */
1276  function alternc_export() {
1277    global $db,$err;
1278    $err->log("dom","export");
1279    $this->enum_domains();
1280    $str="<dom>\n";
1281    foreach ($this->domains as $d) {
1282      $str.="  <domain>\n    <name>".xml_entities($d)."</name>\n";
1283      $s=$this->get_domain_all($d);
1284      $str.="    <hasdns>".xml_entities($s[dns])."</hasdns>\n";
1285      $str.="    <hasmx>".xml_entities($s[mx])."</hasmx>\n";
1286      $str.="    <mx>".xml_entities($s[mail])."</mx>\n";
1287      if (is_array($s[sub])) {
1288        foreach ($s[sub] as $sub) {
1289          $str.="    <subdomain>";
1290          $str.="<name>".xml_entities($sub[name])."</name>";
1291          $str.="<dest>".xml_entities($sub[dest])."</dest>";
1292          $str.="<type>".xml_entities($sub[type])."</type>";
1293          $str.="</subdomain>\n";
1294        }
1295      }
1296      $str.="  </domain>\n";
1297    }
1298    $str.="</dom>\n";
1299    return $str;
1300  }
1301
1302
1303} /* Class m_domains */
1304
1305?>
Note: See TracBrowser for help on using the repository browser.