13c2956007036ade69e71bf3cef73de14f1d76d7
1 <?php
3 class servdns 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 = FALSE;
12 var $attributes = array("");
13 var $objectclasses = array("whatever");
15 var $RecordTypes = array();
17 var $Zones = array();
18 var $dialog = NULL;
20 var $usedDNS = array();
22 var $orig_dn = "";
24 var $DNSinitially_was_account;
27 function servdns ($config, $dn= NULL)
28 {
29 plugin::plugin ($config, $dn);
31 $this->orig_dn = $dn;
33 /* All types with required attrs */
34 $this->RecordTypes['aRecord'] = "aRecord"; // ok
35 $this->RecordTypes['mDRecord'] = "mDRecord"; // ok
36 $this->RecordTypes['mXRecord'] = "mXRecord"; // ok
37 $this->RecordTypes['nSRecord'] = "nSRecord"; // ok
38 $this->RecordTypes['pTRRecord'] = "relativeDomainName";// ok
39 $this->RecordTypes['hInfoRecord'] = "hInfoRecord"; // ok
40 $this->RecordTypes['mInfoRecord'] = "mInfoRecord"; // ok
41 $this->RecordTypes['tXTRecord'] = "tXTRecord"; // ok
42 $this->RecordTypes['aFSDBRecord'] = "aFSDBRecord"; // ok
43 $this->RecordTypes['SigRecord'] = "SigRecord"; // ok
44 $this->RecordTypes['KeyRecord'] = "KeyRecord"; // ok
45 $this->RecordTypes['aAAARecord'] = "aAAARecord"; // ok
46 $this->RecordTypes['LocRecord'] = "LocRecord"; // ok
47 $this->RecordTypes['nXTRecord'] = "nXTRecord"; // ok
48 $this->RecordTypes['sRVRecord'] = "sRVRecord"; // ok
49 $this->RecordTypes['nAPTRRecord'] = "nAPTRRecord"; // ok
50 $this->RecordTypes['kXRecord'] = "kXRecord"; // ok
51 $this->RecordTypes['certRecord'] = "certRecord"; // ok
52 $this->RecordTypes['a6Record'] = "a6Record"; // ok
53 $this->RecordTypes['dSRecord'] = "dSRecord"; // ok
54 $this->RecordTypes['sSHFPRecord'] = "sSHFPRecord"; // ok
55 $this->RecordTypes['rRSIGRecord'] = "rRSIGRecord"; // ok
56 $this->RecordTypes['nSECRecord'] = "nSECRecord"; // ok
58 $types = array();
60 /* Get all records */
61 $ldap = $this->config->get_ldap_link();
62 $ldap->cd($this->dn);
63 $ldap->search("(&(objectClass=dNSZone)(relativeDomainName=@))",array("*"));
65 while($attrs = $ldap->fetch()){
66 /* If relative domainname
67 * Try to read dnsclass / TTl / zone
68 */
69 $this->usedDNS[$attrs['dn']] = $attrs['dn'];
70 if((isset($attrs['tXTRecord'][0]))&&(preg_match("/zoneName\=/",$attrs['tXTRecord'][0]))){
71 $zoneName= preg_replace("/zoneName\=/","",$attrs['tXTRecord'][0]);
72 $z = preg_replace("/\.in\-addr\.arpa/","",$attrs['zoneName'][0]);
74 $z = $this->FlipIp($z);
76 $types[$zoneName]['ReverseZone'] = $z;
77 $types[$zoneName]['ReverseDN'] = $attrs['dn'];
78 }else{
80 /* Generate SOA entry */
81 if(isset($attrs['sOARecord'][0])){
82 $tmp = split("\ ",$attrs['sOARecord'][0]) ;
83 $tmp2 = array();
84 $ar = array("0"=>"sOAprimary","1"=>"sOAmail","2"=>"sOAserial","3"=>"sOArefresh","4"=>"sOAretry","5"=>"sOAexpire","6"=>"sOAttl");
86 /* Assign soa vars */
87 foreach($ar as $key => $name){
88 if(isset($tmp[$key])){
89 $types[$attrs['zoneName'][0]][$name] = $tmp[$key];
90 }else{
91 $types[$attrs['zoneName'][0]][$name] = "";
92 }
93 }
94 }
96 /* Set TTL value */
97 if(isset($attrs['dNSTTL'][0])){
98 $types[$attrs['zoneName'][0]]['dNSTTL'] = $attrs['dNSTTL'][0];
99 }
101 /* Set dns Class*/
102 if(isset($attrs['dNSClass'][0])){
103 $types[$attrs['zoneName'][0]]['dNSClass'] = $attrs['dNSClass'][0];
104 }
106 /* Set zone Name */
107 if(isset($attrs['zoneName'][0])){
108 $types[$attrs['zoneName'][0]]['zoneName'] = $attrs['zoneName'][0];
109 }
111 /* Create list with all used records */
112 foreach($this->RecordTypes as $name => $value){
114 /* If there is a record attribute */
115 if(isset($attrs[$name])){
117 $types[$attrs['zoneName'][0]]['Records']=array();
119 /* get all entries */
120 for($i = 0 ; $i < $attrs[$value]['count']; $i ++){
121 $types[$attrs['zoneName'][0]]['Records'][] =array("type" =>$name,
122 "inittype" =>$name,
123 "value" =>$attrs[$value][$i],
124 "status" =>"edited",
125 "dn" =>$attrs['dn']);
126 }
127 }
128 }
129 }
130 }
132 /* If there is at least one entry in this -> types, we have DNS enabled */
133 $this->Zones = $types;
134 if(count($this->Zones) == 0){
135 $this->is_account = false;
136 }else{
137 $this->is_account = true;
138 }
140 /* Store initally account settings */
141 $this->DNSinitially_was_account = $this->is_account;
142 }
145 /* this is used to flip the ip address for example
146 12.3.45 -> 54.3.12
147 Because some entries (like zones) are store like that 54.3.12.in-addr.arpa
148 but we want to display 12.3.45.
149 */
150 function FlipIp($ip)
151 {
152 $tmp = array_reverse(split("\.",$ip));
153 $new = "";
154 foreach($tmp as $section){
155 $new .= $section.".";
156 }
157 return(preg_replace("/.$/","",$new));
158 }
160 function execute()
161 {
162 /* Call parent execute */
163 plugin::execute();
165 /* Fill templating stuff */
166 $smarty= get_smarty();
167 $display= "";
169 /* Do we need to flip is_account state? */
170 if (isset($_POST['modify_state'])){
171 $this->is_account= !$this->is_account;
172 }
174 /* Show tab dialog headers */
175 if ($this->is_account){
176 $display= $this->show_header(_("Remove DNS service"),
177 _("This server has DNS features enabled. You can disable them by clicking below."));
178 } else {
179 $display= $this->show_header(_("Add DNS service"),
180 _("This server has DNS features disabled. You can enable them by clicking below."));
181 return ($display);
182 }
184 /* Edited or Added zone hould be saved saved */
185 if(isset($_POST['SaveZoneChanges'])){
186 $this->dialog->save_object();
188 /* Check if noting went wrong */
189 if(count($this->dialog->check())){
190 foreach($this->dialog->check() as $msgs){
191 print_red($msgs);
192 }
193 }else{
195 /* add new/edited zone */
196 $ret = $this->dialog->save();
197 unset($this->Zones[$this->dialog->InitiallyZoneName]);
198 $this->Zones[$ret['zoneName']] = $ret;
199 $this->dialog = NULL;
200 }
201 }
203 /* Cancel zone edit / new */
204 if(isset($_POST['CancelZoneChanges'])){
205 $this->dialog = NULL;
206 }
208 /* Add empty new zone */
209 if(isset($_POST['AddZone'])){
210 $this->dialog = new servdnseditZone($this->config,$this->dn,$this->RecordTypes);
211 }
213 /* Check for edit zone request */
214 $once = false;
215 foreach( $_POST as $name => $value){
217 /* check all post for edit request */
218 if(preg_match("/^editZone_/",$name)&&!$once){
219 $once =true;
220 $tmp = preg_replace("/^editZone_/","",$name);
221 $tmp = base64_decode(preg_replace("/_.*$/","",$tmp));
222 $this->dialog= new servdnseditZone($this->config,$this->dn,$this->RecordTypes,$this->Zones[$tmp]);
223 }
225 /* check posts for delete zone */
226 if(preg_match("/^delZone_/",$name)&&!$once){
229 $once =true;
230 $tmp = preg_replace("/^delZone_/","",$name);
231 $tmp = base64_decode(preg_replace("/_.*$/","",$tmp));
233 $zones = $this->getUsedZoneNames();
234 $rev = $this->Zones[$tmp]['ReverseZone'];
235 $res = array_merge(($zones[$tmp]),($zones[$rev.".in-addr.arpa"]));
237 if(count($res)){
238 $i = 2;
239 $str ="";
240 foreach($res as $dn){
241 if($i > 0 ){
242 $i --;
243 $str.=$dn." ";
244 }
245 }
246 if(count($res)> 2) $str .=" ... ";
247 print_red(sprintf(_("Can't delete the selected zone, because it is still in use by these entry/entries '%s'"),trim($str)));
248 }else{
249 unset($this->Zones[$tmp]);
250 }
251 }
252 }
254 /* Show dialog */
255 if($this->dialog!= NULL){
256 $this->dialog->save_object();
257 $this->dialog->parent = $this;
258 return($this->dialog->execute());
259 }
261 /* Create Listbox with existing Zones */
262 $ZoneList = new divSelectBox("dNSZones");
263 $ZoneList -> SetHeight(254);
265 /* Add entries to divlist*/
266 $editImg = "<input type='image' src='images/edit.png' name='editZone_%s'>
267 <input type='image' src='images/edittrash.png' name='delZone_%s'>";
268 foreach($this->Zones as $zone => $values ){
269 $ZoneList->AddEntry(array(
270 array("string" => $zone),
271 array("string" => _("Reverse zone")." : ".$values['ReverseZone']),
272 array("string" => _("TTL")." : ".$values['dNSTTL']),
273 array("string" => _("Class")." : ".$values['dNSClass']),
274 array("string" =>str_replace("%s",base64_encode($zone),$editImg))
275 ));
276 }
278 /* Display tempalte */
279 $smarty->assign("ZoneList",$ZoneList->DrawList());
280 $display.= $smarty->fetch(get_template_path('servdns.tpl', TRUE));
281 return($display);
282 }
285 /* This funtion returns all used Zonenames */
286 function getUsedZoneNames()
287 {
288 $ret = array();
289 $ldap = $this->config->get_ldap_link();
290 $ldap->cd($this->config->current['BASE']);
291 $ldap->search("(&(objectClass=dNSZone)(!(relativeDomainName=@))(zoneName=*))",array("zoneName","relativeDomainName","tXTRecord"));
292 while($attr = $ldap->fetch()){
293 if(preg_match("/in-addr\.arpa/",$attr['zoneName'][0])){
294 $ret[$attr['zoneName'][0]][] = $attr['dn'];
295 }else{
296 $ret[$attr['zoneName'][0]][] = $attr['dn'];
297 }
298 }
299 return($ret);
300 }
303 /* Remove dns service */
304 function remove_from_parent()
305 {
306 if(!$this->DNSinitially_was_account){
307 return;
308 }
310 $ldap = $this->config->get_ldap_link();
311 $ldap->cd($this->config->current['BASE']);
312 foreach($this->usedDNS as $dn){
313 $ldap->cd($dn);
314 $ldap->rmdir_recursive($dn);
315 }
317 $ldap = $this->config->get_ldap_link();
318 $ldap->cd($this->orig_dn);
319 $ldap->search("(&(objectClass=dNSZone)(zoneName=*)(relativeDomainName=@))",array("relativeDomainName","zoneName"));
320 while($attr = $ldap->fetch()){
321 $ldap->cd($attr['dn']);
322 $ldap->rmDir($attr['dn']);
323 }
326 show_ldap_error($ldap->get_error());
327 }
330 /* Save data to object */
331 function save_object()
332 {
333 }
336 /* Check supplied data */
337 function check()
338 {
339 $message= array();
340 return ($message);
341 }
344 /* Save to LDAP */
345 function save()
346 {
347 /* Ldap conenction / var initialization */
348 $ldap = $this->config->get_ldap_link();
349 $ldap->cd($this->config->current['BASE']);
350 $actions =array("update"=>array(),"add"=>array(),"delete"=>array());
352 /* Generate entries for all zones, and check if they must be updated deleted added */
353 foreach($this->Zones as $zone){
355 /* Get ldap syntax */
356 $tmp = $this->generate_LDAP_entries($zone);
358 /* Check if dn is new, or if entry was edited */
359 foreach($tmp as $key => $values){
360 if(isset($this->usedDNS[$key])){
361 $actions['update'][$key]=$values;
362 unset($this->usedDNS[$key]);
363 }else{
364 $actions['add'][$key] = $values;
365 }
366 }
367 }
369 /* Check which dns are not used anymore ...*/
370 foreach($this->usedDNS as $key => $values){
371 $actions['delete'][$key] = $values;
372 }
374 /* Remove deleted zones */
375 foreach($actions['delete'] as $dn => $attrs){
376 $ldap->cd($dn);
377 $ldap->rmdir_recursive($dn);
378 }
380 /* Add new zones */
381 foreach($actions['add'] as $dn => $attrs){
382 $ldap->cd($this->config->current['BASE']);
383 // $ldap->create_missing_trees($dn);
384 $ldap->cd($dn);
385 $ldap->add($attrs);
386 }
388 /* Update existing entries */
389 foreach($actions['update'] as $dn => $attrs){
390 $ldap->cd($dn);
391 $ldap->modify($attrs);
392 }
393 show_ldap_error($ldap->get_error());
394 }
397 /* This function generates ldap friendly output
398 of all changes for a single zone (reverse and forward)
399 */
400 function generate_LDAP_entries($zone)
401 {
402 $tmp = array();
403 $tmp['objectClass'] = array("top","dNSZone");
404 $tmp['dNSTTL'] = $zone['dNSTTL'];
405 $tmp['dNSClass'] = $zone['dNSClass'];
406 $tmp['relativeDomainName'] = "@";//$zone['relativeDomainName'];
408 $str = "";
409 foreach(array("sOAprimary","sOAmail","sOAserial","sOArefresh","sOAretry","sOAexpire","sOAttl") as $name){
410 $str .= $zone[$name]." ";
411 }
412 $tmp['sOARecord'] = $str;
415 /* Generate Record entries */
416 $arr = array("SigRecord","KeyRecord","aAAARecord","nSRecord","iaFSDBRecord","mInfoRecord","hInfoRecord","mXRecord","mDRecord","tXTRecord",
417 "LocRecord","nXTRecord","sRVRecord","nAPTRRecord","kXRecord","certRecord","a6Record","dSRecord","sSHFPRecord","rRSIGRecord","nSECRecord");
418 $aRecords = array();
419 foreach($arr as $ar){
420 if((isset($zone['Records']))&&(is_array($zone['Records']))){
421 foreach($zone['Records'] as $type){
422 if(($type['type'] == $ar)&&($type['status']!="deleted")){
423 $tmp[$ar][] = $type['value'];
424 }
425 }
426 }
427 }
429 /* Check if there are records removed,
430 if there are some removed records, the append an array
431 to ensure that these record types are deleted
432 */
433 if((isset($zone['Records']))&&(is_array($zone['Records']))){
434 foreach($zone['Records'] as $type){
435 if((isset($type['inittype']))&&($type['inittype']!="")){
436 if($type['type'] != $type['inittype']){
437 $tmp[$type['inittype']] = array();
438 }
439 }
440 }
441 }
443 /* generate forward entry */
444 $dn = "zoneName=".$zone['zoneName'].",".$this->dn;
445 $tmp2[$dn] = $tmp;
446 $tmp2[$dn]['zoneName'] = $zone['zoneName'];
448 /* generate reverse entry */
449 $dn = "zoneName=".$this->FlipIp($zone['ReverseZone']).".in-addr.arpa,".$this->dn;
450 $tmp2[$dn] = $tmp;
451 $tmp2[$dn]['tXTRecord'] ="zoneName=".$zone['zoneName'];
452 $tmp2[$dn]['zoneName'] = $this->FlipIp($zone['ReverseZone']).".in-addr.arpa";
454 return($tmp2);
455 }
459 }
461 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
462 ?>