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->search("(&(objectClass=dNSZone)(zoneName=*)(!(relativeDomainName=@)))",array("*"));
101 while($attrs = $ldap->fetch()){
102 /* If relative domainname == cn
103 * Try to read dnsclass / TTl / zone
104 */
105 if($attrs['relativeDomainName'][0] == $this->cn){
106 /* Get class */
107 if(isset($attrs['dNSClass'][0])){
108 $this->dNSClass = $attrs['dNSClass'][0];
109 }
110 /* Get Zone*/
111 if(isset($attrs['zoneName'][0])){
112 $this->zoneName = $attrs['zoneName'][0];
113 }
114 /* Get ttl */
115 if(isset($attrs['dNSTTL'][0])){
116 $this->dNSTTL = $attrs['dNSTTL'][0];
117 }
118 }
120 /* Create list with all used records */
121 foreach($this->RecordTypes as $name => $value){
123 /* If there is a record attribute */
124 if(isset($attrs[$name])){
127 /* get all entries */
128 for($i = 0 ; $i < $attrs[$value]['count']; $i ++){
129 if(($value == "aRecord")&&($this->ipHostNumber==$attrs[$value][$i])){
130 continue;
131 }
132 $types[] =array("type"=>$name,"inittype"=>$name,"value"=>$attrs[$value][$i],"status"=>"edited","dn"=>$attrs['dn']);
133 }
134 }
135 }
136 }
138 /* If there is at least one entry in this -> types, we have DNS enabled */
139 $this->types = $types;
140 if(count($this->types) == 0){
141 $this->DNS_is_account = false;
142 }else{
143 $this->DNS_is_account = true;
144 }
146 /* Store initally account settings */
147 $this->DNSinitially_was_account = $this->DNS_is_account;
148 }
150 function execute()
151 {
152 /* Call parent execute */
153 $smarty= get_smarty();
154 $display= "";
156 /* There is no dns available
157 */
158 if($this->found == false){
160 $smarty->assign("DNS_is_account",false);
161 $smarty->assign("IPisMust",(($this->IPisMust)||($this->DNS_is_account)));
163 /* Assign smarty all non DNs attributes */
164 foreach($this->attributes as $attr){
165 $smarty->assign($attr,$this->$attr);
166 }
168 $display.= $smarty->fetch(get_template_path('network.tpl', TRUE));
169 return($display);
170 }else{
171 $smarty->assign("DNS_is_account",true);
172 }
174 /* Add new empty array with status new, to our record list */
175 if(isset($_POST['AddNewRecord'])){
176 $this->types[] =array("type"=>"aRecord","value"=>"","status"=>"new");
177 }
179 /* Handle all posts */
180 $only_once =true;
181 foreach($_POST as $name => $value){
183 /* Check if we have to delete a record entry */
184 if((preg_match("/RemoveRecord_/",$name))&&($only_once)) {
186 /* Avoid performing this once again */
187 $only_once = false;
189 /* Extract id for specified entry */
190 $id = preg_replace("/RemoveRecord_/","",$name);
191 $id = preg_replace("/_.*$/","",$id);
193 /* Delete this record, mark edited entries to be able to delete them */
194 if(isset($this->types[$id])){
195 if($this->types[$id]['status'] == "edited"){
196 $this->types[$id]['status'] = "deleted";
197 }else{
198 unset($this->types[$id]);
199 }
200 }
201 }
202 }
204 /* Assign smarty all non DNs attributes */
205 foreach($this->attributes as $attr){
206 $smarty->assign($attr,$this->$attr);
207 }
209 /* Assign smarty all DNS attributes */
210 foreach($this->DNSattributes as $attr){
211 $smarty->assign($attr,$this->$attr);
212 }
214 /* Assign all needed vars */
215 $smarty->assign("DNSAccount",$this->DNS_is_account);
216 $smarty->assign("Zones",$this->Zones);
217 $smarty->assign("ZoneKeys",($this->Zones));
218 $smarty->assign("IPisMust",(($this->IPisMust)||($this->DNS_is_account)));
219 $changeStateForRecords ="";
220 $smarty->assign("records",$this->generateRecordsList(&$changeStateForRecords));
221 $smarty->assign("changeStateForRecords",$changeStateForRecords);
222 // $smarty->assign("dNSClasses",array("IN"=>"IN"));
223 $smarty->assign("staticAddress","<font class=\"must\">*</font>");
224 $display.= $smarty->fetch(get_template_path('network.tpl', TRUE));
225 return($display);
226 }
228 function remove_from_parent()
229 {
230 $ldap = $this->config->get_ldap_link();
231 $ldap->cd($this->orig_dn);
232 $ldap->search("(&(objectClass=dNSZone)(zoneName=*)(!(relativeDomainName=@)))",array("relativeDomainName","zoneName"));
233 while($attr = $ldap->fetch()){
234 $ldap->cd($attr['dn']);
235 $ldap->rmDir($attr['dn']);
236 }
237 }
239 /* Save data to object */
240 function save_object()
241 {
242 /* Save all posted vars */
243 plugin::save_object();
245 /* Ge all non dns attributes (IP/MAC)*/
246 foreach($this->attributes as $attr){
247 if(isset($_POST[$attr])){
248 $this->$attr = $_POST[$attr];
249 }
250 }
252 /* Get dns attributes */
253 if(isset($_POST['network_tpl_posted'])){
255 /* Check for posted record changes */
256 foreach($this->types as $key => $value){
258 /* Check if type has changed */
259 if(isset($_POST['RecordTypeSelectedFor_'.$key])){
260 $this->types[$key]['type'] = $_POST['RecordTypeSelectedFor_'.$key];
261 }
262 /* Check if value has changed */
263 if(isset($_POST['RecordValue_'.$key])){
264 $this->types[$key]['value'] = $_POST['RecordValue_'.$key];
265 }
266 }
268 /* Get all basic DNS attributes (TTL, Clas ..)*/
269 foreach($this->DNSattributes as $attr){
270 if(isset($_POST[$attr])){
271 $this->$attr = $_POST[$attr];
272 }
273 }
275 /* Enable diable DNS */
276 if(isset($_POST['enableDNS'])){
277 $this->DNS_is_account = true;
278 }else{
279 $this->DNS_is_account = false;
280 }
281 }
282 }
285 /* Check supplied data */
286 function check()
287 {
288 $message= array();
291 if(($this->IPisMust)||($this->DNS_is_account)){
292 /* Check if ip is empty */
293 if ($this->ipHostNumber == "" && chkacl ($this->acl, "ipHostNumber") == ""){
294 $message[]= _("The required field 'IP-address' is not set.");
295 }
297 /* check if given ip is valid ip*/
298 $num="(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])";
299 if (!preg_match("/^$num\\.$num\\.$num\\.$num$/", $this->ipHostNumber)){
300 $message[]= _("Wrong IP format in field IP-address.");
301 }
302 }
304 /* Check if mac is empty */
305 if ($this->macAddress == "" && chkacl ($this->acl, "macAddress") == ""){
306 $message[]= _("The required field 'MAC-address' is not set.");
307 }
309 /* Check if given mac is valid mac */
310 $tr = count(split(":",$this->macAddress));
311 if($tr!=6){
312 $message[]=(_("The given macaddress is invalid. There must be 6 1byte segments seperated by ':'."));
313 }
315 /* only perfrom this checks if this is a valid DNS account */
316 if($this->DNS_is_account){
317 foreach($this->types as $name => $values){
319 /* Check if there is an aRecord defined which uses the same IP as used in IPhostAddress */
320 if(($values['type'] == "aRecord")&&($values['value'] == $this->ipHostNumber)&&($values['status']!="deleted")){
321 $message[]=sprintf(_("The device IP '%s' is added as 'A Record', this will be done automatically, please remove the record."),
322 $this->ipHostNumber);
323 }
325 /* only lower-case is allowed in record entries ... */
326 if($values['value'] != strtolower($values['value'])){
327 $message[] = sprintf(_("Only lowercase is allowed, please check your '%ss'."),$values['type']);
328 }
329 }
330 }
332 return ($message);
333 }
336 /* Save to LDAP */
337 function save($dn)
338 {
339 $ldap= $this->config->get_ldap_link();
341 /*******************/
342 /* IP-MAC HANDLING */
343 /*******************/
345 /* $dn was posted as parameter */
346 $this->dn = $dn;
348 /* Save DNS setting & ip/Mac*/
349 plugin::save();
351 /* Write back to ldap */
352 $ldap->cd($this->dn);
353 $this->cleanup();
354 $ldap->modify ($this->attrs);
357 /****************/
358 /* DNS HANDLING */
359 /****************/
361 /* If isn't DNS account but initially was DNS account
362 remove all DNS entries
363 */
364 if(!$this->DNS_is_account){
365 if($this->DNSinitially_was_account){
366 $tmp = array();
367 foreach($this->types as $type){
368 $dn = $type['dn'];
369 if(!isset($tmp[$dn])) {
370 $ldap->cd($dn);
371 $ldap->rmDir($dn);
372 }
373 $tmp[$dn]=$dn;
374 }
375 }
376 }else{
378 /* DNS is enabled, check what we have to do */
379 $delete = array();
381 /* Generate a list of new ldap entries,
382 & $delete contains all dns which should be deleted
383 */
384 $entries = $this->generate_LDAP_entries(&$delete);
386 /* Delete dns */
387 foreach($delete as $dn => $del){
388 $ldap->cd($dn);
389 $ldap->rmDir($dn);
390 }
392 /* Add || Update new DNS entries */
393 foreach($entries as $dn => $attrs){
394 $ldap->cd($dn);
395 $ldap->cat($dn);
397 if(count($ldap->fetch())){
398 $ldap->cd($dn);
399 // $this->cleanup();
400 $ldap->modify ($attrs);
402 }else{
403 $ldap->cd($dn);
404 $ldap->add($attrs);
405 }
406 }
407 }
408 if($ldap->get_error() != "Success"){
409 show_ldap_error($ldap->get_error());
410 }
412 }
414 /* Create html table with all used record types
415 */
416 function generateRecordsList($changeStateForRecords)
417 {
418 $changeStateForRecords = "";
420 if(!$this->DNS_is_account) {
421 $str = "<input type='submit' value='"._("Add")."' name='AddNewRecord' id='AddNewRecord' disabled>";
422 return $str;
423 }
425 $str = "<table summary='' width='100%'>";
426 foreach($this->types as $key => $entry){
427 if($entry['status'] == "deleted") continue;
429 $changeStateForRecords.= "changeState('RecordTypeSelectedFor_".$key."');\n";
430 $changeStateForRecords.= "changeState('RecordValue_".$key."');\n";
431 $changeStateForRecords.= "changeState('RemoveRecord_".$key."');\n";
433 $str.=" <tr>".
434 " <td>".$this->generateRecordListBox($entry['type'],"RecordTypeSelectedFor_".$key)."</td>".
435 " <td><input type='text' value='".$entry['value']."' name='RecordValue_".$key."' id='RecordValue_".$key."'></td>".
436 " <td><input type='submit' name='RemoveRecord_".$key."' value='"._("Delete")."' id='RemoveRecord_".$key."'></td>".
437 "</tr>";
438 }
440 $str.= " <tr>".
441 " <td colspan=2 width='50%'></td><td>".
442 " <input type='submit' value='"._("Add")."' name='AddNewRecord'>".
443 " </td>".
444 " </tr>".
445 "</table>";
446 return($str);
447 }
449 /* Create a html select box which allows us to select different types of records */
450 function generateRecordListBox($selected,$name)
451 {
452 $str = "<select name='".$name."' id='".$name."'>";
453 foreach($this->RecordTypes as $type => $value){
454 $use = "";
455 if($type == $selected){
456 $use = " selected ";
457 }
458 $str.="\n <option value='".$type."' ".$use.">".strtoupper(preg_replace("/record/i","",$type))."</option>";
459 }
460 $str.="</select>";
461 return($str);
462 }
464 /* return all Zone names */
465 function get_Zones()
466 {
467 $ret = array();
468 $ldap = $this->config->get_ldap_link();
469 $ldap-> cd ($this->config->current['BASE']);
470 $ldap->search("(&(objectClass=dNSZone)(sOARecord=*))",array("*"));
472 while($at = $ldap->fetch()){
473 if(preg_match("/\.in\-addr\.arpa/",$at['zoneName'][0])){
474 $ret[$at['relativeDomainName'][0]]['addr']= $at['zoneName'][0];
475 }else{
476 $ret[$at['relativeDomainName'][0]]['name']= $at['zoneName'][0];
477 }
478 }
480 $tmp =array();
481 foreach($ret as $name => $entry){
482 if((isset($entry['addr']))&&(isset($entry['name']))){
483 $tmp[$entry['addr']]=$entry['name'];
484 }
485 }
486 $ret = $tmp;
487 return($ret);
488 }
490 /* this is used to generate ldap friendly output of our
491 dns configuration
492 */
493 function generate_LDAP_entries($delete)
494 {
495 $entries = array();
496 $delete = array();
498 /* Generate Main Entry */
499 $dn = "relativeDomainName=".$this->cn.",".$this->dn;
500 $entries[$dn]['dNSClass'] = $this->dNSClass;
501 $entries[$dn]['zoneName'] = $this->zoneName;
502 $entries[$dn]['dNSTTL'] = $this->dNSTTL;
503 $entries[$dn]['relativeDomainName'] = $this->cn;
505 /* Generate cNAMERecord */
506 $aRecords = array();
507 foreach($this->types as $type){
508 if($type['type'] == "cNAMERecord"){
510 $Cdn = "relativeDomainName=".$type['value'].",".$this->dn;
511 if($type['status']=="deleted"){
512 $delete [$type['dn']] = $Cdn;
513 }else{
514 $entries[$Cdn] = $entries[$dn];
515 $entries[$Cdn]['relativeDomainName'] = $type['value'];
516 $entries[$Cdn]['cNAMERecord'] = $this->cn.".".$this->zoneName;
517 }
518 }
519 }
521 /* Generate tXTRecord */
522 $aRecords = array();
523 foreach($this->types as $type){
524 if(($type['type'] == "tXTRecord")&&($type['status']!="deleted")){
525 $entries[$dn]['tXTRecord'][] = $type['value'];
526 }
527 }
529 /* Generate mDRecord */
530 $aRecords = array();
531 foreach($this->types as $type){
532 if(($type['type'] == "mDRecord")&&($type['status']!="deleted")){
533 $entries[$dn]['mDRecord'][] = $type['value'];
534 }
535 }
537 /* Generate mXRecord */
538 $aRecords = array();
539 foreach($this->types as $type){
540 if(($type['type'] == "mXRecord")&&($type['status']!="deleted")){
541 $entries[$dn]['mXRecord'][] = $type['value'];
542 }
543 }
545 /* Generate hInfoRecord */
546 $aRecords = array();
547 foreach($this->types as $type){
548 if(($type['type'] == "hInfoRecord")&&($type['status']!="deleted")){
549 $entries[$dn]['hInfoRecord'][] = $type['value'];
550 }
551 }
553 /* Generate mInfoRecord */
554 $aRecords = array();
555 foreach($this->types as $type){
556 if(($type['type'] == "mInfoRecord")&&($type['status']!="deleted")){
557 $entries[$dn]['mInfoRecord'][] = $type['value'];
558 }
559 }
561 /* Generate aFSDBRecord */
562 $aRecords = array();
563 foreach($this->types as $type){
564 if(($type['type'] == "aFSDBRecord")&&($type['status']!="deleted")){
565 $entries[$dn]['aFSDBRecord'][] = $type['value'];
566 }
567 }
569 /* Generate some attrs */
570 $arr = array("SigRecord","KeyRecord","aAAARecord","nSRecord",
571 "LocRecord","nXTRecord","sRVRecord","nAPTRRecord","kXRecord","certRecord","a6Record","dSRecord","sSHFPRecord","rRSIGRecord","nSECRecord");
572 $aRecords = array();
573 foreach($arr as $ar){
574 foreach($this->types as $type){
575 if(($type['type'] == $ar)&&($type['status']!="deleted")){
576 $entries[$dn][$ar][] = $type['value'];
577 }
578 }
579 }
582 /* Generate A Records (IP Address relation) */
583 $aRecords = array();
584 foreach($this->types as $type){
585 if(($type['type'] == "aRecord")&&($type['status']!="deleted")){
586 $aRecords[] = $type['value'];
587 }
588 }
589 if(count($aRecords)){
591 /* Add ipHostNumber as default aRecord */
592 $aRecords[] = $this->ipHostNumber;
594 $dn = "relativeDomainName=".$this->cn.",".$this->dn;
595 foreach($aRecords as $rec){
596 $entries[$dn]['aRecord'][] = $rec;
597 }
598 }
600 /* Generate pTRRecord Records */
601 foreach($this->types as $type){
602 if($type['type'] == "pTRRecord"){
603 $PTRdn= "relativeDomainName=".$type['value'].",".$this->dn;
604 if($type['status']=="deleted"){
605 $delete [$type['dn']] = $PTRdn;
606 }else{
607 $zones = array_flip($this->Zones);
608 $zone = $zones[$this->zoneName];
609 $entries[$PTRdn]['relativeDomainName'] = $type['value'];
610 $entries[$PTRdn]['pTRRecord'] = $this->cn.".".$this->zoneName;
611 $entries[$PTRdn]['zoneName'] = $zone;
612 }
613 }
614 }
616 /* add ObjectClasses */
617 foreach($entries as $key => $entry ){
618 $entries[$key]['objectClass']=array("top","dNSZone");
619 $entries[$key] = array_reverse($entries[$key]);
620 }
622 /* Check if record type has changed, and if we need to delete this record attribute from ldap entry */
623 foreach($this->types as $type){
624 if(isset($type['inittype'])){
625 if(!isset($entries[$dn][$type['inittype']])){
626 $entries[$dn][$type['inittype']] = array();
627 }
628 }
629 }
631 return($entries);
632 }
633 }
635 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
636 ?>