Code

Replaced in_array calls with in_array_strict
[gosa.git] / gosa-plugins / dns / admin / systems / services / dns / class_servDNSeditZoneEntries.inc
1 <?php
3 class servDNSeditZoneEntries extends plugin
4 {
5     /* attribute list for save action */
6     var $ignore_account     = TRUE;
7     var $attributes         = array();
8     var $objectclasses      = array("whatever");
10     var $Devices            = array();
12     var $zoneName           = "";   // ZoneName of currently edited Zone
13     var $reverseName        = "";   // ReverseZone of the currently edited Zone
15     var $RecordTypes        = array();  // Possible record type.
16     var $acl                = "";
17     var $disableDialog      = false; // Dialog will be disabled, if this zone is new 
20     function servDNSeditZoneEntries (&$config,$dn, &$zoneObject)
21     {
22         plugin::plugin ($config, $dn);
24         /* Initialise class
25          */
26         $this->RecordTypes  = DNS::getDnsRecordTypes();
27         $this->dn           = "zoneName=".$zoneObject['InitialzoneName'].",".$dn; 
28         $this->zoneName     = $zoneObject['InitialzoneName'];
29         $this->reverseName  = $zoneObject['InitialReverseZone'];
31         /* Remove nSRecord from listed types */
32         if(isset($this->RecordTypes['nSRecord'])){
33             unset($this->RecordTypes['nSRecord']);
34         }
35         /* Remove nSRecord from listed types */
36         if(isset($this->RecordTypes['pTRRecord'])){
37             unset($this->RecordTypes['pTRRecord']);
38         }
40         /* Get ldap connection 
41          */
42         $ldap = $this->config->get_ldap_link();
43         $ldap->cd($this->config->current['BASE']);
45         /* Get zone content
46          */
47         $ldap->ls("(&(objectClass=dNSZone)(!(relativeDomainName=@)))",$this->dn,array("relativeDomainName"));
49         while($attrs = $ldap->fetch()){
50             $this->Devices[$attrs['relativeDomainName'][0]] = DNS::getDNSHostEntries($config,$attrs['relativeDomainName'][0],true);
51             $this->Devices[$attrs['relativeDomainName'][0]]['OrigCn'] = $attrs['relativeDomainName'][0];
52         }
54         $ldap->cat($this->dn,array("objectClass"));
56         $this->disableDialog = true;
57         if(count($this->Devices)|| $ldap->count()){
58             $this->disableDialog = false;
59         }
60     }
62     function execute()
63     {
64         plugin::execute();
66         /* Fill templating stuff */
67         $smarty= get_smarty();
68         $display= "";
70         $table = "";
71         foreach($this->Devices as $key => $dev){
72             $table .= $this->generateRecordConfigurationRow($key);
73         }
75         $smarty->assign("acl",$this->acl);
76         $smarty->assign("disableDialog",$this->disableDialog);
77         $smarty->assign("table",$table);;
78         $display.= $smarty->fetch(get_template_path('servDNSeditZoneEntries.tpl', TRUE, dirname(__FILE__)));
79         return($display);
80     }
83     function save_object()
84     {
85         /* Check posts for operations ...  
86          */
87         $once = true;
88         $ptr_updates = array();
89         if(!preg_match("/w/",$this->acl)) return;
91         foreach($_POST as $name => $value){
93             /* Extract informations out of post name 
94              */
95             $tmp    = preg_replace("/^[^_]*_/","\\1",$name);
96             $tmp2   = explode("|",postDecode($tmp));      
98             /* Add new host entry
99              */
100             if((preg_match("/^UserRecord_?/",$name)) && ($once)){
101                 $once = false;
102                 $entry = DNS::getDNSHostEntries($this->config,"",true);     
103                 $entry['exists']    = true;
104                 $entry['zoneName']  = strtoupper($this->attrs['cn'][0])."/".$this->zoneName; 
105                 $entry['RECORDS'][] = array("type" => "aRecord" , "value"=>"");
106                 $this->Devices[_("New entry")] = $entry;
107             }
109             if(count($tmp2) != 2) continue;
111             $Name     = $tmp2[0];
112             $RecordID = $tmp2[1];
114             /* Add new REcord
115              */
116             if((preg_match("/^AddRecord_/",$name)) && ($once)){
117                 $once = false;
118                 $this->Devices[$Name]['RECORDS'][] = $this->Devices[$Name]['RECORDS'][$RecordID];
119             }
121             /* Remove record from given dn
122              */
123             if((preg_match("/^RemoveRecord_/",$name)) && ($once)){
124                 $once   = false;
125                 if(isset($this->Devices[$Name]['RECORDS'][$RecordID])){
126                     unset($this->Devices[$Name]['RECORDS'][$RecordID]);
127                 }
129                 /* Check if there is at least one visible record. Else remove complete entry */
130                 $visible = false;
131                 foreach($this->Devices[$Name]['RECORDS'] as $rec){
132                     if(in_array_strict($rec['type'],$this->RecordTypes)){
133                         $visible = true;  
134                         break;
135                     }
136                 }
137                 if(!$visible && isset($this->Devices[$Name]['RECORDS'])){
138                     $this->Devices[$Name]['RECORDS'] = array();
139                 }
140             }
141         }
143         /* Possible attributes posted 
144          */
145         foreach($_POST as $name => $value){
147             $value = get_post($name);
149             /* Extract informations out of post name 
150              */
151             $tmp    = preg_replace("/^[^_]*_/","\\1",$name);
152             $tmp2   = explode("|",postDecode($tmp));      
154             if(count($tmp2) != 2) continue;
156             $Name     = $tmp2[0];
157             $RecordID = $tmp2[1];
159             /* Check for value change 
160              */          
161             if(preg_match("/ValueSelection_/",$name)){
162                 if(isset($this->Devices[$Name]['RECORDS'][$RecordID])){
164                     /* Update value */ 
165                     $old = $this->Devices[$Name]['RECORDS'][$RecordID]['value'];
166                     $this->Devices[$Name]['RECORDS'][$RecordID]['value'] = get_post($name);
168                     /* Handle pTRRecord */
169                     if(!isset($ptr_updates[$Name]) && $this->Devices[$Name]['RECORDS'][$RecordID]['type'] == "aRecord"){
171                         $found = false;
172                         $ip = $value;
173                         $match = preg_replace("/^[^\/]*+\//","",$this->reverseName);
174                         $ip = preg_replace("/^".preg_quote($match)."/","",$ip);
175                         $ip = preg_replace("/^\./","",$ip);
177                         foreach($this->Devices[$Name]['RECORDS'] as $key => $dev){
178                             if($dev['type'] == "pTRRecord"){
179                                 $ptr_updates[$Name] = $Name;
180                                 $this->Devices[$Name]['RECORDS'][$key]['value'] = $ip;
181                                 $found = true;
182                                 break;
183                             }
184                         }
185                         if(!$found){
186                             $dev = array('type'=> 'pTRRecord', 'value' => $ip);
187                             $this->Devices[$Name]['RECORDS'][] = $dev;
188                         }
189                     }
190                 }
191             }
193             /* record type changed
194              */        
195             if(preg_match("/^RecordTypeSelection_/",$name)){
196                 if(isset($this->Devices[$Name]['RECORDS'][$RecordID])){
197                     $this->Devices[$Name]['RECORDS'][$RecordID]['type'] = $value;
198                 }  
199             }   
200         }
202         /* check for renamed entries 
203          */ 
204         foreach($_POST as $name => $value){
206         
207             $value = get_post($name);
209             /* Extract informations out of post name 
210              */
211             $tmp    = preg_replace("/^[^_]*_/","\\1",$name);
212             $tmp2   = explode("|",postDecode($tmp));      
214             if(count($tmp2) != 2) continue;
216             $Name     = $tmp2[0];
217             $RecordID = $tmp2[1];
219             /* Host renamed
220              */
221             if(preg_match("/RenameHost_/",$name)){
222                 if((isset($this->Devices[$Name])) && ($Name != $value)){
224                     if(isset($this->Devices[$value])){
225                         msg_dialog::display(_("Error"), sprintf(_("Cannot rename '%s' to '%s'. Name is already in use!"), $Name, $value), ERROR_DIALOG);
226                     }else{
227                         $this->Devices[$value] = $this->Devices[$Name];
228                         unset($this->Devices[$Name]);
229                     }
230                 }
231             }
232         }
233     }
236     /*  check something 
237      */
238     function check()
239     {
240         /* Call common method to give check the hook */
241         $message= plugin::check();
243         if(!preg_match("/w/",$this->acl)) return($message);
245         $ldap = $this->config->get_ldap_link();
246         $ldap->cd($this->config->current['BASE']);
248         $names = array();
250         foreach($this->Devices as $DevName => $device){
252             /* Don't need to check empty values ... */
253             if(!count($device['RECORDS'])) continue;
255             /* Checking entry name
256              */
257             if(!preg_match("/^[a-z0-9_\.-]+$/i", $DevName) || (empty($DevName))){
258                 $message[] = msgPool::invalid(_("Name"),$DevName,"/[a-z0-9_\.-]/i");
259             }      
261             /* Renaming check for existing devices 
262              */
263             if(isset($device['OrigCn'])  && ($DevName != $device['OrigCn'] )){
264                 $ldap->cd($this->config->current['BASE']);
265                 $ldap->search("(relativeDomainName=".$DevName.")",array("relativeDomainName"));
266                 if($ldap->count()){
267                     $message[] = sprintf(_("Cannot rename '%s' to '%s'. Entry is already in use."),$device['OrigCn'],$DevName);
268                 }
269             }elseif(!isset($device['OrigCn'])){
270                 $ldap->cd($this->config->current['BASE']);
271                 $ldap->search("(relativeDomainName=".$DevName.")",array("relativeDomainName"));
272                 if($ldap->count()){
273                     $message[] = sprintf(_("Cannot create '%s'. Entry is already in use."),$DevName);
274                 }
275             }
277             /* Check names 
278              */
279             if(!isset($names[$DevName])){
280                 $names[$DevName] = "";
281             }else{
282                 $message[] = sprintf(_("Entry '%s' is used more than once."),$DevName);
283             }
285             /* Names should be written in lowercase
286              */
287 #      if(strtolower($DevName) != $DevName){
288 #        $message[] = sprintf(_("The host name '%s' should be written in lowercase."), $DevName);
289 #      }
291             /* Check records
292              */                 
293             $singleEntries = array("pTRRecord");
295             $tmp  = array();
296             $tmp2 = array();
297             foreach($device['RECORDS'] as $Num => $Rec){
299                 /* Check values */
300                 $message += $this->checkRecordType($DevName, $Rec['type'], $Rec['value']);
302                 /* Check for multiple use of unique record types
303                  */
304                 if(in_array_strict($Rec['type'],$singleEntries)){
305                     if(!isset($tmp[$Rec['type']])){
306                         $tmp[$Rec['type']] = "";
307                     }else{
308                         $message[] = sprintf(_("%s records cannot be used more than once."),$Rec['type']);
309                     }
310                 }
312                 /* Check for empty / duplicate entries in record array 
313                  */
314                 if(empty($Rec['value'])){
315                     $message[] = sprintf(_("Please fix the empty %s record for entry '%s'."),$Rec['type'],$DevName);
316                 }
318                 /* Check for duplicate record entries 
319                  */
320                 if(!isset($tmp[$Rec['type']][$Rec['value']])){
321                     $tmp[$Rec['type']][$Rec['value']] = "";
322                 }else{
323                     $message[] = sprintf(_("Please fix the duplicate %s record for entry '%s'."),$Rec['type'],$DevName); 
324                 }
325             }
326         }
327         return ($message);
328     }
331     function save()
332     {
333         if($this->disableDialog || !preg_match("/w/",$this->acl)) return;
335         $todo = array(); 
339         /* Create todolist
340          */
341         foreach($this->Devices as $name => $dev){
342             if(isset($dev['OrigCn'])){
343                 if(count($dev['RECORDS'])){
344                     $todo[] = DNS::getDNSHostEntriesDiff($this->config,$dev['OrigCn'],$dev,$name);
345                 }else{
346                     $dev['exists'] = false;
347                     $todo[] = DNS::getDNSHostEntriesDiff($this->config,$dev['OrigCn'],$dev,$name);
348                 }
349             }else{
350                 if(count($dev['RECORDS'])){
351                     $todo[] = DNS::getDNSHostEntriesDiff($this->config,"",$dev,$name);
352                 }else{
353                     $dev['exists'] = false;
354                     $todo[] = DNS::getDNSHostEntriesDiff($this->config,"",$dev,$name);
355                 }
356             }
357         }
359         $tmp = array();
360         $tmp['del']   = array();
361         $tmp['add']   = array();
362         $tmp['move']  = array();
363         foreach($todo as $to){
364             foreach($to as $type => $entries){
365                 $tmp[$type] = array_merge($tmp[$type],$entries);
366             }
367         }
369         /* Get ldap link
370          */
371         $ldap = $this->config->get_ldap_link();
372         $ldap->cd ($this->config->current['BASE']);
374         /* move follwoing entries
375          */
376         foreach($tmp['move'] as $src => $dst){
377             $this->recursive_move($src,$dst);
378         }
380         /* Delete dns */
381         foreach($tmp['del'] as $dn => $del){
382             $ldap->cd($dn);
383             $ldap->rmdir_recursive($dn);
384             if(is_object($this->parent->parent)){
385                 $this->parent->parent->handle_post_events("remove",array("dn" => $dn));
386             }
387         }
389         /* Add || Update new DNS entries
390          */
391         foreach($tmp['add'] as $dn => $attrs){
392             $ldap->cd($dn);
393             $ldap->cat($dn, array('dn'));
394             if(count($ldap->fetch())){
395                 $ldap->cd($dn);
396                 $ldap->modify ($attrs);
397                 if(is_object($this->parent->parent)){
398                     $this->parent->parent->handle_post_events("modify",array("dn" => $dn));
399                 }
400             }else{
401                 $ldap->cd($dn);
402                 $ldap->add($attrs);
403                 if(is_object($this->parent->parent)){
404                     $this->parent->parent->handle_post_events("add",array("dn" => $dn));
405                 }
406             }
407         }
408     }
411     /* Create html table out of given entry 
412      */
413     function generateRecordConfigurationRow($objKey){
415         /* Get some basic informations 
416          */
417         $obj        = $this->Devices[$objKey];
418         $objectName = $objKey;
420         $dis = "";
421         if(!preg_match("/w/",$this->acl)){
422             $dis = " disabled ";
423         }
425         /* Abort if emtpy
426          */
427         if(count($obj['RECORDS']) == 0) return "";
429         /* Set title 
430          */
431         $str= "<br>";
433         $hostNameOnce = true;
435         /* Walk through all defined records 
436          */
437         $str.= "<table summary=''>";
438         foreach($obj['RECORDS'] as $id => $record){
440             /* Skip not selectable entries */
441             if(!isset($this->RecordTypes [$record['type']])) {
442                 continue;
443             }
445             /* Create unique post name
446              */
447             $name = postEncode($objKey."|".$id);
449             /* Only first host entry name should be editable
450              */
451             if($hostNameOnce){
452                 $hostNameOnce = false;  
453                 $field1 ="<input $dis type='text' style='width:250px;' name='RenameHost_".$name."' value='".set_post($objectName)."'>\n";
454             }else{
455                 $field1 = "";
456             }
457             $field2 = $this->createRecordTypeSelection($record['type'],$name);
458             $field3 = "<input type='text' $dis value='".set_post($record['value'])."' name='ValueSelection_".$name."' style='width:250px;'>";
459             if(preg_match("/w/",$this->acl)){
460                 $acl = image('images/lists/element.png[new]',"AddRecord_".$name,_("Add"));
461                 $acl.= image('images/lists/trash.png',"RemoveRecord_".$name,_("Remove"));
462             }
464             /* Display settings backwards for CNAMERecords 
465              */
466             if($record['type'] == "cNAMERecord"){
467                 $str .= "
468                     <tr>
469                     <td style='width:250px;text-align:right;'>".$field3."</td>
470                     <td style='width:90px;'>".$field2."</td>
471                     <td>".$objectName."</td>
472                     <td>".$acl."</td>
473                     </tr>";
474             }else{ 
475                 $str .= "
476                     <tr>
477                     <td style='width:75px;text-align:right;'>".$field1."</td>
478                     <td style='width:90px;'>".$field2."</td>
479                     <td>".$field3."</td>
480                     <td>".$acl."</td>
481                     </tr>";
482             }
483         }
484         $str .="</table>";
485         return($str); 
486     }
489     /* Create selectbox with all available option types 
490      */
491     function createRecordTypeSelection($id,$refID){
493         if(preg_match("/w/",$this->acl)){
494             $str = "\n<select name='RecordTypeSelection_".$refID."' onChange='document.mainform.submit();'>";
495             foreach($this->RecordTypes as $type => $atr) {
496                 if($id == $type){
497                     $str .="\n<option value='".$type."' selected >".strtoupper(preg_replace("/record/i","",$type))."</option>";
498                 }else{
499                     $str .="\n<option value='".$type."'>".strtoupper(preg_replace("/record/i","",$type))."</option>";
500                 }
501             }
502             $str.= "\n</select>";
503         }else{
504             $str = "&nbsp;".strtoupper(preg_replace("/record/i","",$id));
505         }
506         return($str);
507     }
510     /* Check record types for strange inputs */
511     function checkRecordType($name, $type, $value)
512     {
513         $template = _("The syntax of entry %s (record type %s, value %s) is invalid!")." %s<br><br><i>"._("Example").":</i> %s";
515         $message = Array();
516         switch($type) {
517             case 'aAAARecord': // RFC 3596
518                 if(!tests::is_dns_name($name)) {
519                     $message[] = sprintf($template, $name, $type, $value, _("Entry should be a DNS name."), "example");
520                 }
521                 if(!tests::is_ipv6($value)) {
522                     $message[] = sprintf($template, $name, $type, $value, _("Value should be an IPv6 address."), "1fff:0000:0a88:85a3:0000:0000:ac1f:8001");
523                 }
524                 break;
525             case 'aRecord': // RFC 1035
526                 if(!tests::is_dns_name($name)) {
527                     $message[] = sprintf($template, $name, $type, $value, _("Entry should be a DNS name."), "example");
528                 }
529                 if(!tests::is_ip($value)) {
530                     $message[] = sprintf($template, $name, $type, $value, _("Value should be an IPv4 address."), "192.168.1.10");
531                 }
532                 break;
533             case 'cNAMERecord': // RFC 1035
534                 if(!tests::is_dns_name($name)) {
535                     $message[] = sprintf($template, $name, $type, $value, _("Entry should be a DNS name."), "example");
536                 }
537                 if(!tests::is_dns_name($value)) {
538                     $message[] = sprintf($template, $name, $type, $value, _("Value should be a DNS name."), "example");
539                 }
540                 break;
541             case 'mXRecord': // RFC 1035
542                 //value: preference target
543                 if(preg_match('/^(\S+)\s+(\S+)$/', $value, $matches)) {
544                     if(!tests::is_id($matches[1])) {
545                         $message[] = sprintf($template, $name, $type, $value, _("Value 1 should be a number."), "10 example");
546                     }
547                     if(!tests::is_dns_name($matches[2])) {
548                         $message[] = sprintf($template, $name, $type, $value, _("Value 2 should be a DNS name."), "10 example");
549                     }
550                 } else {
551                     $message[] = sprintf($template, $name, $type, $value, _("Value should be composed of 'preference target'."), "10 example");
552                 }
553                 break;
554             case 'nSRecord': // RFC 1035
555                 if(!tests::is_dns_name($value)) {
556                     $message[] = sprintf($template, $name, $type, $value, _("Value should be a DNS name."), "example");
557                 }
558                 break;
559             case 'pTRRecord': // RFC 1035
560                 if(!tests::is_dns_name($value)) {
561                     $message[] = sprintf($template, $name, $type, $value, _("Value should be a DNS name."), "example");
562                 }
563                 break;
564             case 'sRVRecord': // RFC 2782
565                 if(!tests::is_dns_name($name)) {
566                     $message[] = sprintf($template, $name, $type, $value, _("Entry should be a DNS name."), "example");
567                 }
568                 //value: priority weight port target
569                 if(preg_match('/^([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+(\S+)$/', $value, $matches)) {
570                     if(!tests::is_id($matches[1])) {
571                         $message[] = sprintf($template, $name, $type, $value, _("Value 1 (priority) should be a number."), "0 5 5060 example");
572                     }
573                     if(!tests::is_id($matches[2])) {
574                         $message[] = sprintf($template, $name, $type, $value, _("Value 2 (weight) should be a number."), "0 5 5060 example");
575                     }
576                     if(!tests::is_id($matches[3])) {
577                         $message[] = sprintf($template, $name, $type, $value, _("Value 3 (port) should be a number."), "0 5 5060 example");
578                     }
579                     if(!tests::is_dns_name($matches[4])) {
580                         $message[] = sprintf($template, $name, $type, $value, _("Value 4 (target) should be a DNS name."), "0 5 5060 example");
581                     }
582                 } else {
583                     $message[] = sprintf($template, $name, $type, $value, _("Value should be composed of 'priority weight port target'."), "0 5 5060 example");
584                 }
585                 break;
586         }
587         return $message;
588     }
591     function remove_from_parent()
592     {
593     }
597 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
598 ?>