9ec385ffb012234e0cd6288ee3d7fb736fa4b250
1 <?php
3 class termDNS extends plugin
4 {
5 /* CLI vars */
6 var $cli_summary= "Manage server basic objects";
7 var $cli_description= "Some longer text\nfor help";
8 var $cli_parameters= array("eins" => "Eins ist toll", "zwei" => "Zwei ist noch besser");
10 /* attribute list for save action */
11 var $ignore_account= TRUE;
12 var $DNSattributes = array("dNSClass","zoneName","dNSTTL");
13 var $attributes= array("ipHostNumber","macAddress");
14 var $objectclasses= array("whatever");
16 var $ipHostNumber =""; // IP address
17 var $macAddress =""; // Mac address
18 var $cn =""; // CN of currently edited device
20 var $Zones = array(); // All Available Zones like array("3.2.1"=>"MyServer.de")
21 var $RecordTypes= array(); // Possible record types
23 var $dNSClass = "IN"; // dNSClass name
24 var $zoneName = ""; // Used ZoneName
25 var $dNSTTL = 7200; // TTL settings for the created entries
27 /* Used records */
28 var $types = array();
29 var $DNSinitially_was_account = false;
31 var $orig_dn ="";
33 var $IPisMust = false;
34 var $MACisMust= false;
36 var $found = false;
38 function termDNS ($config, $dn,$objectClasses,$IPisMust = false)
39 {
40 /* We need to know which objectClasses are used, to store the ip/mac*/
41 $this->objectclasses= $objectClasses;
42 plugin::plugin ($config, $dn);
44 $this->orig_dn= $dn;
46 $this->IPisMust = $IPisMust;
48 /* Hide all dns specific code, if dns is not available
49 */
50 $found = false;
51 foreach($this->config->data['TABS']['SERVTABS'] as $tab){
52 if(preg_match("/^servdns$/",$tab['CLASS'])){
53 $found = true;
54 }
55 }
56 $this->found = $found;
57 if(!$this->found){
58 $this->DNS_is_account = false;
59 return;
60 }
63 /* All types with required attrs */
64 $this->RecordTypes['aRecord'] = "aRecord"; // ok
65 $this->RecordTypes['mDRecord'] = "mDRecord"; // ok
66 $this->RecordTypes['mXRecord'] = "mXRecord"; // ok
67 $this->RecordTypes['nSRecord'] = "nSRecord"; // ok
68 $this->RecordTypes['pTRRecord'] = "relativeDomainName";// ok
69 $this->RecordTypes['hInfoRecord'] = "hInfoRecord"; // ok
70 $this->RecordTypes['mInfoRecord'] = "mInfoRecord"; // ok
71 $this->RecordTypes['cNAMERecord'] = "relativeDomainName";// ok
72 $this->RecordTypes['tXTRecord'] = "tXTRecord"; // ok
73 $this->RecordTypes['aFSDBRecord'] = "aFSDBRecord"; // ok
74 $this->RecordTypes['SigRecord'] = "SigRecord"; // ok
75 $this->RecordTypes['KeyRecord'] = "KeyRecord"; // ok
76 $this->RecordTypes['aAAARecord'] = "aAAARecord"; // ok
77 $this->RecordTypes['LocRecord'] = "LocRecord"; // ok
78 $this->RecordTypes['nXTRecord'] = "nXTRecord"; // ok
79 $this->RecordTypes['sRVRecord'] = "sRVRecord"; // ok
80 $this->RecordTypes['nAPTRRecord'] = "nAPTRRecord"; // ok
81 $this->RecordTypes['kXRecord'] = "kXRecord"; // ok
82 $this->RecordTypes['certRecord'] = "certRecord"; // ok
83 $this->RecordTypes['a6Record'] = "a6Record"; // ok
84 $this->RecordTypes['dSRecord'] = "dSRecord"; // ok
85 $this->RecordTypes['sSHFPRecord'] = "sSHFPRecord"; // ok
86 $this->RecordTypes['rRSIGRecord'] = "rRSIGRecord"; // ok
87 $this->RecordTypes['nSECRecord'] = "nSECRecord"; // ok
89 /* Get all available zones */
90 if(empty($this->cn)&&(isset($this->attrs['cn'][0]))){
91 $this->cn = $this->attrs['cn'][0];
92 }
93 $this->Zones = $this->get_Zones();
94 $types = array();
96 /* Get all records */
97 $ldap = $this->config->get_ldap_link();
98 $ldap->cd($this->dn);
99 $ldap->ls("(&(objectClass=dNSZone)(zoneName=*)(!(relativeDomainName=@)))",$this->dn,array("*"));
101 $found = false;
103 while($attrs = $ldap->fetch()){
104 /* If relative domainname == cn
105 * Try to read dnsclass / TTl / zone
106 */
108 if($attrs['relativeDomainName'][0] == $this->cn){
109 /* Get class */
110 if(isset($attrs['dNSClass'][0])){
111 $this->dNSClass = $attrs['dNSClass'][0];
112 $found = true;
113 }
114 /* Get Zone*/
115 if(isset($attrs['zoneName'][0])){
116 $this->zoneName = $attrs['zoneName'][0];
117 $found = true;
118 }
119 /* Get ttl */
120 if(isset($attrs['dNSTTL'][0])){
121 $this->dNSTTL = $attrs['dNSTTL'][0];
122 $found = true;
123 }
124 }
126 /* Create list with all used records */
127 foreach($this->RecordTypes as $name => $value){
129 /* If there is a record attribute */
130 if(isset($attrs[$name])){
133 /* get all entries */
134 for($i = 0 ; $i < $attrs[$value]['count']; $i ++){
135 if(($value == "aRecord")&&($this->ipHostNumber==$attrs[$value][$i])){
136 continue;
137 }
138 $types[] =array("type"=>$name,"inittype"=>$name,"value"=>$attrs[$value][$i],"status"=>"edited","dn"=>$attrs['dn']);
139 }
140 }
141 }
142 }
144 /* If there is at least one entry in this -> types, we have DNS enabled */
145 $this->types = $types;
146 if((count($this->types) == 0) &&($found == false)){
147 $this->DNS_is_account = false;
148 }else{
149 $this->DNS_is_account = true;
150 }
152 /* Store initally account settings */
153 $this->DNSinitially_was_account = $this->DNS_is_account;
154 }
156 function getVarsForSaving($attrs)
157 {
158 foreach($this->attributes as $attr){
159 if(!empty($this->$attr)){
160 $attrs[$attr] = $this->$attr;
161 }
162 }
163 return($attrs);
164 }
166 function execute()
167 {
168 /* Call parent execute */
169 $smarty= get_smarty();
170 $display= "";
172 $smarty->assign("staticAddress", "");
174 /* There is no dns available
175 */
176 if($this->found == false){
178 $smarty->assign("DNS_is_account",false);
179 $smarty->assign("IPisMust",(($this->IPisMust)||($this->DNS_is_account)));
181 /* Assign smarty all non DNs attributes */
182 foreach($this->attributes as $attr){
183 $smarty->assign($attr,$this->$attr);
184 }
185 $smarty->assign("staticAddress", "");
186 $display.= $smarty->fetch(get_template_path('network.tpl', TRUE));
187 return($display);
188 }else{
189 $smarty->assign("DNS_is_account",true);
190 }
192 /* Add new empty array with status new, to our record list */
193 if(isset($_POST['AddNewRecord'])){
194 $this->types[] =array("type"=>"aRecord","value"=>"","status"=>"new");
195 }
197 /* Handle all posts */
198 $only_once =true;
199 foreach($_POST as $name => $value){
201 /* Check if we have to delete a record entry */
202 if((preg_match("/RemoveRecord_/",$name))&&($only_once)) {
204 /* Avoid performing this once again */
205 $only_once = false;
207 /* Extract id for specified entry */
208 $id = preg_replace("/RemoveRecord_/","",$name);
209 $id = preg_replace("/_.*$/","",$id);
211 /* Delete this record, mark edited entries to be able to delete them */
212 if(isset($this->types[$id])){
213 if($this->types[$id]['status'] == "edited"){
214 $this->types[$id]['status'] = "deleted";
215 }else{
216 unset($this->types[$id]);
217 }
218 }
219 }
220 }
222 /* Assign smarty all non DNs attributes */
223 foreach($this->attributes as $attr){
224 $smarty->assign($attr,$this->$attr);
225 }
227 /* Assign smarty all DNS attributes */
228 foreach($this->DNSattributes as $attr){
229 $smarty->assign($attr,$this->$attr);
230 }
232 /* Assign all needed vars */
233 $smarty->assign("DNSAccount",$this->DNS_is_account);
234 $smarty->assign("Zones",$this->Zones);
235 $smarty->assign("ZoneKeys",($this->Zones));
236 $smarty->assign("IPisMust",(($this->IPisMust)||($this->DNS_is_account)));
238 $tmp = $this->generateRecordsList();
239 $changeStateForRecords = $tmp['changeStateForRecords'];
240 $smarty->assign("records",$tmp['str']);
241 $smarty->assign("changeStateForRecords",$changeStateForRecords);
242 $smarty->assign("staticAddress","<font class=\"must\">*</font>");
243 $display.= $smarty->fetch(get_template_path('network.tpl', TRUE));
244 return($display);
245 }
247 function remove_from_parent()
248 {
249 $ldap = $this->config->get_ldap_link();
250 $ldap->cd($this->orig_dn);
251 $ldap->search("(&(objectClass=dNSZone)(zoneName=*)(!(relativeDomainName=@)))",array("relativeDomainName","zoneName"));
252 while($attr = $ldap->fetch()){
253 $ldap->cd($attr['dn']);
254 $ldap->rmDir($attr['dn']);
255 }
256 }
258 /* Save data to object */
259 function save_object()
260 {
261 /* Save all posted vars */
262 plugin::save_object();
264 /* Ge all non dns attributes (IP/MAC)*/
265 foreach($this->attributes as $attr){
266 if(isset($_POST[$attr])){
267 $this->$attr = $_POST[$attr];
268 }
269 }
271 /* Get dns attributes */
272 if(isset($_POST['network_tpl_posted'])){
274 /* Check for posted record changes */
275 foreach($this->types as $key => $value){
277 /* Check if type has changed */
278 if(isset($_POST['RecordTypeSelectedFor_'.$key])){
279 $this->types[$key]['type'] = $_POST['RecordTypeSelectedFor_'.$key];
280 }
281 /* Check if value has changed */
282 if(isset($_POST['RecordValue_'.$key])){
283 $this->types[$key]['value'] = $_POST['RecordValue_'.$key];
284 }
285 }
287 /* Get all basic DNS attributes (TTL, Clas ..)*/
288 foreach($this->DNSattributes as $attr){
289 if(isset($_POST[$attr])){
290 $this->$attr = $_POST[$attr];
291 }
292 }
294 /* Enable diable DNS */
295 if(isset($_POST['enableDNS'])){
296 $this->DNS_is_account = true;
297 }else{
298 $this->DNS_is_account = false;
299 }
300 }
301 }
304 /* Check supplied data */
305 function check()
306 {
307 $message= array();
310 if(($this->IPisMust)||($this->DNS_is_account)){
311 /* Check if ip is empty */
312 if ($this->ipHostNumber == "" && chkacl ($this->acl, "ipHostNumber") == ""){
313 $message[]= _("The required field 'IP-address' is not set.");
314 }
316 /* check if given ip is valid ip*/
317 $num="(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])";
318 if (!preg_match("/^$num\\.$num\\.$num\\.$num$/", $this->ipHostNumber)){
319 $message[]= _("Wrong IP format in field IP-address.");
320 }
321 }
323 /* Check if mac is empty */
324 if ($this->macAddress == "" && chkacl ($this->acl, "macAddress") == ""){
325 $message[]= _("The required field 'MAC-address' is not set.");
326 }
328 /* Check if given mac is valid mac */
329 $tr = count(split(":",$this->macAddress));
330 if($tr!=6){
331 $message[]=(_("The given macaddress is invalid. There must be 6 1byte segments seperated by ':'."));
332 }
334 /* only perfrom this checks if this is a valid DNS account */
335 if($this->DNS_is_account){
337 $checkArray = array();
338 $onlyOnce = array();
339 $onlyOnce['cNAMERecord'] = 0;
341 foreach($this->types as $name => $values){
343 if(!isset($checkArray[$values['type']][$values['value']])){
344 $checkArray[$values['type']][$values['value']] = 0;
345 }else{
346 $message[] = sprintf(_("Found duplicate value for record type '%s'."),$values['type']);
347 }
349 if(isset($onlyOnce[$values['type']])){
350 $onlyOnce[$values['type']] ++;
351 if($onlyOnce[$values['type']] > 1){
352 $message[] = sprintf(_("Found more than one entry for the uniqe record type '%s'."),$values['type']);
353 }
354 }
356 if($values['type'] == "tXTRecord") continue;
358 /* Check if there is an aRecord defined which uses the same IP as used in IPhostAddress */
359 if(($values['type'] == "aRecord")&&($values['value'] == $this->ipHostNumber)&&($values['status']!="deleted")){
360 $message[]=sprintf(_("The device IP '%s' is added as 'A Record', this will be done automatically, please remove the record."),
361 $this->ipHostNumber);
362 }
364 /* only lower-case is allowed in record entries ... */
365 if($values['value'] != strtolower($values['value'])){
366 $message[] = sprintf(_("Only lowercase is allowed, please check your '%ss'."),$values['type']);
367 }
368 }
369 }
370 return ($message);
371 }
374 /* Save to LDAP */
375 function save($dn)
376 {
377 $ldap= $this->config->get_ldap_link();
379 /*******************/
380 /* IP-MAC HANDLING */
381 /*******************/
383 /* $dn was posted as parameter */
384 $this->dn = $dn;
386 /* Save DNS setting & ip/Mac*/
387 plugin::save();
389 /* Write back to ldap */
390 $ldap->cd($this->dn);
391 $this->cleanup();
392 $ldap->modify ($this->attrs);
395 /****************/
396 /* DNS HANDLING */
397 /****************/
399 /* If isn't DNS account but initially was DNS account
400 remove all DNS entries
401 */
402 if(!$this->DNS_is_account){
403 if($this->DNSinitially_was_account){
404 $tmp = array();
406 $ldap->ls("(&(objectClass=dNSZone)(!(relativeDomainName=@)))",$this->dn,array("relativeDomainName"));
407 while($attrs = $ldap->fetch()){
408 $dn=$attrs['dn'];
409 $ldap->cd($dn);
410 $ldap->rmdir_recursive($dn);
411 }
412 }
413 }else{
415 /* DNS is enabled, check what we have to do */
416 $delete = array();
418 /* Generate a list of new ldap entries,
419 & $delete contains all dns which should be deleted
420 */
421 $tmp = $this->generate_LDAP_entries();
423 $entries = $tmp['entries'];
424 $delete = $tmp['delete'];
426 /* Delete dns */
427 foreach($delete as $dn => $del){
428 $ldap->cd($dn);
429 $ldap->rmDir($dn);
430 }
432 /* Add || Update new DNS entries */
433 foreach($entries as $dn => $attrs){
434 $ldap->cd($dn);
435 $ldap->cat($dn);
437 if(count($ldap->fetch())){
438 $ldap->cd($dn);
439 // $this->cleanup();
440 $ldap->modify ($attrs);
442 }else{
443 $ldap->cd($dn);
444 $ldap->add($attrs);
445 }
446 }
447 }
448 if($ldap->get_error() != "Success"){
449 show_ldap_error($ldap->get_error());
450 }
452 }
454 /* Create html table with all used record types
455 */
456 function generateRecordsList()
457 {
458 $changeStateForRecords = "";
460 if(!$this->DNS_is_account) {
461 $str = "<input type='submit' value='"._("Add")."' name='AddNewRecord' id='AddNewRecord' disabled>";
462 return $str;
463 }
465 $str = "<table summary='' width='100%'>";
466 foreach($this->types as $key => $entry){
467 if($entry['status'] == "deleted") continue;
469 $changeStateForRecords.= "changeState('RecordTypeSelectedFor_".$key."');\n";
470 $changeStateForRecords.= "changeState('RecordValue_".$key."');\n";
471 $changeStateForRecords.= "changeState('RemoveRecord_".$key."');\n";
473 $str.=" <tr>".
474 " <td>".$this->generateRecordListBox($entry['type'],"RecordTypeSelectedFor_".$key)."</td>".
475 " <td><input type='text' value='".$entry['value']."' name='RecordValue_".$key."' id='RecordValue_".$key."'></td>".
476 " <td><input type='submit' name='RemoveRecord_".$key."' value='"._("Delete")."' id='RemoveRecord_".$key."'></td>".
477 "</tr>";
478 }
480 $str.= " <tr>".
481 " <td colspan=2 width='50%'></td><td>".
482 " <input type='submit' value='"._("Add")."' name='AddNewRecord'>".
483 " </td>".
484 " </tr>".
485 "</table>";
486 $ret = array("str" => $str, "changeStateForRecords" => $changeStateForRecords);
487 return($ret);
488 }
490 /* Create a html select box which allows us to select different types of records */
491 function generateRecordListBox($selected,$name)
492 {
493 $str = "<select name='".$name."' id='".$name."'>";
494 foreach($this->RecordTypes as $type => $value){
495 $use = "";
496 if($type == $selected){
497 $use = " selected ";
498 }
499 $str.="\n <option value='".$type."' ".$use.">".strtoupper(preg_replace("/record/i","",$type))."</option>";
500 }
501 $str.="</select>";
502 return($str);
503 }
505 /* return all Zone names */
506 function get_Zones()
507 {
508 $ret = array();
509 $ldap = $this->config->get_ldap_link();
510 $ldap-> cd ($this->config->current['BASE']);
511 $ldap->search("(&(objectClass=dNSZone)(sOARecord=*))",array("zoneName","tXTRecord"));
513 while($at = $ldap->fetch()){
514 if(preg_match("/\.in\-addr\.arpa/",$at['zoneName'][0])){
515 $name = preg_replace("/^zoneName=/","",$at['tXTRecord'][0]);
516 $ret[$name]['addr']= $at['zoneName'][0];
517 }else{
518 $name = $at['zoneName'][0];
519 $ret[$name]['name']= $at['zoneName'][0];
520 }
521 }
523 $tmp =array();
524 foreach($ret as $name => $entry){
525 if((isset($entry['addr']))&&(isset($entry['name']))){
526 $tmp[$entry['addr']]=$entry['name'];
527 }
528 }
529 $ret = $tmp;
530 return($ret);
531 }
533 /* this is used to generate ldap friendly output of our
534 dns configuration
535 */
536 function generate_LDAP_entries()
537 {
538 $entries = array();
539 $delete = array();
541 /* Generate Main Entry */
542 $dn = "relativeDomainName=".$this->cn.",".$this->dn;
543 $entries[$dn]['dNSClass'] = $this->dNSClass;
544 $entries[$dn]['zoneName'] = $this->zoneName;
545 $entries[$dn]['dNSTTL'] = $this->dNSTTL;
546 $entries[$dn]['relativeDomainName'] = $this->cn;
548 /* Generate cNAMERecord */
549 $aRecords = array();
550 foreach($this->types as $type){
551 if($type['type'] == "cNAMERecord"){
553 $Cdn = "relativeDomainName=".$type['value'].",".$this->dn;
554 if($type['status']=="deleted"){
555 $delete [$type['dn']] = $Cdn;
556 }else{
557 $entries[$Cdn] = $entries[$dn];
558 $entries[$Cdn]['relativeDomainName'] = $type['value'];
559 $entries[$Cdn]['cNAMERecord'] = $this->cn.".".$this->zoneName;
560 }
561 }
562 }
564 /* Generate tXTRecord */
565 $aRecords = array();
566 foreach($this->types as $type){
567 if(($type['type'] == "tXTRecord")&&($type['status']!="deleted")){
568 $entries[$dn]['tXTRecord'][] = $type['value'];
569 }
570 }
572 /* Generate mDRecord */
573 $aRecords = array();
574 foreach($this->types as $type){
575 if(($type['type'] == "mDRecord")&&($type['status']!="deleted")){
576 $entries[$dn]['mDRecord'][] = $type['value'];
577 }
578 }
580 /* Generate mXRecord */
581 $aRecords = array();
582 foreach($this->types as $type){
583 if(($type['type'] == "mXRecord")&&($type['status']!="deleted")){
584 $entries[$dn]['mXRecord'][] = $type['value'];
585 }
586 }
588 /* Generate hInfoRecord */
589 $aRecords = array();
590 foreach($this->types as $type){
591 if(($type['type'] == "hInfoRecord")&&($type['status']!="deleted")){
592 $entries[$dn]['hInfoRecord'][] = $type['value'];
593 }
594 }
596 /* Generate mInfoRecord */
597 $aRecords = array();
598 foreach($this->types as $type){
599 if(($type['type'] == "mInfoRecord")&&($type['status']!="deleted")){
600 $entries[$dn]['mInfoRecord'][] = $type['value'];
601 }
602 }
604 /* Generate aFSDBRecord */
605 $aRecords = array();
606 foreach($this->types as $type){
607 if(($type['type'] == "aFSDBRecord")&&($type['status']!="deleted")){
608 $entries[$dn]['aFSDBRecord'][] = $type['value'];
609 }
610 }
612 /* Generate some attrs */
613 $arr = array("SigRecord","KeyRecord","aAAARecord","nSRecord",
614 "LocRecord","nXTRecord","sRVRecord","nAPTRRecord","kXRecord","certRecord","a6Record","dSRecord","sSHFPRecord","rRSIGRecord","nSECRecord");
615 $aRecords = array();
616 foreach($arr as $ar){
617 foreach($this->types as $type){
618 if(($type['type'] == $ar)&&($type['status']!="deleted")){
619 $entries[$dn][$ar][] = $type['value'];
620 }
621 }
622 }
625 /* Generate A Records (IP Address relation) */
626 $aRecords = array();
627 foreach($this->types as $type){
628 if(($type['type'] == "aRecord")&&($type['status']!="deleted")){
629 $aRecords[] = $type['value'];
630 }
631 }
632 if(count($aRecords)){
634 /* Add ipHostNumber as default aRecord */
635 $aRecords[] = $this->ipHostNumber;
637 $dn = "relativeDomainName=".$this->cn.",".$this->dn;
638 foreach($aRecords as $rec){
639 $entries[$dn]['aRecord'][] = $rec;
640 }
641 }
643 /* Generate pTRRecord Records */
644 foreach($this->types as $type){
645 if($type['type'] == "pTRRecord"){
646 $PTRdn= "relativeDomainName=".$type['value'].",".$this->dn;
647 if($type['status']=="deleted"){
648 $delete [$type['dn']] = $PTRdn;
649 }else{
650 $zones = array_flip($this->Zones);
651 $zone = $zones[$this->zoneName];
652 $entries[$PTRdn]['relativeDomainName'] = $type['value'];
653 $entries[$PTRdn]['pTRRecord'] = $this->cn.".".$this->zoneName;
654 $entries[$PTRdn]['zoneName'] = $zone;
655 }
656 }
657 }
659 /* add ObjectClasses */
660 foreach($entries as $key => $entry ){
661 $entries[$key]['objectClass']=array("top","dNSZone");
662 $entries[$key] = array_reverse($entries[$key]);
663 }
665 /* Check if record type has changed, and if we need to delete this record attribute from ldap entry */
666 foreach($this->types as $type){
667 if(isset($type['inittype'])){
668 if(!isset($entries[$dn][$type['inittype']])){
669 $entries[$dn][$type['inittype']] = array();
670 }
671 }
672 }
674 $ret = array("entries"=> $entries,"delete"=>$delete);
675 return($ret);
676 }
677 }
679 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
680 ?>