1 <?php
3 class servdns extends goService
4 {
5 /* attribute list for save action */
6 var $ignore_account = FALSE;
7 var $attributes = array();
8 var $objectclasses = array("whatever");
10 var $RecordTypes = array();
11 var $Zones = array();
13 var $orig_dn = "";
15 var $initially_was_account;
17 /* ServerService tab vars */
18 var $conflicts = array("servdns");
19 var $DisplayName = "";
20 var $StatusFlag = "";
21 var $view_logged = FALSE;
23 var $dns_server_list = array("ENTRIES"=> array(),"FOR_LIST"=> array());
24 var $take_over_id = -1;
27 function servdns (&$config, $dn= NULL, $parent= NULL)
28 {
29 plugin::plugin ($config, $dn, $parent);
31 $this->DisplayName = _("DNS service");
33 $this->orig_dn = $dn;
35 /* Get record types for zones
36 */
37 $this->RecordTypes = DNS::getDnsRecordTypes(true);
39 /* Get all zone Informations
40 */
41 $this->Zones = DNS::getDNSZoneEntries($config,$dn);
43 /* If there is at least one entry in this -> types, we have DNS enabled
44 */
45 if(count($this->Zones) == 0){
46 $this->is_account = false;
47 $this->dns_server_list = $this->get_list_of_dns_servers();
48 }else{
49 $this->is_account = true;
50 }
51 $this->initially_was_account = $this->is_account;
52 }
55 function get_list_of_dns_servers()
56 {
57 $ret = array("ENTRIES"=> array(),"FOR_LIST"=> array());
58 $ldap = $this->config->get_ldap_link();
59 $ldap->cd($this->config->current['BASE']);
60 $ldap->search("(&(objectClass=dNSZone)(zoneName=*))",array("dn","zoneName"));
61 $dns = array();
62 while($attrs = $ldap->fetch()){
63 /* Skip own config */
64 if($this->dn != "new" && preg_match("/".preg_quote($this->dn, '/')."$/",$attrs['dn'])){
65 continue;
66 }
67 $dn = preg_replace("/^zoneName=[^,]+,/","",$attrs['dn']);
68 if(preg_match("/^cn=/",$dn) && !in_array_strict($dn,$dns)){
69 $dns[] = $dn;
70 }
71 }
72 $i = 0;
73 foreach($dns as $dn){
74 $ldap->cat($dn,array('*'));
75 if($ldap->count()){
76 $i ++;
77 $attrs = $ldap->fetch();
78 $ret['ENTRIES'][$i] = $attrs;
79 $ret['FOR_LIST'][$i] = $attrs['cn'][0];
80 }
81 }
82 return($ret);
83 }
86 function get_dns_info_string($id)
87 {
88 $ret="";
89 $ldap = $this->config->get_ldap_link();
90 $ldap->cd($this->dns_server_list['ENTRIES'][$id]['dn']);
91 $ldap->search("(|(zoneName=*)(relativeDomainName=*))",array("dn"));
92 while($attrs = $ldap->fetch()){
93 $ret .= $attrs['dn']."\n";
94 }
95 return($ret);
96 }
99 function execute()
100 {
101 /* Call parent execute
102 */
103 plugin::execute();
105 if($this->is_account && !$this->view_logged){
106 $this->view_logged = TRUE;
107 new log("view","server/".get_class($this),$this->dn);
108 }
110 /* Fill templating stuff
111 */
112 $smarty= get_smarty();
113 $smarty->assign("dns_take_over",FALSE);
114 $smarty->assign("is_createable",$this->acl_is_createable());
115 $display= "";
118 $this->initially_was_account= $this->is_account;
119 /*****************/
120 /* Handle Take Over Actions
121 /*****************/
123 /* Give smarty the required informations */
124 $smarty->assign("dns_server_list", $this->dns_server_list['FOR_LIST']);
125 $smarty->assign("dns_server_list_cnt", count($this->dns_server_list['FOR_LIST']));
127 /* Take over requested, save id */
128 if(isset($_POST['take_over_src']) && isset($_POST['take_over'])){
129 $id = $_POST['take_over_src'];
130 if(isset($this->dns_server_list['ENTRIES'][$id])){
131 $this->take_over_id = $id;
132 }
133 }
135 /* Abort take over action */
136 if(isset($_POST['cancel_take_over'])){
137 $this->dialog =false;
138 $this->take_over_id = -1;
139 $this->dns_server_list = $this->get_list_of_dns_servers();
140 }
142 /* Display informartion about take over that will be started when saving this server
143 * and hide default dns output
144 */
145 if($this->take_over_id != -1){
146 $this->dialog = FALSE;
147 $id = $this->take_over_id;
148 $info = $this->get_dns_info_string($id);
149 $smarty->assign("dns_take_over",TRUE);
150 $smarty->assign("info",$info);
151 $warning = sprintf(_("You are going to migrate the DNS setup from server '%s'."),$this->dns_server_list['ENTRIES'][$id]['cn'][0]);
152 $warning2 = _("The migration will be started when you save this system. To cancel this action, use the cancel button below.");
153 $smarty->assign("warning",$warning);
154 $smarty->assign("warning2",$warning2);
155 return($smarty->fetch(get_template_path('servdns.tpl', TRUE, dirname(__FILE__))));
156 }
159 /* Do we need to flip is_account state?
160 */
161 if (isset($_POST['modify_state'])){
162 $this->is_account= !$this->is_account;
163 }
165 /* Edited or Added zone
166 */
167 if(isset($_POST['SaveZoneChanges'])){
168 $this->dialog->save_object();
170 /* Check for errors
171 */
172 if(count($this->dialog->check())){
173 foreach($this->dialog->check() as $msgs){
174 msg_dialog::display(_("Error"), $msgs, ERROR_DIALOG);
175 }
176 }else{
177 /* add new/edited zone
178 */
179 $ret = $this->dialog->save();
180 if(!$this->dialog->isNew){
181 unset($this->Zones[$this->dialog->OldZoneName]);
182 }
183 $this->Zones[$ret['zoneName']] = $ret;
184 $this->dialog = FALSE;
185 }
186 }
188 /* Cancel zone edit / new
189 */
190 if(isset($_POST['CancelZoneChanges'])){
191 $this->dialog = FALSE;
192 }
194 /* Add empty new zone
195 */
196 if(isset($_POST['AddZone'])){
197 $this->dialog = new servdnseditZone($this->config,$this->dn);
198 if($this->is_new){
199 $this->dialog->acl_base = $this->acl_base;
200 }
201 }
203 /* Check for edit zone request
204 */
205 $once = false;
206 foreach( $_POST as $name => $value){
208 /* check all post for edit request
209 */
210 if(preg_match("/^editZone_/",$name)&&!$once){
211 $once =true;
212 $tmp = preg_replace("/^editZone_/","",$name);
213 $tmp = base64_decode(preg_replace("/_.*$/","",$tmp));
214 $this->dialog= new servdnseditZone($this->config,$this->dn,$this->Zones[$tmp]);
215 }
217 /* check posts for delete zone
218 */
219 if(preg_match("/^delZone_/",$name)&&!$once){
221 $once =true;
222 $tmp = preg_replace("/^delZone_/","",$name);
223 $tmp = base64_decode(preg_replace("/_.*$/","",$tmp));
225 /* Initiate deletion
226 */
227 $this->RemoveZone($tmp);
228 }
229 }
231 if(isset($_GET['act']) && $_GET['act'] == "edit" && isset($_GET['id'])){
232 $id = base64_decode($_GET['id']);
233 if(isset($this->Zones[$id])){
234 $this->dialog= new servdnseditZone($this->config,$this->dn,$this->Zones[$id]);
235 }
236 }
238 if(isset($_GET['act']) && $_GET['act'] == "edit" && isset($_GET['id'])){
239 $id = base64_decode($_GET['id']);
240 if(isset($this->Zones[$id])){
241 $this->dialog= new servdnseditZone($this->config,$this->dn,$this->Zones[$id]);
242 }
243 }
245 /* Show dialog
246 */
247 if(is_object($this->dialog)){
248 $this->dialog->save_object();
249 $this->dialog->parent = $this;
250 return($this->dialog->execute());
251 }
253 /* Create Listbox with existing Zones
254 */
255 $ZoneList = new divSelectBox("dNSZones");
256 $ZoneList -> SetHeight(254);
258 /* Add entries to divlist
259 */
260 $editImg = "<input type='image' src='images/lists/edit.png' name='editZone_%s'>";
261 if($this->acl_is_removeable()){
262 $editImg.= "<input type='image' src='images/lists/trash.png' name='delZone_%s'>";
263 }
265 $link = "<a href='?plug=".$_GET['plug']."&act=edit&id=%s'>%s</a>";
266 foreach($this->Zones as $zone => $values ){
267 $ZoneList->AddEntry(array(
268 array("string" => sprintf($link,base64_encode($zone),($zone))),
269 array("string" => sprintf($link,base64_encode($zone),_("Reverse zone")." : ".($values['ReverseZone']))),
270 array("string" => _("TTL")." : ".$values['sOAttl']),
271 array("string" => _("Class")." : ".$values['dNSClass']),
272 array("string" =>str_replace("%s",base64_encode($zone),$editImg))
273 ));
274 }
276 /* Display tempalte
277 */
278 $smarty->assign("ZoneList",$ZoneList->DrawList());
279 $display.= $smarty->fetch(get_template_path('servdns.tpl', TRUE, dirname(__FILE__)));
280 return($display);
281 }
284 /* Delete specified zone
285 */
286 function RemoveZone($id,$force = FALSE)
287 {
288 $zones = $this->getUsedZoneNames();
290 if(isset($this->Zones[$id]['InitialReverseZone'])){
291 $rev = DNS::FlipIp($this->Zones[$id]['InitialReverseZone']);
292 }else{
293 $rev = DNS::FlipIp($this->Zones[$id]['ReverseZone']);
294 }
296 $zonename = "";
297 if(isset($this->Zones[$id]['InitialzoneName'])){
298 $zonename= $this->Zones[$id]['InitialzoneName'];
299 }
301 $used = array();
303 /* Add Records which use this zoneName
304 */
305 if(isset($zones[$zonename])){
306 $used = array_merge($used,$zones[$zonename]);
307 }
309 /* Add Records which uses this reverse zone
310 */
311 if(isset($zones[$rev.".in-addr.arpa."])){
312 $used = array_merge($used,$zones[$rev.".in-addr.arpa."]);
313 }
315 /* There are still entries using this configuration
316 * Abort deletion
317 */
318 if(count($used) && !$force){
319 $i = 2;
320 $str ="";
321 foreach($used as $dn){
322 if($i > 0 && !preg_match("/,relativeDomainName=/",$dn)){
323 $i --;
324 $name = preg_replace("/^[^=]+=([^,]*),.*$/","\\1",$dn);
325 $zone = preg_replace("/^.*zoneName=([^,]*),.*$/","\\1",$dn);
326 $str.= $name.".".$zone." ";
327 }
328 }
330 /* Only show 2 dns in the error message
331 */
332 if(count($used)> 2) {
333 $str .=" ... ";
334 }
335 msg_dialog::display(_("Error"), sprintf(_("Cannot delete the selected zone. It is still in use by '%s'"), trim($str)), ERROR_DIALOG);
336 return(false);
337 }else{
338 unset($this->Zones[$id]);
339 return(true);
340 }
341 }
344 /* This funtion returns all used Zonenames
345 */
346 function getUsedZoneNames()
347 {
348 $ret = array();
349 $ldap = $this->config->get_ldap_link();
350 $ldap->cd($this->config->current['BASE']);
351 $ldap->search("(&(objectClass=dNSZone)(!(relativeDomainName=@))(zoneName=*))",array("zoneName","relativeDomainName"));
352 while($attr = $ldap->fetch()){
353 $ret[$attr['zoneName'][0]][] = $attr['dn'];
354 }
355 return($ret);
356 }
359 /* Remove dns service
360 */
361 function remove_from_parent()
362 {
363 if($this->initially_was_account){
364 $bool = true;
365 $this->is_account = FALSE;
366 foreach($this->Zones as $key => $zone){
367 $bool= $bool & $this->RemoveZone($key,TRUE);
368 }
369 if($bool){
370 $this->save();
371 }
372 return($bool);
373 }
374 }
377 /* Save to LDAP */
378 function save()
379 {
381 /* Take over handling
382 * - Create list of zones managed by source server
383 * - Copy ldap entries to destination server
384 * - Remove old zone entries from source
385 */
386 if($this->take_over_id != -1){
387 $del = array();
388 $id = $this->take_over_id;
389 $src = $this->dns_server_list['ENTRIES'][$id]['dn'];
390 $ldap = $this->config->get_ldap_link();
391 $ldap->ls("(objectClass=dnsZone)",$src,array('cn'));
392 while($attrs = $ldap->fetch()){
393 $src_zone = $attrs['dn'];
394 $dst_zone = preg_replace("/".preg_quote($src, '/')."$/",$this->dn,$src_zone);
395 $res = plugin::recursive_move($src_zone, $dst_zone);
397 if($res){
398 $del [] = $src_zone;
399 }
400 }
401 foreach($del as $src_zone){
402 $ldap->rmdir_recursive($src_zone);
403 }
404 return;
405 }
407 /* Save zone editor changes now */
408 foreach($this->Zones as $name => $zone){
409 if(isset($zone['zoneEditor'] ) && $zone['zoneEditor'] != NULL && is_object($zone['zoneEditor'])){
410 $zone['zoneEditor']->save();
411 unset($this->Zones[$name]['zoneEditor']);;
412 }
413 }
415 $ldap = $this->config->get_ldap_link();
416 $ldap->cd($this->config->current['BASE']);
418 /* Get differences
419 */
420 $old_dn = $this->orig_dn;
421 if($old_dn == "new"){
422 $old_dn = $this->dn;
423 }
425 /* Update dns to current object dn */
426 $tmp = DNS::getDNSZoneEntriesDiff($this->config,$this->Zones,$old_dn);
427 $tmp2 = array();
428 foreach($tmp as $key1 => $data1){
429 $tmp2[$key1] = array();
430 foreach($data1 as $key2 => $data2){
431 $tmp2[$key1][preg_replace("/".preg_quote($old_dn, '/')."$/",$this->dn,$key2)] = $data2;
432 }
433 }
434 $tmp = $tmp2;
436 /* Updated zone entries if reverser or forward name has changed
437 * Must be done before moving entries, else the given dn is invalid
438 */
439 if(isset($tmp['zoneUpdates'])){
440 foreach($tmp['zoneUpdates'] as $dn => $attrs){
441 $ldap->cd($dn);
442 $ldap->modify($attrs);
443 new log("modify","unknown/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());
444 if (!$ldap->success()){
445 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
446 }
447 }
448 }
450 /* Delete dns
451 */
452 foreach($tmp['del'] as $dn => $del){
454 $for = $del['InitialzoneName'];
455 $rev = DNS::FlipIp($del['InitialReverseZone']).".in-addr.arpa.";
457 $ldap->cd($dn);
458 $ldap->rmdir_recursive($dn);
459 new log("remove","unknown/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());
460 if (!$ldap->success()){
461 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_DEL, get_class()));
462 }
464 /* Handle Post events */
465 if(preg_match("/^zoneName=/",$dn)){
466 # $this->handle_post_events("remove",array("dn" => $dn,"zoneName" => $for));
467 # $this->handle_post_events("remove",array("dn" => $dn,"zoneName" => $rev));
468 }
469 }
471 /* move follwoing entries
472 */
473 foreach($tmp['move'] as $src => $dst){
474 $this->recursive_move($src,$dst);
475 }
477 /* Add || Update new DNS entries
478 */
479 foreach($tmp['add'] as $dn => $attrs){
480 $ldap->cd($dn);
481 $ldap->cat($dn, array('dn'));
482 if($ldap->fetch()){
483 $ldap->cd($dn);
484 $ldap->modify ($attrs);
485 if (!$ldap->success()){
486 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
487 }
489 /* Handle Post events */
490 if(preg_match("/^zoneName=/",$dn)){
491 # $this->handle_post_events("modify",array("dn" => $dn,"zoneName" => $attrs['zoneName']));
492 }
493 }else{
494 $ldap->cd($dn);
495 $ldap->add($attrs);
496 if (!$ldap->success()){
497 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_ADD, get_class()));
498 }
500 /* Handle Post events */
501 if(preg_match("/^zoneName=/",$dn)){
502 # $this->handle_post_events("add",array("dn" => $dn,"zoneName" => $attrs['zoneName']));
503 }
504 }
505 }
506 $this->handle_post_events("modify");
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 if (!$ldap->success()){
530 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
531 }
532 $this->action_hook();
533 }
534 }
537 function getListEntry()
538 {
539 $fields = goService::getListEntry();
540 $fields['Message'] = _("DNS service");
541 #$fields['AllowEdit'] = true;
542 return($fields);
543 }
546 /* Get updates for status flag */
547 function updateStatusState()
548 {
549 if(empty($this->StatusFlag)) return;
551 $attrs = array();
552 $flag = $this->StatusFlag;
553 $ldap = $this->config->get_ldap_link();
554 $ldap->cd($this->cn);
555 $ldap->cat($this->dn,array($flag));
556 if($ldap->count()){
557 $attrs = $ldap->fetch();
558 }
559 if(isset($attrs[$flag][0])){
560 $this->$flag = $attrs[$flag][0];
561 }
562 }
565 /* Return plugin informations for acl handling */
566 static function plInfo()
567 {
568 return (array(
569 "plShortName" => _("DNS service"),
570 "plDescription" => _("DNS service")." ("._("Services").")",
571 "plSelfModify" => FALSE,
572 "plDepends" => array(),
573 "plPriority" => 83,
574 "plSection" => array("administration"),
575 "plCategory" => array("server"),
577 "plProvidedAcls"=> array(
578 "start" => _("Start service"), // Remove this to hide the start button at all.
579 "stop" => _("Stop service"), // Remove this to hide the stop button at all.
580 "restart" => _("Restart service"),// Remove this to hide the restart button at all.
582 "zoneName" =>_("Zone name"),
583 "ReverseZone" =>_("Reverse zone"),
584 "NetworkClass" =>_("Network class"),
585 "zoneEditor" =>_("Zone entry editor"),
586 "sOAprimary" =>_("Primary dns server"),
587 "sOAmail" =>_("Mail address"),
588 "sOAserial" =>_("Serial"),
589 "sOArefresh" =>_("Refresh"),
590 "sOAretry" =>_("Retry"),
591 "sOAexpire" =>_("Expire"),
592 "sOAttl" =>_("TTL"),
593 "mXRecord" =>_("MX records"),
594 "zoneRecords" =>_("Zone records"))
595 ));
596 }
598 }
599 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
600 ?>