Code

We don't need a dhcp and dns activation in the gosa.conf anymore, since GOsa is split...
[gosa.git] / gosa-si / gosa-si-server
index 11c142f85564dc4c27537fc00f4f721afb3ef8fd..a6daf3fe11c0202a8767961dbb0858fcc11a3bc2 100755 (executable)
 #     REVISION:  ---
 #===============================================================================
 
-
-# TODO
-#
-# max_children wird momentan nicht mehr verwendet, jede eingehende nachricht bekommt ein eigenes POE child
+my $server_version = '$HeadURL: https://oss.gonicus.de/repositories/gosa/trunk/gosa-si/gosa-si-server $:$Rev$';
 
 use strict;
 use warnings;
@@ -31,7 +28,7 @@ use Getopt::Long;
 use Config::IniFiles;
 use POSIX;
 
-use Fcntl;
+use Fcntl qw/:flock/;
 use IO::Socket::INET;
 use IO::Handle;
 use IO::Select;
@@ -42,6 +39,7 @@ use Digest::MD5  qw(md5 md5_hex md5_base64);
 use XML::Simple;
 use Data::Dumper;
 use Sys::Syslog qw( :DEFAULT setlogsock);
+use Time::HiRes qw( usleep);
 use Cwd;
 use File::Spec;
 use File::Basename;
@@ -52,7 +50,14 @@ use GOSA::GosaSupportDaemon;
 use POE qw(Component::Server::TCP Wheel::Run Filter::Reference);
 use Net::LDAP;
 use Net::LDAP::Util qw(:escape);
-use Time::HiRes qw( usleep);
+use ResourcePool;
+use ResourcePool::Factory::Net::LDAP;
+
+# revision number of server and program name
+my $server_headURL;
+my $server_revision;
+my $server_status;
+our $prg= basename($0);
 
 my $db_module = "DBsqlite";
 {
@@ -65,20 +70,13 @@ daemon_log("0 INFO: importing database module '$db_module'", 1);
 my $modules_path = "/usr/lib/gosa-si/modules";
 use lib "/usr/lib/gosa-si/modules";
 
-# revision number of server and program name
-my $server_version = '$HeadURL: https://oss.gonicus.de/repositories/gosa/trunk/gosa-si/gosa-si-server $:$Rev: 10826 $';
-my $server_headURL;
-my $server_revision;
-my $server_status;
-our $prg= basename($0);
-
 our $global_kernel;
 my ($foreground, $ping_timeout);
 my ($server);
 my ($gosa_server, $job_queue_timeout, $job_queue_loop_delay);
 my ($messaging_db_loop_delay);
 my ($procid, $pid);
-my ($arp_fifo);
+my ($arp_fifo, $ldap_pool, $ldap_factory);
 my ($xml);
 my $sources_list;
 my $max_clients;
@@ -106,7 +104,7 @@ our $no_arp;
 our $verbose;
 our $forground;
 our $cfg_file;
-our ($ldap_uri, $ldap_base, $ldap_admin_dn, $ldap_admin_password, $ldap_server_dn);
+our ($ldap_uri, $ldap_base, $ldap_admin_dn, $ldap_admin_password, $ldap_server_dn, $ldap_version);
 our ($mysql_username, $mysql_password, $mysql_database, $mysql_host);
 our $known_modules;
 our $root_uid;
@@ -131,7 +129,7 @@ my $watch_for_new_jobs_in_progress = 0;
 our $incoming_db;
 our $incoming_tn = 'incoming';
 my $incoming_file_name;
-my @incoming_col_names = ("id INTEGER PRIMARY KEY auto_increment",
+my @incoming_col_names = ("id INTEGER PRIMARY KEY",
        "timestamp VARCHAR(14) DEFAULT 'none'", 
        "headertag VARCHAR(255) DEFAULT 'none'",
        "targettag VARCHAR(255) DEFAULT 'none'",
@@ -144,7 +142,7 @@ my @incoming_col_names = ("id INTEGER PRIMARY KEY auto_increment",
 our $job_db;
 our $job_queue_tn = 'jobs';
 my $job_queue_file_name;
-my @job_queue_col_names = ("id INTEGER PRIMARY KEY auto_increment",
+my @job_queue_col_names = ("id INTEGER PRIMARY KEY",
        "timestamp VARCHAR(14) DEFAULT 'none'", 
        "status VARCHAR(255) DEFAULT 'none'", 
        "result TEXT",
@@ -180,7 +178,7 @@ my @foreign_clients_col_names = ("hostname VARCHAR(255)", "macaddress VARCHAR(17
 our $login_users_db;
 our $login_users_tn = "login_users";
 my $login_users_file_name;
-my @login_users_col_names = ("client VARCHAR(255)", "user VARCHAR(255)", "timestamp VARCHAR(14)");
+my @login_users_col_names = ("client VARCHAR(255)", "user VARCHAR(255)", "timestamp VARCHAR(14)", "regserver VARCHAR(255) DEFAULT 'localhost'");
 
 # holds all fai server, the debian release and tag
 our $fai_server_db;
@@ -251,13 +249,14 @@ our $logged_in_user_date_of_expiry = 600;
     "ldap-base"             => [\$ldap_base, ""],
     "ldap-admin-dn"         => [\$ldap_admin_dn, ""],
     "ldap-admin-password"   => [\$ldap_admin_password, ""],
+       "ldap-version"                  => [\$ldap_version, 3],
     "gosa-unit-tag"         => [\$gosa_unit_tag, ""],
     "max-clients"           => [\$max_clients, 10],
     "wol-password"          => [\$wake_on_lan_passwd, ""],
-               "mysql-username"        => [\$mysql_username, "gosa_si"],
-               "mysql-password"        => [\$mysql_password, ""],
-               "mysql-database"        => [\$mysql_database, "gosa_si"],
-               "mysql-host"            => [\$mysql_host, "127.0.0.1"],
+       "mysql-username"        => [\$mysql_username, "gosa_si"],
+       "mysql-password"        => [\$mysql_password, ""],
+       "mysql-database"        => [\$mysql_database, "gosa_si"],
+       "mysql-host"            => [\$mysql_host, "127.0.0.1"],
     },
 "GOsaPackages" => {
     "job-queue" => [\$job_queue_file_name, '/var/lib/gosa-si/jobs.db'],
@@ -328,11 +327,17 @@ sub daemon_log {
     if(not defined $msg) { return }
     if(not defined $level) { $level = 1 }
     if(defined $log_file){
-        open(LOG_HANDLE, ">>$log_file");
-        if(not defined open( LOG_HANDLE, ">>$log_file" )) {
+        my $open_log_fh = sysopen(LOG_HANDLE, $log_file, O_WRONLY | O_CREAT | O_APPEND , 0440);
+        if(not $open_log_fh) {
             print STDERR "cannot open $log_file: $!";
-            return 
+            return;
+        }
+        # check owner and group of log_file and update settings if necessary
+        my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat($log_file);
+        if((not $uid eq $root_uid) || (not $gid eq $adm_gid)) {
+            chown($root_uid, $adm_gid, $log_file);
         }
+
         chomp($msg);
         #$msg =~s/\n//g;   # no newlines are allowed in log messages, this is important for later log parsing
         if($level <= $verbose){
@@ -348,7 +353,10 @@ sub daemon_log {
             my $name = $prg;
 
             my $log_msg = "$month $monthday $hours:$minutes:$seconds $name $msg\n";
+                       flock(LOG_HANDLE, LOCK_EX);
+                       seek(LOG_HANDLE, 0, 2);
             print LOG_HANDLE $log_msg;
+                       flock(LOG_HANDLE, LOCK_UN);
             if( $foreground ) { 
                 print STDERR $log_msg;
             }
@@ -448,6 +456,8 @@ sub import_modules {
     }
 
     opendir (DIR, $modules_path) or die "ERROR while loading modules from directory $modules_path : $!\n";
+
+       my $ldap_handle = &get_ldap_handle;
     while (defined (my $file = readdir (DIR))) {
         if (not $file =~ /(\S*?).pm$/) {
             next;
@@ -465,7 +475,7 @@ sub import_modules {
             daemon_log("$@", 1);
            exit;
                } else {
-                       my $info = eval($mod_name.'::get_module_info()');
+                       my $info = eval($mod_name.'::get_module_info($ldap_handle)');
                        # Only load module if get_module_info() returns a non-null object
                        if( $info ) {
                                my ($input_address, $input_key, $event_hash) = @{$info};
@@ -474,7 +484,7 @@ sub import_modules {
                        }
                }
     }   
-
+       &release_ldap_handle($ldap_handle); 
     close (DIR);
 }
 
@@ -868,48 +878,6 @@ sub open_socket {
 }
 
 
-#sub get_local_ip_for_remote_ip {
-#      my $remote_ip= shift;
-#      my $result="0.0.0.0";
-#
-#      if($remote_ip =~ /^(\d\d?\d?\.){3}\d\d?\d?$/) {
-#              if($remote_ip eq "127.0.0.1") {
-#                      $result = "127.0.0.1";
-#              } else {
-#                      my $PROC_NET_ROUTE= ('/proc/net/route');
-#
-#                      open(PROC_NET_ROUTE, "<$PROC_NET_ROUTE")
-#                              or die "Could not open $PROC_NET_ROUTE";
-#
-#                      my @ifs = <PROC_NET_ROUTE>;
-#
-#                      close(PROC_NET_ROUTE);
-#
-#                      # Eat header line
-#                      shift @ifs;
-#                      chomp @ifs;
-#                      foreach my $line(@ifs) {
-#                              my ($Iface,$Destination,$Gateway,$Flags,$RefCnt,$Use,$Metric,$Mask,$MTU,$Window,$IRTT)=split(/\s/, $line);
-#                              my $destination;
-#                              my $mask;
-#                              my ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Destination);
-#                              $destination= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d));
-#                              ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Mask);
-#                              $mask= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d));
-#                              if(new NetAddr::IP($remote_ip)->within(new NetAddr::IP($destination, $mask))) {
-#                                      # destination matches route, save mac and exit
-#                                      $result= &get_ip($Iface);
-#                                      last;
-#                              }
-#                      }
-#              }
-#      } else {
-#              daemon_log("0 WARNING: get_local_ip_for_remote_ip() was called with a non-ip parameter: '$remote_ip'", 1);
-#      }
-#      return $result;
-#}
-
-
 sub send_msg_to_target {
     my ($msg, $address, $encrypt_key, $msg_header, $session_id) = @_ ;
     my $error = 0;
@@ -1004,32 +972,88 @@ sub send_msg_to_target {
 
 
 sub update_jobdb_status_for_send_msgs {
-    my ($answer, $error) = @_;
+    my ($session_id, $answer, $error) = @_;
+    &daemon_log("$session_id DEBUG: try to update job status", 7); 
     if( $answer =~ /<jobdb_id>(\d+)<\/jobdb_id>/ ) {
         my $jobdb_id = $1;
+    
+        $answer =~ /<header>(.*)<\/header>/;
+        my $job_header = $1;
+
+        $answer =~ /<target>(.*)<\/target>/;
+        my $job_target = $1;
             
-        # sending msg faild
+        # Sending msg failed
         if( $error ) {
 
-daemon_log("D \n$error\n$answer");
-
-            if ((not $answer =~ /<header>trigger_action_reinstall<\/header>/) || (not $answer =~ /<header>trigger_action_update<\/header>/)) {
+            # Set jobs to done, jobs do not need to deliver their message in any case
+            if (($job_header eq "trigger_action_localboot")
+                    ||($job_header eq "trigger_action_lock")
+                    ||($job_header eq "trigger_action_halt") 
+                    ) {
+                my $sql_statement = "UPDATE $job_queue_tn SET status='done' WHERE id=$jobdb_id";
+                &daemon_log("$session_id DEBUG: $sql_statement", 7); 
+                my $res = $job_db->update_dbentry($sql_statement);
+                
+            # Reactivate jobs, jobs need to deliver their message
+            } elsif (($job_header eq "trigger_action_activate")
+                    ||($job_header eq "trigger_action_update")
+                    ||($job_header eq "trigger_action_reinstall") 
+                    ||($job_header eq "trigger_activate_new")
+                    ) {
+                &reactivate_job_with_delay($session_id, $job_target, $job_header, 30 );
+
+            # For all other messages
+            } else {
                 my $sql_statement = "UPDATE $job_queue_tn ".
                     "SET status='error', result='can not deliver msg, please consult log file' ".
                     "WHERE id=$jobdb_id";
+                &daemon_log("$session_id DEBUG: $sql_statement", 7); 
                 my $res = $job_db->update_dbentry($sql_statement);
             }
 
-        # sending msg was successful
+        # Sending msg was successful
         } else {
-            my $sql_statement = "UPDATE $job_queue_tn ".
-                "SET status='done' ".
-                "WHERE id=$jobdb_id AND status='processed'";
-            my $res = $job_db->update_dbentry($sql_statement);
-        }
+            # Set jobs localboot, lock, activate, halt, reboot and wake to done
+            # jobs reinstall, update, inst_update do themself setting to done
+            if (($job_header eq "trigger_action_localboot")
+                    ||($job_header eq "trigger_action_lock")
+                    ||($job_header eq "trigger_action_activate")
+                    ||($job_header eq "trigger_action_halt") 
+                    ||($job_header eq "trigger_action_reboot")
+                    ||($job_header eq "trigger_action_wake")
+                    ||($job_header eq "trigger_wake")
+                    ) {
+
+                my $sql_statement = "UPDATE $job_queue_tn ".
+                    "SET status='done' ".
+                    "WHERE id=$jobdb_id AND status='processed'";
+                &daemon_log("$session_id DEBUG: $sql_statement", 7); 
+                my $res = $job_db->update_dbentry($sql_statement);
+            } else { 
+                &daemon_log("$session_id DEBUG: sending message succeed but cannot update job status.", 7); 
+            } 
+        } 
+    } else { 
+        &daemon_log("$session_id DEBUG: cannot update job status, msg has no jobdb_id-tag: $answer", 7); 
     }
 }
 
+sub reactivate_job_with_delay {
+    my ($session_id, $target, $header, $delay) = @_ ;
+    # Sometimes the client is still booting or does not wake up, in this case reactivate the job (if it exists) with a delay of n sec
+    
+    if (not defined $delay) { $delay = 30 } ;
+    my $delay_timestamp = &calc_timestamp(&get_time(), "plus", $delay);
+
+    my $sql = "UPDATE $job_queue_tn Set timestamp='$delay_timestamp', status='waiting' WHERE (macaddress='$target' AND headertag='$header')"; 
+    my $res = $job_db->update_dbentry($sql);
+    daemon_log("$session_id INFO: '$header'-job will be reactivated at '$delay_timestamp' ".
+            "cause client '$target' is currently not available", 5);
+    daemon_log("$session_id $sql", 7);                             
+    return;
+}
+
 
 sub sig_handler {
        my ($kernel, $signal) = @_[KERNEL, ARG0] ;
@@ -1045,8 +1069,9 @@ sub msg_to_decrypt {
        my ($msg, $msg_hash, $module);
        my $error = 0;
 
-       # hole neue msg aus @msgs_to_decrypt
-       my $next_msg = shift @msgs_to_decrypt;
+       # fetch new msg out of @msgs_to_decrypt
+       my $tmp_next_msg = shift @msgs_to_decrypt;
+    my ($next_msg, $msg_source) = split(/;/, $tmp_next_msg);
 
        # msg is from a new client or gosa
        ($msg, $msg_hash, $module) = &input_from_unknown_host($next_msg, $session_id);
@@ -1063,17 +1088,13 @@ sub msg_to_decrypt {
        if(( !$msg ) || ( !$msg_hash ) || ( !$module )){
                # if an incoming msg could not be decrypted (maybe a wrong key), send client a ping. If the client
                # could not understand a msg from its server the client cause a re-registering process
+        my $remote_ip = $heap->{'remote_ip'};
+        my $remote_port = $heap->{'remote_port'};
+        my $ping_msg = "<xml> <header>gosa_ping</header> <source>$server_address</source><target>$msg_source</target></xml>";
+        my ($test_error, $test_error_string) = &send_msg_to_target($ping_msg, "$msg_source", "dummy-key", "gosa_ping", $session_id);
+
                daemon_log("$session_id WARNING cannot understand incoming msg, send 'ping'-msg to all host with ip '".$heap->{remote_ip}.
                        "' to cause a re-registering of the client if necessary", 3);
-               my $sql_statement = "SELECT * FROM $main::known_clients_tn WHERE (hostname LIKE '".$heap->{'remote_ip'}."%')";
-               my $query_res = $known_clients_db->select_dbentry( $sql_statement ); 
-               while( my ($hit_num, $hit) = each %{ $query_res } ) {    
-                       my $host_name = $hit->{'hostname'};
-                       my $host_key = $hit->{'hostkey'};
-                       my $ping_msg = "<xml> <header>gosa_ping</header> <source>$server_address</source> <target>$host_name</target></xml>";
-                       my $error = &send_msg_to_target($ping_msg, $host_name, $host_key, "gosa_ping", $session_id);
-                       &update_jobdb_status_for_send_msgs($ping_msg, $error);
-               }
                $error++;
        }
 
@@ -1304,15 +1325,16 @@ sub msg_to_decrypt {
 
 
 sub next_task {
-    my ($session, $heap, $task) = @_[SESSION, HEAP, ARG0];
+    my ($session, $heap, $task, $ldap_handle) = @_[SESSION, HEAP, ARG0, ARG1];
     my $running_task = POE::Wheel::Run->new(
-            Program => sub { process_task($session, $heap, $task) },
+            Program => sub { process_task($session, $heap, $task, $ldap_handle) },
             StdioFilter => POE::Filter::Reference->new(),
             StdoutEvent  => "task_result",
             StderrEvent  => "task_debug",
             CloseEvent   => "task_done",
             );
     $heap->{task}->{ $running_task->ID } = $running_task;
+       $heap->{ldap_handle}->{$running_task->ID} = $ldap_handle;
 }
 
 sub handle_task_result {
@@ -1342,12 +1364,15 @@ sub handle_task_debug {
 sub handle_task_done {
     my ( $kernel, $heap, $task_id ) = @_[ KERNEL, HEAP, ARG0 ];
     delete $heap->{task}->{$task_id};
+       if (exists $heap->{ldap_handle}->{$task_id}) {
+               &release_ldap_handle($heap->{ldap_handle}->{$task_id});
+       }
 }
 
 sub process_task {
     no strict "refs";
     #CHECK: Not @_[...]?
-    my ($session, $heap, $task) = @_;
+    my ($session, $heap, $task, $ldap_handle) = @_;
     my $error = 0;
     my $answer_l;
     my ($answer_header, @answer_target_l, $answer_source);
@@ -1369,8 +1394,8 @@ sub process_task {
     
     # set timestamp of incoming client uptodate, so client will not 
     # be deleted from known_clients because of expiration
-    my $act_time = &get_time();
-    my $sql = "UPDATE $known_clients_tn SET timestamp='$act_time' WHERE hostname='$source'"; 
+    my $cur_time = &get_time();
+    my $sql = "UPDATE $known_clients_tn SET timestamp='$cur_time' WHERE hostname='$source'"; 
     my $res = $known_clients_db->exec_statement($sql);
 
     ######################
@@ -1378,7 +1403,7 @@ sub process_task {
     if( $error == 0) {
         daemon_log("$session_id INFO: Incoming msg (session_id=$session_id) with header '".@{$msg_hash->{'header'}}[0]."'", 5); 
         daemon_log("$session_id DEBUG: Processing module ".$module, 7);
-        $answer_l = &{ $module."::process_incoming_msg" }($msg, $msg_hash, $session_id);
+        $answer_l = &{ $module."::process_incoming_msg" }($msg, $msg_hash, $session_id, $ldap_handle);
 
         if ( 0 < @{$answer_l} ) {
             my $answer_str = join("\n", @{$answer_l});
@@ -1418,7 +1443,7 @@ sub process_task {
                         my $host_name = $hit->{hostname};
                         my $host_key = $hit->{hostkey};
                         my $error = &send_msg_to_target($answer, $host_name, $host_key, $answer_header, $session_id);
-                        &update_jobdb_status_for_send_msgs($answer, $error);
+                        &update_jobdb_status_for_send_msgs($session_id, $answer, $error);
                     }
                 }
 
@@ -1432,7 +1457,7 @@ sub process_task {
                         my $host_key = $hit->{hostkey};
                         $answer =~ s/<target>\S+<\/target>/<target>$host_name<\/target>/g;
                         my $error = &send_msg_to_target($answer, $host_name, $host_key, $answer_header, $session_id);
-                        &update_jobdb_status_for_send_msgs($answer, $error);
+                        &update_jobdb_status_for_send_msgs($session_id, $answer, $error);
                     }
                 }
 
@@ -1454,7 +1479,7 @@ sub process_task {
                     my $header;
                     if( defined $1 ) { $header = $1; }
                     my $error = &send_msg_to_target($answer, $server_address, $GosaPackages_key, $header, $session_id);
-                    &update_jobdb_status_for_send_msgs($answer, $error);
+                    &update_jobdb_status_for_send_msgs($session_id, $answer, $error);
                 }
 
                 # Target of msg is a mac address
@@ -1471,7 +1496,7 @@ sub process_task {
                         $answer =~ s/$answer_target/$host_name/g;
                         daemon_log("$session_id INFO: found host '$host_name', associated to '$answer_target'", 5);
                         my $error = &send_msg_to_target($answer, $host_name, $host_key, $answer_header, $session_id);
-                        &update_jobdb_status_for_send_msgs($answer, $error);
+                        &update_jobdb_status_for_send_msgs($session_id, $answer, $error);
                         $found_ip_flag++ ;
                     }   
 
@@ -1500,7 +1525,7 @@ sub process_task {
                             if (defined $reg_server_key) {
                                 $answer =~ s/$answer_target/$host_name/g;
                                 my $error = &send_msg_to_target($answer, $reg_server, $reg_server_key, $answer_header, $session_id);
-                                &update_jobdb_status_for_send_msgs($answer, $error);
+                                &update_jobdb_status_for_send_msgs($session_id, $answer, $error);
                                 $found_ip_flag++ ;
                             }
                         }
@@ -1509,14 +1534,7 @@ sub process_task {
                     # No mac to ip matching found
                     if( $found_ip_flag == 0) {
                         daemon_log("$session_id WARNING: no host found in known_clients or foreign_clients with mac address '$answer_target'", 3);
-
-                        # Sometimes the client is still booting or does not wake up, in this case reactivate the job (if it exists) with a delay of 30 sec
-                        my $delay_timestamp = &calc_timestamp(&get_time(), "plus", 30);
-                        my $sql = "UPDATE $job_queue_tn Set timestamp='$delay_timestamp', status='waiting' WHERE (macaddress='$answer_target' AND headertag='$answer_header')"; 
-                        my $res = $job_db->update_dbentry($sql);
-                        daemon_log("$session_id INFO: '$answer_header'-job will be reactivated at '$delay_timestamp' ".
-                                "cause client '$answer_target' is currently not available", 5);
-                        daemon_log("$session_id $sql", 7);                                
+                        &reactivate_job_with_delay($session_id, $answer_target, $answer_header, 30);
                     }
 
                 # Answer is for one specific host   
@@ -1529,7 +1547,7 @@ sub process_task {
                         next;
                     }
                     my $error = &send_msg_to_target($answer, $answer_target, $encrypt_key, $answer_header,$session_id);
-                    &update_jobdb_status_for_send_msgs($answer, $error);
+                    &update_jobdb_status_for_send_msgs($session_id, $answer, $error);
                 }
             }
         }
@@ -1573,19 +1591,19 @@ sub session_start {
 
 
 sub watch_for_done_jobs {
-    #CHECK: $heap for what?
-    my ($kernel,$heap) = @_[KERNEL, HEAP];
+       #CHECK: $heap for what?
+       my ($kernel,$heap) = @_[KERNEL, HEAP];
 
-    my $sql_statement = "SELECT * FROM ".$job_queue_tn." WHERE ((status='done') AND (modified='0'))";
+       my $sql_statement = "SELECT * FROM ".$job_queue_tn." WHERE ((status='done') AND (modified='0'))";
        my $res = $job_db->select_dbentry( $sql_statement );
 
-    while( my ($id, $hit) = each %{$res} ) {
-        my $jobdb_id = $hit->{id};
-        my $sql_statement = "DELETE FROM $job_queue_tn WHERE id=$jobdb_id"; 
-        my $res = $job_db->del_dbentry($sql_statement);        
-    }
+       while( my ($id, $hit) = each %{$res} ) {
+               my $jobdb_id = $hit->{id};
+               my $sql_statement = "DELETE FROM $job_queue_tn WHERE id=$jobdb_id"; 
+               my $res = $job_db->del_dbentry($sql_statement); 
+       }
 
-    $kernel->delay_set('watch_for_done_jobs',$job_queue_loop_delay);
+       $kernel->delay_set('watch_for_done_jobs',$job_queue_loop_delay);
 }
 
 
@@ -1781,7 +1799,7 @@ sub watch_for_new_jobs {
                                        if(defined($res_2) and defined @{$res_2}[0]) {
                                                # Set status from goto-activation to 'waiting' and update timestamp
                                                $job_db->exec_statement("UPDATE $job_queue_tn SET status='waiting' WHERE macaddress LIKE '$macaddress' AND headertag = 'trigger_action_reinstall'");
-                                               $job_db->exec_statement("UPDATE $job_queue_tn SET timestamp='".&get_time(30)."' WHERE macaddress LIKE '$macaddress' AND headertag = 'trigger_action_reinstall'");
+                                               $job_db->exec_statement("UPDATE $job_queue_tn SET timestamp='".&calc_timestamp(&get_time(), 'plus', 30)."' WHERE macaddress LIKE '$macaddress' AND headertag = 'trigger_action_reinstall'");
                                        }
                                }
                                next;
@@ -1811,7 +1829,9 @@ sub watch_for_new_jobs {
 
                                        # update status in job queue to ...
                     # ... 'processing', for jobs: 'reinstall', 'update'
-                    if (($header =~ /gosa_trigger_action_reinstall/) || ($header =~ /gosa_trigger_action_update/)) {
+                    if (($header =~ /gosa_trigger_action_reinstall/) 
+                            || ($header =~ /gosa_trigger_activate_new/)
+                            || ($header =~ /gosa_trigger_action_update/)) {
                         my $sql_statement = "UPDATE $job_queue_tn SET status='processing' WHERE id=$jobdb_id";
                         my $dbres = $job_db->update_dbentry($sql_statement);
                     }
@@ -1852,7 +1872,7 @@ sub watch_for_new_messages {
                my %receiver_h; 
                foreach my $receiver (@message_to_l) {
                        if ($receiver =~ /^u_([\s\S]*)$/) {
-                               $receiver_h{$receiver} = 0;
+                               $receiver_h{$1} = 0;
                        } elsif ($receiver =~ /^g_([\s\S]*)$/) {
                                my $group_name = $1;
                                # fetch all group members from ldap and add them to receiver hash
@@ -1864,6 +1884,7 @@ sub watch_for_new_messages {
                                                                                attrs => ['memberUid'],
                                                                                filter => "cn=$group_name",
                                                                                );
+                                               &release_ldap_handle($ldap_handle);
                                                if ($mesg->count) {
                                                                my @entries = $mesg->entries;
                                                                foreach my $entry (@entries) {
@@ -2059,7 +2080,7 @@ sub watch_for_old_known_clients {
     my $sql_statement = "SELECT * FROM $known_clients_tn";
     my $res = $known_clients_db->select_dbentry( $sql_statement );
 
-    my $act_time = int(&get_time());
+    my $cur_time = int(&get_time());
 
     while ( my ($hit_num, $hit) = each %$res) {
         my $expired_timestamp = int($hit->{'timestamp'});
@@ -2074,7 +2095,7 @@ sub watch_for_old_known_clients {
 
         $dt->add( seconds => 2 * int($hit->{'keylifetime'}) );
         $expired_timestamp = $dt->ymd('').$dt->hms('');
-        if ($act_time > $expired_timestamp) {
+        if ($cur_time > $expired_timestamp) {
             my $hostname = $hit->{'hostname'};
             my $del_sql = "DELETE FROM $known_clients_tn WHERE hostname='$hostname'"; 
             my $del_res = $known_clients_db->exec_statement($del_sql);
@@ -2103,7 +2124,10 @@ sub watch_for_next_tasks {
         my $message_id = $hit->{'id'};
         my $session_id = $hit->{'sessionid'};
         &daemon_log("$session_id DEBUG: start processing for message with incoming id: '$message_id'", 7);
-        $kernel->yield('next_task', $hit);
+
+               my $ldap_handle = &get_ldap_handle();
+               if (not defined $ldap_handle) { next; }
+        $kernel->yield('next_task', $hit, $ldap_handle);
 
         my $sql = "DELETE FROM $incoming_tn WHERE id=$message_id";
         my $res = $incoming_db->exec_statement($sql);
@@ -2116,42 +2140,33 @@ sub watch_for_next_tasks {
 sub get_ldap_handle {
        my ($session_id) = @_;
        my $heap;
-       my $ldap_handle;
 
        if (not defined $session_id ) { $session_id = 0 };
        if ($session_id =~ /[^0-9]*/) { $session_id = 0 };
 
-       if ($session_id == 0) {
-               daemon_log("$session_id DEBUG: get_ldap_handle invoked without a session_id, create a new ldap_handle", 7); 
-               $ldap_handle = Net::LDAP->new( $ldap_uri );
-               if (defined $ldap_handle) {
-                       $ldap_handle->bind($ldap_admin_dn, password => $ldap_admin_password) or daemon_log("$session_id ERROR: Bind to LDAP $ldap_uri as $ldap_admin_dn failed!"); 
-               } else {
-                       daemon_log("$session_id ERROR: creation of a new LDAP handle failed (ldap_uri '$ldap_uri')");
-               }
-
-       } else {
-               my $session_reference = $global_kernel->ID_id_to_session($session_id);
-               if( defined $session_reference ) {
-                       $heap = $session_reference->get_heap();
-               }
-
-               if (not defined $heap) {
-                       daemon_log("$session_id DEBUG: cannot get heap for session_id '$session_id'", 7); 
-                       return;
-               }
+       (my $package, my $file, my $row, my $subroutine, my $hasArgs, my $wantArray, my $evalText, my $isRequire) = caller(1);
+       my $caller_text = "subroutin $subroutine";
+       if ($subroutine eq "(eval)") {
+               $caller_text = "eval block within file '$file' for '$evalText'"; 
+       }
+       daemon_log("$session_id INFO: new ldap handle for $caller_text required");
 
-               # TODO: This "if" is nonsense, because it doesn't prove that the
-                #       used handle is still valid - or if we've to reconnect...
-               #if (not exists $heap->{ldap_handle}) {
-                       $ldap_handle = Net::LDAP->new( $ldap_uri );
-                       $ldap_handle->bind($ldap_admin_dn, password => $ldap_admin_password) or daemon_log("$session_id ERROR: Bind to LDAP $ldap_uri as $ldap_admin_dn failed!"); 
-                       $heap->{ldap_handle} = $ldap_handle;
-               #}
+       my $ldap_handle = $ldap_pool->get();
+       
+       if (not defined $ldap_handle) {
+               daemon_log("$session_id INFO: ldap handle for $caller_text not available");
        }
+       daemon_log("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
        return $ldap_handle;
 }
 
+sub release_ldap_handle {
+       my ($ldap_handle) = @_ ;
+       $ldap_pool->free($ldap_handle);
+       daemon_log("0 INFO: ldap handle released!\n-------------------------------------------------------------------------------");
+       return;
+}
+
 
 sub change_fai_state {
     my ($st, $targets, $session_id) = @_;
@@ -2177,8 +2192,7 @@ sub change_fai_state {
 
     my $state= $mapActions{ $st };
 
-    my $ldap_handle = &get_ldap_handle($session_id);
-    if( defined($ldap_handle) ) {
+    #if( defined($ldap_handle) ) {
 
       # Build search filter for hosts
         my $search= "(&(objectClass=GOhard)";
@@ -2193,6 +2207,7 @@ sub change_fai_state {
             return;
         }
 
+       my $ldap_handle = &get_ldap_handle($session_id);
       # Perform search for Unit Tag
       my $mesg = $ldap_handle->search(
           base   => $ldap_base,
@@ -2234,11 +2249,12 @@ sub change_fai_state {
          } else {
                daemon_log("$session_id ERROR: LDAP search failed: ldap_base=$ldap_base, filter=$search", 1);
          }
+         &release_ldap_handle($ldap_handle);             
 
     # if no ldap handle defined
-    } else {
-        daemon_log("$session_id ERROR: no LDAP handle defined for update FAIstate", 1); 
-    }
+    #} else {
+    #    daemon_log("$session_id ERROR: no LDAP handle defined for update FAIstate", 1); 
+    #}
 
        return;
 }
@@ -2297,6 +2313,8 @@ sub change_goto_state {
          }
 
     }
+       &release_ldap_handle($ldap_handle);
+       return;
 }
 
 
@@ -2313,24 +2331,29 @@ sub run_recreate_packages_db {
 sub run_create_fai_server_db {
     my ($kernel, $session, $heap, $table_name) = @_[KERNEL, SESSION, HEAP, ARG0];
     my $session_id = $session->ID;
+       my $ldap_handle = &get_ldap_handle();
+       if (not defined $ldap_handle) {
+               $kernel->delay_set('create_fai_server_db', 1, $table_name);
+               return;
+       }
     my $task = POE::Wheel::Run->new(
-            Program => sub { &create_fai_server_db($table_name,$kernel, undef, $session_id) },
+            Program => sub { &create_fai_server_db($table_name,$kernel, undef, $session_id, $ldap_handle) },
             StdoutEvent  => "session_run_result",
             StderrEvent  => "session_run_debug",
             CloseEvent   => "session_run_done",
             );
 
     $heap->{task}->{ $task->ID } = $task;
+       $heap->{ldap_handle}->{$task->ID} = $ldap_handle;
     return;
 }
 
 
 sub create_fai_server_db {
-       my ($table_name, $kernel, $dont_create_packages_list, $session_id) = @_;
+       my ($table_name, $kernel, $dont_create_packages_list, $session_id, $ldap_handle) = @_;
        my $result;
 
        if (not defined $session_id) { $session_id = 0; }
-       my $ldap_handle = &get_ldap_handle();
        if(defined($ldap_handle)) {
                daemon_log("$session_id INFO: create_fai_server_db: start", 5);
                my $mesg= $ldap_handle->search(
@@ -2363,38 +2386,43 @@ sub create_fai_server_db {
 
                # TODO: Find a way to post the 'create_packages_list_db' event
                if(not defined($dont_create_packages_list)) {
-                       &create_packages_list_db(undef, undef, $session_id);
+                       &create_packages_list_db(undef, $session_id);
                }
        }       
 
-       $ldap_handle->disconnect;
        return $result;
 }
 
 
 sub run_create_fai_release_db {
-       my ($session, $heap, $table_name) = @_[SESSION, HEAP, ARG0];
+       my ($kernel, $session, $heap, $table_name) = @_[KERNEL, SESSION, HEAP, ARG0];
        my $session_id = $session->ID;
+       my $ldap_handle = &get_ldap_handle();
+       if (not defined $ldap_handle) {
+               $kernel->delay_set('create_fai_release_db', 1, $table_name);
+               return;
+       }
        my $task = POE::Wheel::Run->new(
-               Program => sub { &create_fai_release_db($table_name, $session_id) },
+               Program => sub { &create_fai_release_db($table_name, $session_id, $ldap_handle) },
                StdoutEvent  => "session_run_result",
                StderrEvent  => "session_run_debug",
                CloseEvent   => "session_run_done",
        );
 
        $heap->{task}->{ $task->ID } = $task;
+       $heap->{ldap_handle}->{$task->ID} = $ldap_handle;
        return;
 }
 
 
 sub create_fai_release_db {
-       my ($table_name, $session_id) = @_;
+       my ($table_name, $session_id, $ldap_handle) = @_;
        my $result;
 
        # used for logging
        if (not defined $session_id) { $session_id = 0; }
 
-       my $ldap_handle = &get_ldap_handle();
+       #my $ldap_handle = &get_ldap_handle();
        if(defined($ldap_handle)) {
                daemon_log("$session_id INFO: create_fai_release_db: start",5);
                my $mesg= $ldap_handle->search(
@@ -2403,8 +2431,10 @@ sub create_fai_release_db {
                        attrs  => [],
                        filter => "(&(objectClass=organizationalUnit)(ou=fai))",
                );
-               if($mesg->{'resultCode'} == 0 &&
-                       $mesg->count != 0) {
+               if(($mesg->code == 0) && ($mesg->count != 0))
+               {
+                       daemon_log("$session_id DEBUG: create_fai_release_db: count " . $mesg->count,8);
+
                        # Walk through all possible FAI container ou's
                        my @sql_list;
                        my $timestamp= &get_time();
@@ -2430,16 +2460,19 @@ sub create_fai_release_db {
                                }
                        }
 
-                       daemon_log("$session_id DEBUG: Inserting ".scalar @sql_list." entries to DB",8);
+                       daemon_log("$session_id DEBUG: create_fai_release_db: Inserting ".scalar @sql_list." entries to DB",8);
                        if(@sql_list) {
+                               unshift @sql_list, "VACUUM";
                                unshift @sql_list, "DELETE FROM $table_name";
                                $fai_release_db->exec_statementlist(\@sql_list);
                        }
-                       daemon_log("$session_id DEBUG: Done with inserting",7);
+                       daemon_log("$session_id DEBUG: create_fai_release_db: Done with inserting",7);
+               } else {
+                       daemon_log("$session_id INFO: create_fai_release_db: error: " . $mesg->code, 5);
                }
                daemon_log("$session_id INFO: create_fai_release_db: finished",5);
        }
-       $ldap_handle->disconnect;
+       #&release_ldap_handle($ldap_handle);
        return $result;
 }
 
@@ -2498,9 +2531,11 @@ sub resolve_fai_classes {
                foreach my $entry (@{$mesg->{entries}}) {
                        if($entry->exists('cn')) {
                                my $tmp_dn= $entry->dn();
+                               $tmp_dn= substr( $tmp_dn, 0, length($tmp_dn)
+                                       - length($fai_base) - 1 );
 
                                # Skip classname and ou dn parts for class
-                               my $tmp_release = ($1) if $tmp_dn =~ /^[^,]+,[^,]+,(.*?),$fai_base$/;
+                               my $tmp_release = ($1) if $tmp_dn =~ /^[^,]+,[^,]+,(.*?)$/;
 
                                # Skip classes without releases
                                if((!defined($tmp_release)) || length($tmp_release)==0) {
@@ -2535,7 +2570,9 @@ sub resolve_fai_classes {
                                }
                        } elsif (!$entry->exists('cn')) {
                                my $tmp_dn= $entry->dn();
-                               my $tmp_release = ($1) if $tmp_dn =~ /^(.*?),$fai_base$/;
+                               $tmp_dn= substr( $tmp_dn, 0, length($tmp_dn)
+                                       - length($fai_base) - 1 );
+                               my $tmp_release = ($1) if $tmp_dn =~ /^(.*?)$/;
 
                                # Skip classes without releases
                                if((!defined($tmp_release)) || length($tmp_release)==0) {
@@ -2680,12 +2717,15 @@ sub session_run_debug {
 sub session_run_done {
     my ( $kernel, $heap, $task_id ) = @_[ KERNEL, HEAP, ARG0 ];
     delete $heap->{task}->{$task_id};
+       if (exists $heap->{ldap_handle}->{$task_id}) {
+               &release_ldap_handle($heap->{ldap_handle}->{$task_id});
+       }
+       delete $heap->{ldap_handle}->{$task_id};
 }
 
 
 sub create_sources_list {
        my $session_id = shift;
-       my $ldap_handle = &main::get_ldap_handle;
        my $result="/tmp/gosa_si_tmp_sources_list";
 
        # Remove old file
@@ -2701,12 +2741,14 @@ sub create_sources_list {
                return undef;
        }
        if(defined($main::ldap_server_dn) and length($main::ldap_server_dn) > 0) {
+               my $ldap_handle = &get_ldap_handle();
                my $mesg=$ldap_handle->search(
                        base    => $main::ldap_server_dn,
                        scope   => 'base',
                        attrs   => 'FAIrepository',
                        filter  => 'objectClass=FAIrepositoryServer'
                );
+               &release_ldap_handle($ldap_handle);
                if($mesg->count) {
                        foreach my $entry(@{$mesg->{'entries'}}) {
                                foreach my $value(@{$entry->get_value('FAIrepository', asref => 1)}) {
@@ -2734,10 +2776,9 @@ sub create_sources_list {
 sub run_create_packages_list_db {
     my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
        my $session_id = $session->ID;
-
        my $task = POE::Wheel::Run->new(
                                        Priority => +20,
-                                       Program => sub {&create_packages_list_db(undef, undef, $session_id)},
+                                       Program => sub {&create_packages_list_db(undef, $session_id)},
                                        StdoutEvent  => "session_run_result",
                                        StderrEvent  => "session_run_debug",
                                        CloseEvent   => "session_run_done",
@@ -2747,7 +2788,7 @@ sub run_create_packages_list_db {
 
 
 sub create_packages_list_db {
-       my ($ldap_handle, $sources_file, $session_id) = @_;
+       my ($sources_file, $session_id) = @_;
        
        # it should not be possible to trigger a recreation of packages_list_db
        # while packages_list_db is under construction, so set flag packages_list_under_construction
@@ -2763,15 +2804,7 @@ sub create_packages_list_db {
        }
 
        if (not defined $session_id) { $session_id = 0; }
-       if (not defined $ldap_handle) { 
-               $ldap_handle= &get_ldap_handle();
 
-               if (not defined $ldap_handle) {
-                       daemon_log("$session_id ERROR: no ldap_handle available to create_packages_list_db", 1);
-                       unlink($packages_list_under_construction);
-                       return;
-               }
-       }
        if (not defined $sources_file) { 
                &main::daemon_log("$session_id INFO: no sources_file given for creating packages list so trigger creation of it", 5); 
                $sources_file = &create_sources_list($session_id);
@@ -2958,6 +2991,8 @@ sub strip_packages_list_statements {
                }
        }
 
+       unshift(@new_statement_list, "VACUUM");
+
        @packages_list_statements = @new_statement_list;
 }
 
@@ -2992,7 +3027,7 @@ sub get_package {
         unlink($dest);
         daemon_log("$session_id DEBUG: delete file '$dest'", 5); 
     } else {
-        daemon_log("$session_id ERROR: create_packages_list_db: get_packages: fetching '$url' failed!", 1);
+        daemon_log("$session_id ERROR: create_packages_list_db: get_packages: fetching '$url' into '$dest' failed!", 1);
     }
     return 0;
 }
@@ -3225,11 +3260,12 @@ if ($server_headURL =~ /\/tag\// ||
 } else {
     $server_status = "developmental" ;
 }
-
-# Prepare log file
+# Prepare log file and set permissions
 $root_uid = getpwnam('root');
 $adm_gid = getgrnam('adm');
-chmod(0640, $log_file);
+open(FH, ">>$log_file");
+close FH;
+chmod(0440, $log_file);
 chown($root_uid, $adm_gid, $log_file);
 chown($root_uid, $adm_gid, "/var/lib/gosa-si");
 
@@ -3238,6 +3274,18 @@ daemon_log("$0 started!", 1);
 daemon_log("status: $server_status", 1);
 daemon_log($server_status_hash->{$server_status}.": $server_revision", 1); 
 
+# Create a pool of LDAP handles
+$ldap_factory =  ResourcePool::Factory::Net::LDAP->new($ldap_uri, version => $ldap_version);
+$ldap_factory->bind($ldap_admin_dn, password=>$ldap_admin_password);
+$ldap_pool = ResourcePool->new($ldap_factory,
+               Max         => 10,
+               #MaxTry      => 1,
+               #SleepOnFail    => [0, 0, 1, 1],
+               PreCreate       => 5,
+);
+
+
+# Buildup data bases
 {
     no strict "refs";
 
@@ -3280,60 +3328,61 @@ daemon_log($server_status_hash->{$server_status}.": $server_revision", 1);
         # connect to gosa-si job queue
         unlink($job_queue_file_name);  ## just for debugging
         $job_db = GOSA::DBsqlite->new($job_queue_file_name);
-        chmod(0660, $job_queue_file_name);
+        chmod(0640, $job_queue_file_name);
         chown($root_uid, $adm_gid, $job_queue_file_name);
         
         # connect to known_clients_db
         unlink($known_clients_file_name);   ## just for debugging
         $known_clients_db = GOSA::DBsqlite->new($known_clients_file_name);
-        chmod(0660, $known_clients_file_name);
+        chmod(0640, $known_clients_file_name);
         chown($root_uid, $adm_gid, $known_clients_file_name);
         
         # connect to foreign_clients_db
         unlink($foreign_clients_file_name);
         $foreign_clients_db = GOSA::DBsqlite->new($foreign_clients_file_name);
-        chmod(0660, $foreign_clients_file_name);
+        chmod(0640, $foreign_clients_file_name);
         chown($root_uid, $adm_gid, $foreign_clients_file_name);
         
         # connect to known_server_db
         unlink($known_server_file_name);
         $known_server_db = GOSA::DBsqlite->new($known_server_file_name);
-        chmod(0660, $known_server_file_name);
+        chmod(0640, $known_server_file_name);
         chown($root_uid, $adm_gid, $known_server_file_name);
         
         # connect to login_usr_db
         unlink($login_users_file_name);
         $login_users_db = GOSA::DBsqlite->new($login_users_file_name);
-        chmod(0660, $login_users_file_name);
+        chmod(0640, $login_users_file_name);
         chown($root_uid, $adm_gid, $login_users_file_name);
         
         # connect to fai_server_db
         unlink($fai_server_file_name);
         $fai_server_db = GOSA::DBsqlite->new($fai_server_file_name);
-        chmod(0660, $fai_server_file_name);
+        chmod(0640, $fai_server_file_name);
         chown($root_uid, $adm_gid, $fai_server_file_name);
         
         # connect to fai_release_db
         unlink($fai_release_file_name);
         $fai_release_db = GOSA::DBsqlite->new($fai_release_file_name);
-        chmod(0660, $fai_release_file_name);
+        chmod(0640, $fai_release_file_name);
         chown($root_uid, $adm_gid, $fai_release_file_name);
         
         # connect to packages_list_db
         #unlink($packages_list_file_name);
         unlink($packages_list_under_construction);
         $packages_list_db = GOSA::DBsqlite->new($packages_list_file_name);
-        chmod(0660, $packages_list_file_name);
+        chmod(0640, $packages_list_file_name);
         chown($root_uid, $adm_gid, $packages_list_file_name);
         
         # connect to messaging_db
         unlink($messaging_file_name);
         $messaging_db = GOSA::DBsqlite->new($messaging_file_name);
-        chmod(0660, $messaging_file_name);
+        chmod(0640, $messaging_file_name);
         chown($root_uid, $adm_gid, $messaging_file_name);
     }
 }
 
+
 # Creating tables
 $messaging_db->create_table($messaging_tn, \@messaging_col_names);
 $packages_list_db->create_table($packages_list_tn, \@packages_list_col_names);
@@ -3346,7 +3395,6 @@ $known_clients_db->create_table($known_clients_tn, \@known_clients_col_names);
 $incoming_db->create_table($incoming_tn, \@incoming_col_names);
 $job_db->create_table($job_queue_tn, \@job_queue_col_names);
 
-
 # create xml object used for en/decrypting
 $xml = new XML::Simple();
 
@@ -3405,7 +3453,7 @@ my $all_foreign_server = join(", ", @foreign_server_list);
 daemon_log("0 INFO: found foreign server in config file and DNS: '$all_foreign_server'", 5);
 
 # add all found foreign servers to known_server
-my $act_timestamp = &get_time();
+my $cur_timestamp = &get_time();
 foreach my $foreign_server (@foreign_server_list) {
 
        # do not add myself to known_server_db
@@ -3416,10 +3464,10 @@ foreach my $foreign_server (@foreign_server_list) {
             primkey=>['hostname'],
             hostname=>$foreign_server,
             macaddress=>"",
-            status=>'not_jet_registered',
+            status=>'not_yet_registered',
             hostkey=>"none",
             loaded_modules => "none", 
-            timestamp=>$act_timestamp,
+            timestamp=>$cur_timestamp,
             } );
 }