1 <?php
3 class servdns extends goService
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();
16 var $Zones = array();
17 var $dialog = NULL;
19 var $orig_dn = "";
21 var $initially_was_account;
23 /* ServerService tab vars */
24 var $conflicts = array("servdns");
25 var $DisplayName = "";
26 var $StatusFlag = "";
27 var $view_logged = FALSE;
29 var $dns_server_list = array("ENTRIES"=> array(),"FOR_LIST"=> array());
30 var $take_over_id = -1;
33 function servdns (&$config, $dn= NULL, $parent= NULL)
34 {
35 plugin::plugin ($config, $dn, $parent);
37 $this->DisplayName = _("DNS service");
39 $this->orig_dn = $dn;
41 /* Get record types for zones
42 */
43 $this->RecordTypes = getDnsRecordTypes(true);
45 /* Get all zone Informations
46 */
47 $this->Zones = getDNSZoneEntries($config,$dn);
49 /* If there is at least one entry in this -> types, we have DNS enabled
50 */
51 if(count($this->Zones) == 0){
52 $this->is_account = false;
53 $this->dns_server_list = $this->get_list_of_dns_servers();
54 }else{
55 $this->is_account = true;
56 }
57 $this->initially_was_account = $this->is_account;
58 }
61 function get_list_of_dns_servers()
62 {
63 $ret = array("ENTRIES"=> array(),"FOR_LIST"=> array());
64 $ldap = $this->config->get_ldap_link();
65 $ldap->cd($this->config->current['BASE']);
66 $ldap->search("(&(objectClass=dNSZone)(zoneName=*))",array("dn","zoneName"));
67 $dns = array();
68 while($attrs = $ldap->fetch()){
69 /* Skip own config */
70 if($this->dn != "new" && preg_match("/".normalizePreg($this->dn)."$/",$attrs['dn'])){
71 continue;
72 }
73 $dn = preg_replace("/^zoneName=[^,]+,/","",$attrs['dn']);
74 if(preg_match("/^cn=/",$dn) && !in_array($dn,$dns)){
75 $dns[] = $dn;
76 }
77 }
78 $i = 0;
79 foreach($dns as $dn){
80 $ldap->cat($dn,array('*'));
81 if($ldap->count()){
82 $i ++;
83 $attrs = $ldap->fetch();
84 $ret['ENTRIES'][$i] = $attrs;
85 $ret['FOR_LIST'][$i] = $attrs['cn'][0];
86 }
87 }
88 return($ret);
89 }
92 function get_dns_info_string($id)
93 {
94 $ret="";
95 $ldap = $this->config->get_ldap_link();
96 $ldap->cd($this->dns_server_list['ENTRIES'][$id]['dn']);
97 $ldap->search("(|(zoneName=*)(relativeDomainName=*))",array("dn"));
98 while($attrs = $ldap->fetch()){
99 $ret .= $attrs['dn']."\n";
100 }
101 return($ret);
102 }
105 function execute()
106 {
107 /* Call parent execute
108 */
109 plugin::execute();
111 if($this->is_account && !$this->view_logged){
112 $this->view_logged = TRUE;
113 new log("view","server/".get_class($this),$this->dn);
114 }
116 /* Fill templating stuff
117 */
118 $smarty= get_smarty();
119 $smarty->assign("dns_take_over",FALSE);
120 $smarty->assign("is_createable",$this->acl_is_createable());
121 $display= "";
124 $this->initially_was_account= $this->is_account;
125 /*****************/
126 /* Handle Take Over Actions
127 /*****************/
129 /* Give smarty the required informations */
130 $smarty->assign("dns_server_list", $this->dns_server_list['FOR_LIST']);
131 $smarty->assign("dns_server_list_cnt", count($this->dns_server_list['FOR_LIST']));
133 /* Take over requested, save id */
134 if(isset($_POST['take_over_src']) && isset($_POST['take_over'])){
135 $id = $_POST['take_over_src'];
136 if(isset($this->dns_server_list['ENTRIES'][$id])){
137 $this->take_over_id = $id;
138 }
139 }
141 /* Abort take over action */
142 if(isset($_POST['cancel_take_over'])){
143 $this->dialog =false;
144 $this->take_over_id = -1;
145 $this->dns_server_list = $this->get_list_of_dns_servers();
146 }
148 /* Display informartion about take over that will be started when saving this server
149 * and hide default dns output
150 */
151 if($this->take_over_id != -1){
152 $this->dialog = FALSE;
153 $id = $this->take_over_id;
154 $info = $this->get_dns_info_string($id);
155 $smarty->assign("dns_take_over",TRUE);
156 $smarty->assign("info",$info);
157 $warning = sprintf(_("You are going to migrate the DNS setup from server '%s'."),$this->dns_server_list['ENTRIES'][$id]['cn'][0]);
158 $warning2 = _("The migration will be startet when you save this system. To cancel this action, use the cancel button below.");
159 $smarty->assign("warning",$warning);
160 $smarty->assign("warning2",$warning2);
161 return($smarty->fetch(get_template_path('servdns.tpl', TRUE)));
162 }
165 /* Do we need to flip is_account state?
166 */
167 if (isset($_POST['modify_state'])){
168 $this->is_account= !$this->is_account;
169 }
171 if ($this->is_account){
172 $display= $this->show_disable_header(_("Remove DNS service"),
173 _("This server has DNS features enabled. You can disable them by clicking below."));
174 } else {
175 $display= $this->show_enable_header(_("Add DNS service"),
176 _("This server has DNS features disabled. You can enable them by clicking below."));
177 return ($display);
178 }
181 /* Edited or Added zone
182 */
183 if(isset($_POST['SaveZoneChanges'])){
184 $this->dialog->save_object();
186 /* Check for errors
187 */
188 if(count($this->dialog->check())){
189 foreach($this->dialog->check() as $msgs){
190 print_red($msgs);
191 }
192 }else{
193 /* add new/edited zone
194 */
195 $ret = $this->dialog->save();
196 if(!$this->dialog->isNew){
197 unset($this->Zones[$this->dialog->OldZoneName]);
198 }
199 $this->Zones[$ret['zoneName']] = $ret;
200 $this->dialog = NULL;
201 }
202 }
204 /* Cancel zone edit / new
205 */
206 if(isset($_POST['CancelZoneChanges'])){
207 $this->dialog = NULL;
208 }
210 /* Add empty new zone
211 */
212 if(isset($_POST['AddZone'])){
213 $this->dialog = new servdnseditZone($this->config,$this->dn);
214 }
216 /* Check for edit zone request
217 */
218 $once = false;
219 foreach( $_POST as $name => $value){
221 /* check all post for edit request
222 */
223 if(preg_match("/^editZone_/",$name)&&!$once){
224 $once =true;
225 $tmp = preg_replace("/^editZone_/","",$name);
226 $tmp = base64_decode(preg_replace("/_.*$/","",$tmp));
227 $this->dialog= new servdnseditZone($this->config,$this->dn,$this->Zones[$tmp]);
228 }
230 /* check posts for delete zone
231 */
232 if(preg_match("/^delZone_/",$name)&&!$once){
234 $once =true;
235 $tmp = preg_replace("/^delZone_/","",$name);
236 $tmp = base64_decode(preg_replace("/_.*$/","",$tmp));
238 /* Initiate deletion
239 */
240 $this->RemoveZone($tmp);
241 }
242 }
244 if(isset($_GET['act']) && $_GET['act'] == "edit" && isset($_GET['id'])){
245 $id = base64_decode($_GET['id']);
246 if(isset($this->Zones[$id])){
247 $this->dialog= new servdnseditZone($this->config,$this->dn,$this->Zones[$id]);
248 }
249 }
251 if(isset($_GET['act']) && $_GET['act'] == "edit" && isset($_GET['id'])){
252 $id = base64_decode($_GET['id']);
253 if(isset($this->Zones[$id])){
254 $this->dialog= new servdnseditZone($this->config,$this->dn,$this->Zones[$id]);
255 }
256 }
258 /* Show dialog
259 */
260 if($this->dialog!= NULL){
261 $this->dialog->save_object();
262 $this->dialog->parent = $this;
263 return($this->dialog->execute());
264 }
266 /* Create Listbox with existing Zones
267 */
268 $ZoneList = new divSelectBox("dNSZones");
269 $ZoneList -> SetHeight(254);
271 /* Add entries to divlist
272 */
273 $editImg = "<input type='image' src='images/edit.png' name='editZone_%s'>";
274 if($this->acl_is_removeable()){
275 $editImg.= "<input type='image' src='images/edittrash.png' name='delZone_%s'>";
276 }
278 $link = "<a href='?plug=".$_GET['plug']."&act=edit&id=%s'>%s</a>";
279 foreach($this->Zones as $zone => $values ){
280 $ZoneList->AddEntry(array(
281 array("string" => sprintf($link,base64_encode($zone),($zone))),
282 array("string" => sprintf($link,base64_encode($zone),_("Reverse zone")." : ".($values['ReverseZone']))),
283 array("string" => _("TTL")." : ".$values['sOAttl']),
284 array("string" => _("Class")." : ".$values['dNSClass']),
285 array("string" =>str_replace("%s",base64_encode($zone),$editImg))
286 ));
287 }
289 /* Display tempalte
290 */
291 $smarty->assign("ZoneList",$ZoneList->DrawList());
292 $display.= $smarty->fetch(get_template_path('servdns.tpl', TRUE));
293 return($display);
294 }
297 /* Delete specified zone
298 */
299 function RemoveZone($id)
300 {
301 $zones = $this->getUsedZoneNames();
303 if(isset($this->Zones[$id]['InitialReverseZone'])){
304 $rev = FlipIp($this->Zones[$id]['InitialReverseZone']);
305 }else{
306 $rev = FlipIp($this->Zones[$id]['ReverseZone']);
307 }
309 $zonename = "";
310 if(isset($this->Zones[$id]['InitialzoneName'])){
311 $zonename= $this->Zones[$id]['InitialzoneName'];
312 }
314 $used = array();
316 /* Add Records which use this zoneName
317 */
318 if(isset($zones[$zonename])){
319 $used = array_merge($used,$zones[$zonename]);
320 }
322 /* Add Records which uses this reverse zone
323 */
324 if(isset($zones[$rev.".in-addr.arpa"])){
325 $used = array_merge($used,$zones[$rev.".in-addr.arpa"]);
326 }
328 /* There are still entries using this configuration
329 * Abort deletion
330 */
331 if(count($used)){
332 $i = 2;
333 $str ="";
334 foreach($used as $dn){
335 if($i > 0 && !preg_match("/,relativeDomainName=/",$dn)){
336 $i --;
337 $name = preg_replace("/^[^=]+=([^,]*),.*$/","\\1",$dn);
338 $zone = preg_replace("/^.*zoneName=([^,]*),.*$/","\\1",$dn);
339 $str.= $name.".".$zone." ";
340 }
341 }
343 /* Only show 2 dns in the error message
344 */
345 if(count($used)> 2) {
346 $str .=" ... ";
347 }
348 print_red(sprintf(_("Can't delete the selected zone, because it is still in use by these entry/entries '%s'"),trim($str)));
349 return(false);
350 }else{
351 unset($this->Zones[$id]);
352 return(true);
353 }
354 }
357 /* This funtion returns all used Zonenames
358 */
359 function getUsedZoneNames()
360 {
361 $ret = array();
362 $ldap = $this->config->get_ldap_link();
363 $ldap->cd($this->config->current['BASE']);
364 $ldap->search("(&(objectClass=dNSZone)(!(relativeDomainName=@))(zoneName=*))",array("zoneName","relativeDomainName"));
365 while($attr = $ldap->fetch()){
366 $ret[$attr['zoneName'][0]][] = $attr['dn'];
367 }
368 return($ret);
369 }
372 /* Remove dns service
373 */
374 function remove_from_parent()
375 {
376 if($this->initially_was_account){
377 $bool = true;
378 $this->is_account = FALSE;
379 foreach($this->Zones as $key => $zone){
380 $bool= $bool & $this->RemoveZone($key);
381 }
383 if($bool){
384 $this->save();
385 }
386 return($bool);
387 }
388 }
391 /* Save to LDAP */
392 function save()
393 {
395 /* Take over handling
396 * - Create list of zones managed by source server
397 * - Copy ldap entries to destination server
398 * - Remove old zone entries from source
399 */
400 if($this->take_over_id != -1){
401 $del = array();
402 $id = $this->take_over_id;
403 $src = $this->dns_server_list['ENTRIES'][$id]['dn'];
404 $ldap = $this->config->get_ldap_link();
405 $ldap->ls("(objectClass=dnsZone)",$src,array('cn'));
406 while($attrs = $ldap->fetch()){
407 $src_zone = $attrs['dn'];
408 $dst_zone = preg_replace("/".normalizePreg($src)."$/",$this->dn,$src_zone);
409 $res = plugin::recursive_move($src_zone, $dst_zone);
411 if($res){
412 $del [] = $src_zone;
413 }
414 }
415 foreach($del as $src_zone){
416 $ldap->rmdir_recursive($src_zone);
417 }
418 return;
419 }
422 $ldap = $this->config->get_ldap_link();
423 $ldap->cd($this->config->current['BASE']);
425 /* Get differences
426 */
427 $old_dn = $this->orig_dn;
428 if($old_dn == "new"){
429 $old_dn = $this->dn;
430 }
432 $tmp = getDNSZoneEntriesDiff($this->config,$this->Zones,$old_dn);
434 /* Update dns to current object dn */
435 $tmp = getDNSZoneEntriesDiff($this->config,$this->Zones,$old_dn);
436 $tmp2 = array();
437 foreach($tmp as $key1 => $data1){
438 $tmp2[$key1] = array();
439 foreach($data1 as $key2 => $data2){
440 $tmp2[$key1][preg_replace("/".normalizePreg($old_dn)."$/",$this->dn,$key2)] = $data2;
441 }
442 }
443 $tmp = $tmp2;
445 /* Updated zone entries if reverser or forward name has changed
446 * Must be done before moving entries, else the given dn is invalid
447 */
448 if(isset($tmp['zoneUpdates'])){
449 foreach($tmp['zoneUpdates'] as $dn => $attrs){
450 $ldap->cd($dn);
451 $ldap->modify($attrs);
452 new log("modfiy","unknown/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());
453 show_ldap_error($ldap->get_error(), sprintf(_("Updating of system server/dns with dn '%s' failed."),$this->dn));
454 }
455 }
457 /* Delete dns
458 */
459 foreach($tmp['del'] as $dn => $del){
461 $for = $del['InitialzoneName'];
462 $rev = FlipIp($del['InitialReverseZone']).".in-addr.arpa";
464 $ldap->cd($dn);
465 $ldap->rmdir_recursive($dn);
466 new log("remove","unknown/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());
467 show_ldap_error($ldap->get_error(), sprintf(_("Removing of system server/dns with dn '%s' failed."),$this->dn));
469 /* Handle Post events */
470 if(preg_match("/^zoneName=/",$dn)){
471 $this->handle_post_events("remove",array("dn" => $dn,"zoneName" => $for));
472 $this->handle_post_events("remove",array("dn" => $dn,"zoneName" => $rev));
473 }
474 }
476 /* move follwoing entries
477 */
478 foreach($tmp['move'] as $src => $dst){
479 $this->recursive_move($src,$dst);
480 }
482 /* Add || Update new DNS entries
483 */
484 foreach($tmp['add'] as $dn => $attrs){
485 $ldap->cd($dn);
486 $ldap->cat($dn, array('dn'));
487 if($ldap->fetch()){
488 $ldap->cd($dn);
489 $ldap->modify ($attrs);
490 show_ldap_error($ldap->get_error(), sprintf(_("Saving of system server/dns with dn '%s' failed."),$this->dn));
492 /* Handle Post events */
493 if(preg_match("/^zoneName=/",$dn)){
494 $this->handle_post_events("modify",array("dn" => $dn,"zoneName" => $attrs['zoneName']));
495 }
496 }else{
497 $ldap->cd($dn);
498 $ldap->add($attrs);
499 show_ldap_error($ldap->get_error(), sprintf(_("Saving of system server/dns with dn '%s' failed."),$this->dn));
501 /* Handle Post events */
502 if(preg_match("/^zoneName=/",$dn)){
503 $this->handle_post_events("add",array("dn" => $dn,"zoneName" => $attrs['zoneName']));
504 }
505 }
506 }
507 }
510 /* Directly save new status flag */
511 function setStatus($value)
512 {
513 if($value == "none") return;
514 if(!$this->initially_was_account) return;
515 if(empty($this->StatusFlag)) return;
516 $ldap = $this->config->get_ldap_link();
517 $ldap->cd($this->dn);
518 $ldap->cat($this->dn,array("objectClass"));
519 if($ldap->count()){
521 $tmp = $ldap->fetch();
522 for($i = 0; $i < $tmp['objectClass']['count']; $i ++){
523 $attrs['objectClass'][] = $tmp['objectClass'][$i];
524 }
525 $flag = $this->StatusFlag;
526 $attrs[$flag] = $value;
527 $this->$flag = $value;
528 $ldap->modify($attrs);
529 show_ldap_error($ldap->get_error(), sprintf(_("Set status flag for system server/dns with dn '%s' failed."),$this->dn));
530 $this->action_hook();
531 }
532 }
535 function getListEntry()
536 {
537 $fields = goService::getListEntry();
538 $fields['Message'] = _("DNS service");
539 $fields['AllowEdit'] = true;
540 return($fields);
541 }
544 /* Get updates for status flag */
545 function updateStatusState()
546 {
547 if(empty($this->StatusFlag)) return;
549 $attrs = array();
550 $flag = $this->StatusFlag;
551 $ldap = $this->config->get_ldap_link();
552 $ldap->cd($this->cn);
553 $ldap->cat($this->dn,array($flag));
554 if($ldap->count()){
555 $attrs = $ldap->fetch();
556 }
557 if(isset($attrs[$flag][0])){
558 $this->$flag = $attrs[$flag][0];
559 }
560 }
563 /* Return plugin informations for acl handling */
564 function plInfo()
565 {
566 return (array(
567 "plShortName" => _("DNS service"),
568 "plDescription" => _("DNS service")." ("._("Services").")",
569 "plSelfModify" => FALSE,
570 "plDepends" => array(),
571 "plPriority" => 83,
572 "plSection" => array("administration"),
573 "plCategory" => array("server"),
575 "plProvidedAcls"=> array(
576 "zoneName" =>_("Zone name"),
577 "ReverseZone" =>_("Reverse zone"),
578 "sOAprimary" =>_("Primary dns server"),
579 "sOAmail" =>_("Mail address"),
580 "sOAserial" =>_("Serial"),
581 "sOArefresh" =>_("Refresh"),
582 "sOAretry" =>_("Retry"),
583 "sOAexpire" =>_("Expire"),
584 "sOAttl" =>_("TTL"),
585 "zoneRecords" =>_("Zone records"))
586 ));
587 }
589 }
590 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
591 ?>