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 function termDNS ($config, $dn,$objectClasses,$IPisMust = false)
37 {
38 /* We need to know which objectClasses are used, to store the ip/mac*/
39 $this->objectclasses= $objectClasses;
40 plugin::plugin ($config, $dn);
42 $this->orig_dn= $dn;
44 $this->IPisMust = $IPisMust;
46 /* All types with required attrs */
47 $this->RecordTypes['aRecord'] = "aRecord"; // ok
48 $this->RecordTypes['mDRecord'] = "mDRecord"; // ok
49 $this->RecordTypes['mXRecord'] = "mXRecord"; // ok
50 $this->RecordTypes['nSRecord'] = "nSRecord"; // ok
51 $this->RecordTypes['pTRRecord'] = "relativeDomainName";// ok
52 $this->RecordTypes['hInfoRecord'] = "hInfoRecord"; // ok
53 $this->RecordTypes['mInfoRecord'] = "mInfoRecord"; // ok
54 $this->RecordTypes['cNAMERecord'] = "relativeDomainName";// ok
55 $this->RecordTypes['tXTRecord'] = "tXTRecord"; // ok
56 $this->RecordTypes['aFSDBRecord'] = "aFSDBRecord"; // ok
57 $this->RecordTypes['SigRecord'] = "SigRecord"; // ok
58 $this->RecordTypes['KeyRecord'] = "KeyRecord"; // ok
59 $this->RecordTypes['aAAARecord'] = "aAAARecord"; // ok
60 $this->RecordTypes['LocRecord'] = "LocRecord"; // ok
61 $this->RecordTypes['nXTRecord'] = "nXTRecord"; // ok
62 $this->RecordTypes['sRVRecord'] = "sRVRecord"; // ok
63 $this->RecordTypes['nAPTRRecord'] = "nAPTRRecord"; // ok
64 $this->RecordTypes['kXRecord'] = "kXRecord"; // ok
65 $this->RecordTypes['certRecord'] = "certRecord"; // ok
66 $this->RecordTypes['a6Record'] = "a6Record"; // ok
67 $this->RecordTypes['dSRecord'] = "dSRecord"; // ok
68 $this->RecordTypes['sSHFPRecord'] = "sSHFPRecord"; // ok
69 $this->RecordTypes['rRSIGRecord'] = "rRSIGRecord"; // ok
70 $this->RecordTypes['nSECRecord'] = "nSECRecord"; // ok
72 /* Get all available zones */
73 if(empty($this->cn)&&(isset($this->attrs['cn'][0]))){
74 $this->cn = $this->attrs['cn'][0];
75 }
76 $this->Zones = $this->get_Zones();
77 $types = array();
79 /* Get all records */
80 $ldap = $this->config->get_ldap_link();
81 $ldap->cd($this->dn);
82 $ldap->search("(&(objectClass=dNSZone)(zoneName=*)(!(relativeDomainName=@)))",array("*"));
84 while($attrs = $ldap->fetch()){
85 /* If relative domainname == cn
86 * Try to read dnsclass / TTl / zone
87 */
88 if($attrs['relativeDomainName'][0] == $this->cn){
89 /* Get class */
90 if(isset($attrs['dNSClass'][0])){
91 $this->dNSClass = $attrs['dNSClass'][0];
92 }
93 /* Get Zone*/
94 if(isset($attrs['zoneName'][0])){
95 $this->zoneName = $attrs['zoneName'][0];
96 }
97 /* Get ttl */
98 if(isset($attrs['dNSTTL'][0])){
99 $this->dNSTTL = $attrs['dNSTTL'][0];
100 }
101 }
103 /* Create list with all used records */
104 foreach($this->RecordTypes as $name => $value){
106 /* If there is a record attribute */
107 if(isset($attrs[$name])){
110 /* get all entries */
111 for($i = 0 ; $i < $attrs[$value]['count']; $i ++){
112 if(($value == "aRecord")&&($this->ipHostNumber==$attrs[$value][$i])){
113 continue;
114 }
115 $types[] =array("type"=>$name,"inittype"=>$name,"value"=>$attrs[$value][$i],"status"=>"edited","dn"=>$attrs['dn']);
116 }
117 }
118 }
119 }
121 /* If there is at least one entry in this -> types, we have DNS enabled */
122 $this->types = $types;
123 if(count($this->types) == 0){
124 $this->DNS_is_account = false;
125 }else{
126 $this->DNS_is_account = true;
127 }
129 /* Store initally account settings */
130 $this->DNSinitially_was_account = $this->DNS_is_account;
131 }
133 function execute()
134 {
135 /* Call parent execute */
136 $smarty= get_smarty();
137 $display= "";
139 /* Add new empty array with status new, to our record list */
140 if(isset($_POST['AddNewRecord'])){
141 $this->types[] =array("type"=>"aRecord","value"=>"","status"=>"new");
142 }
144 /* Handle all posts */
145 $only_once =true;
146 foreach($_POST as $name => $value){
148 /* Check if we have to delete a record entry */
149 if((preg_match("/RemoveRecord_/",$name))&&($only_once)) {
151 /* Avoid performing this once again */
152 $only_once = false;
154 /* Extract id for specified entry */
155 $id = preg_replace("/RemoveRecord_/","",$name);
156 $id = preg_replace("/_.*$/","",$id);
158 /* Delete this record, mark edited entries to be able to delete them */
159 if(isset($this->types[$id])){
160 if($this->types[$id]['status'] == "edited"){
161 $this->types[$id]['status'] = "deleted";
162 }else{
163 unset($this->types[$id]);
164 }
165 }
166 }
167 }
169 /* Assign smarty all non DNs attributes */
170 foreach($this->attributes as $attr){
171 $smarty->assign($attr,$this->$attr);
172 }
174 /* Assign smarty all DNS attributes */
175 foreach($this->DNSattributes as $attr){
176 $smarty->assign($attr,$this->$attr);
177 }
179 /* Assign all needed vars */
180 $smarty->assign("DNSAccount",$this->DNS_is_account);
181 $smarty->assign("Zones",$this->Zones);
182 $smarty->assign("ZoneKeys",($this->Zones));
183 $smarty->assign("IPisMust",(($this->IPisMust)||($this->DNS_is_account)));
184 $changeStateForRecords ="";
185 $smarty->assign("records",$this->generateRecordsList(&$changeStateForRecords));
186 $smarty->assign("changeStateForRecords",$changeStateForRecords);
187 // $smarty->assign("dNSClasses",array("IN"=>"IN"));
188 $smarty->assign("staticAddress","<font class=\"must\">*</font>");
189 $display.= $smarty->fetch(get_template_path('network.tpl', TRUE));
190 return($display);
191 }
193 function remove_from_parent()
194 {
195 $ldap = $this->config->get_ldap_link();
196 $ldap->cd($this->orig_dn);
197 $ldap->search("(&(objectClass=dNSZone)(zoneName=*)(!(relativeDomainName=@)))",array("relativeDomainName","zoneName"));
198 while($attr = $ldap->fetch()){
199 $ldap->cd($attr['dn']);
200 $ldap->rmDir($attr['dn']);
201 }
202 }
204 /* Save data to object */
205 function save_object()
206 {
207 /* Save all posted vars */
208 plugin::save_object();
210 /* Ge all non dns attributes (IP/MAC)*/
211 foreach($this->attributes as $attr){
212 if(isset($_POST[$attr])){
213 $this->$attr = $_POST[$attr];
214 }
215 }
217 /* Get dns attributes */
218 if(isset($_POST['network_tpl_posted'])){
220 /* Check for posted record changes */
221 foreach($this->types as $key => $value){
223 /* Check if type has changed */
224 if(isset($_POST['RecordTypeSelectedFor_'.$key])){
225 $this->types[$key]['type'] = $_POST['RecordTypeSelectedFor_'.$key];
226 }
227 /* Check if value has changed */
228 if(isset($_POST['RecordValue_'.$key])){
229 $this->types[$key]['value'] = $_POST['RecordValue_'.$key];
230 }
231 }
233 /* Get all basic DNS attributes (TTL, Clas ..)*/
234 foreach($this->DNSattributes as $attr){
235 if(isset($_POST[$attr])){
236 $this->$attr = $_POST[$attr];
237 }
238 }
240 /* Enable diable DNS */
241 if(isset($_POST['enableDNS'])){
242 $this->DNS_is_account = true;
243 }else{
244 $this->DNS_is_account = false;
245 }
246 }
247 }
250 /* Check supplied data */
251 function check()
252 {
253 $message= array();
256 if(($this->IPisMust)||($this->DNS_is_account)){
257 /* Check if ip is empty */
258 if ($this->ipHostNumber == "" && chkacl ($this->acl, "ipHostNumber") == ""){
259 $message[]= _("The required field 'IP-address' is not set.");
260 }
262 /* check if given ip is valid ip*/
263 $num="(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])";
264 if (!preg_match("/^$num\\.$num\\.$num\\.$num$/", $this->ipHostNumber)){
265 $message[]= _("Wrong IP format in field IP-address.");
266 }
267 }
269 /* Check if mac is empty */
270 if ($this->macAddress == "" && chkacl ($this->acl, "macAddress") == ""){
271 $message[]= _("The required field 'MAC-address' is not set.");
272 }
274 /* Check if given mac is valid mac */
275 $tr = count(split(":",$this->macAddress));
276 if($tr!=6){
277 $message[]=(_("The given macaddress is invalid. There must be 6 1byte segments seperated by ':'."));
278 }
280 /* only perfrom this checks if this is a valid DNS account */
281 if($this->DNS_is_account){
282 foreach($this->types as $name => $values){
284 /* Check if there is an aRecord defined which uses the same IP as used in IPhostAddress */
285 if(($values['type'] == "aRecord")&&($values['value'] == $this->ipHostNumber)&&($values['status']!="deleted")){
286 $message[]=sprintf(_("The device IP '%s' is added as 'A Record', this will be done automatically, please remove the record."),
287 $this->ipHostNumber);
288 }
290 /* only lower-case is allowed in record entries ... */
291 if($values['value'] != strtolower($values['value'])){
292 $message[] = sprintf(_("Only lowercase is allowed, please check your '%ss'."),$values['type']);
293 }
294 }
295 }
297 return ($message);
298 }
301 /* Save to LDAP */
302 function save($dn)
303 {
304 $ldap= $this->config->get_ldap_link();
306 /*******************/
307 /* IP-MAC HANDLING */
308 /*******************/
310 /* $dn was posted as parameter */
311 $this->dn = $dn;
313 /* Save DNS setting & ip/Mac*/
314 plugin::save();
316 /* Write back to ldap */
317 $ldap->cd($this->dn);
318 $this->cleanup();
319 $ldap->modify ($this->attrs);
322 /****************/
323 /* DNS HANDLING */
324 /****************/
326 /* If isn't DNS account but initially was DNS account
327 remove all DNS entries
328 */
329 if(!$this->DNS_is_account){
330 if($this->DNSinitially_was_account){
331 $tmp = array();
332 foreach($this->types as $type){
333 $dn = $type['dn'];
334 if(!isset($tmp[$dn])) {
335 $ldap->cd($dn);
336 $ldap->rmDir($dn);
337 }
338 $tmp[$dn]=$dn;
339 }
340 }
341 }else{
343 /* DNS is enabled, check what we have to do */
344 $delete = array();
346 /* Generate a list of new ldap entries,
347 & $delete contains all dns which should be deleted
348 */
349 $entries = $this->generate_LDAP_entries(&$delete);
351 /* Delete dns */
352 foreach($delete as $dn => $del){
353 $ldap->cd($dn);
354 $ldap->rmDir($dn);
355 }
357 /* Add || Update new DNS entries */
358 foreach($entries as $dn => $attrs){
359 $ldap->cd($dn);
360 $ldap->cat($dn);
362 if(count($ldap->fetch())){
363 $ldap->cd($dn);
364 // $this->cleanup();
365 $ldap->modify ($attrs);
367 }else{
368 $ldap->cd($dn);
369 $ldap->add($attrs);
370 }
371 }
372 }
373 if($ldap->get_error() != "Success"){
374 show_ldap_error($ldap->get_error());
375 }
377 }
379 /* Create html table with all used record types
380 */
381 function generateRecordsList($changeStateForRecords)
382 {
383 $changeStateForRecords = "";
385 if(!$this->DNS_is_account) {
386 $str = "<input type='submit' value='"._("Add")."' name='AddNewRecord' id='AddNewRecord' disabled>";
387 return $str;
388 }
390 $str = "<table summary='' width='100%'>";
391 foreach($this->types as $key => $entry){
392 if($entry['status'] == "deleted") continue;
394 $changeStateForRecords.= "changeState('RecordTypeSelectedFor_".$key."');\n";
395 $changeStateForRecords.= "changeState('RecordValue_".$key."');\n";
396 $changeStateForRecords.= "changeState('RemoveRecord_".$key."');\n";
398 $str.=" <tr>".
399 " <td>".$this->generateRecordListBox($entry['type'],"RecordTypeSelectedFor_".$key)."</td>".
400 " <td><input type='text' value='".$entry['value']."' name='RecordValue_".$key."' id='RecordValue_".$key."'></td>".
401 " <td><input type='submit' name='RemoveRecord_".$key."' value='"._("Delete")."' id='RemoveRecord_".$key."'></td>".
402 "</tr>";
403 }
405 $str.= " <tr>".
406 " <td colspan=2 width='50%'></td><td>".
407 " <input type='submit' value='"._("Add")."' name='AddNewRecord'>".
408 " </td>".
409 " </tr>".
410 "</table>";
411 return($str);
412 }
414 /* Create a html select box which allows us to select different types of records */
415 function generateRecordListBox($selected,$name)
416 {
417 $str = "<select name='".$name."' id='".$name."'>";
418 foreach($this->RecordTypes as $type => $value){
419 $use = "";
420 if($type == $selected){
421 $use = " selected ";
422 }
423 $str.="\n <option value='".$type."' ".$use.">".strtoupper(preg_replace("/record/i","",$type))."</option>";
424 }
425 $str.="</select>";
426 return($str);
427 }
429 /* return all Zone names */
430 function get_Zones()
431 {
432 $ret = array();
433 $ldap = $this->config->get_ldap_link();
434 $ldap-> cd ($this->config->current['BASE']);
435 $ldap->search("(&(objectClass=dNSZone)(sOARecord=*))",array("*"));
437 while($at = $ldap->fetch()){
438 if(preg_match("/\.in\-addr\.arpa/",$at['zoneName'][0])){
439 $ret[$at['relativeDomainName'][0]]['addr']= $at['zoneName'][0];
440 }else{
441 $ret[$at['relativeDomainName'][0]]['name']= $at['zoneName'][0];
442 }
443 }
445 $tmp =array();
446 foreach($ret as $name => $entry){
447 if((isset($entry['addr']))&&(isset($entry['name']))){
448 $tmp[$entry['addr']]=$entry['name'];
449 }
450 }
451 $ret = $tmp;
452 return($ret);
453 }
455 /* this is used to generate ldap friendly output of our
456 dns configuration
457 */
458 function generate_LDAP_entries($delete)
459 {
460 $entries = array();
461 $delete = array();
463 /* Generate Main Entry */
464 $dn = "relativeDomainName=".$this->cn.",".$this->dn;
465 $entries[$dn]['dNSClass'] = $this->dNSClass;
466 $entries[$dn]['zoneName'] = $this->zoneName;
467 $entries[$dn]['dNSTTL'] = $this->dNSTTL;
468 $entries[$dn]['relativeDomainName'] = $this->cn;
470 /* Generate cNAMERecord */
471 $aRecords = array();
472 foreach($this->types as $type){
473 if($type['type'] == "cNAMERecord"){
475 $Cdn = "relativeDomainName=".$type['value'].",".$this->dn;
476 if($type['status']=="deleted"){
477 $delete [$type['dn']] = $Cdn;
478 }else{
479 $entries[$Cdn] = $entries[$dn];
480 $entries[$Cdn]['relativeDomainName'] = $type['value'];
481 $entries[$Cdn]['cNAMERecord'] = $this->cn.".".$this->zoneName;
482 }
483 }
484 }
486 /* Generate tXTRecord */
487 $aRecords = array();
488 foreach($this->types as $type){
489 if(($type['type'] == "tXTRecord")&&($type['status']!="deleted")){
490 $entries[$dn]['tXTRecord'][] = $type['value'];
491 }
492 }
494 /* Generate mDRecord */
495 $aRecords = array();
496 foreach($this->types as $type){
497 if(($type['type'] == "mDRecord")&&($type['status']!="deleted")){
498 $entries[$dn]['mDRecord'][] = $type['value'];
499 }
500 }
502 /* Generate mXRecord */
503 $aRecords = array();
504 foreach($this->types as $type){
505 if(($type['type'] == "mXRecord")&&($type['status']!="deleted")){
506 $entries[$dn]['mXRecord'][] = $type['value'];
507 }
508 }
510 /* Generate hInfoRecord */
511 $aRecords = array();
512 foreach($this->types as $type){
513 if(($type['type'] == "hInfoRecord")&&($type['status']!="deleted")){
514 $entries[$dn]['hInfoRecord'][] = $type['value'];
515 }
516 }
518 /* Generate mInfoRecord */
519 $aRecords = array();
520 foreach($this->types as $type){
521 if(($type['type'] == "mInfoRecord")&&($type['status']!="deleted")){
522 $entries[$dn]['mInfoRecord'][] = $type['value'];
523 }
524 }
526 /* Generate aFSDBRecord */
527 $aRecords = array();
528 foreach($this->types as $type){
529 if(($type['type'] == "aFSDBRecord")&&($type['status']!="deleted")){
530 $entries[$dn]['aFSDBRecord'][] = $type['value'];
531 }
532 }
534 /* Generate some attrs */
535 $arr = array("SigRecord","KeyRecord","aAAARecord","nSRecord",
536 "LocRecord","nXTRecord","sRVRecord","nAPTRRecord","kXRecord","certRecord","a6Record","dSRecord","sSHFPRecord","rRSIGRecord","nSECRecord");
537 $aRecords = array();
538 foreach($arr as $ar){
539 foreach($this->types as $type){
540 if(($type['type'] == $ar)&&($type['status']!="deleted")){
541 $entries[$dn][$ar][] = $type['value'];
542 }
543 }
544 }
547 /* Generate A Records (IP Address relation) */
548 $aRecords = array();
549 foreach($this->types as $type){
550 if(($type['type'] == "aRecord")&&($type['status']!="deleted")){
551 $aRecords[] = $type['value'];
552 }
553 }
554 if(count($aRecords)){
556 /* Add ipHostNumber as default aRecord */
557 $aRecords[] = $this->ipHostNumber;
559 $dn = "relativeDomainName=".$this->cn.",".$this->dn;
560 foreach($aRecords as $rec){
561 $entries[$dn]['aRecord'][] = $rec;
562 }
563 }
565 /* Generate pTRRecord Records */
566 foreach($this->types as $type){
567 if($type['type'] == "pTRRecord"){
568 $PTRdn= "relativeDomainName=".$type['value'].",".$this->dn;
569 if($type['status']=="deleted"){
570 $delete [$type['dn']] = $PTRdn;
571 }else{
572 $zones = array_flip($this->Zones);
573 $zone = $zones[$this->zoneName];
574 $entries[$PTRdn]['relativeDomainName'] = $type['value'];
575 $entries[$PTRdn]['pTRRecord'] = $this->cn.".".$this->zoneName;
576 $entries[$PTRdn]['zoneName'] = $zone;
577 }
578 }
579 }
581 /* add ObjectClasses */
582 foreach($entries as $key => $entry ){
583 $entries[$key]['objectClass']=array("top","dNSZone");
584 $entries[$key] = array_reverse($entries[$key]);
585 }
587 /* Check if record type has changed, and if we need to delete this record attribute from ldap entry */
588 foreach($this->types as $type){
589 if(isset($type['inittype'])){
590 if(!isset($entries[$dn][$type['inittype']])){
591 $entries[$dn][$type['inittype']] = array();
592 }
593 }
594 }
596 return($entries);
597 }
598 }
600 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
601 ?>