Code

* Fix LDAP search filter escaping
[gosa.git] / gosa-si / modules / ClientPackages.pm
index 8d4b7e805fb482cc227fdbd5841138a50c759ced..08c8689357e994930ba38f38eac978b39723abd0 100644 (file)
@@ -13,6 +13,7 @@ use XML::Simple;
 use Data::Dumper;
 use NetAddr::IP;
 use Net::LDAP;
+use Net::LDAP::Util;
 use Socket;
 use Net::hostent;
 
@@ -49,7 +50,7 @@ my %cfg_defaults = (
 ### START #####################################################################
 
 # read configfile and import variables
-&read_configfile();
+&local_read_configfile();
 
 
 # if server_ip is not an ip address but a name
@@ -60,14 +61,20 @@ $main::server_mac_address= &get_mac($network_interface);
 
 # import local events
 my ($error, $result, $event_hash) = &import_events($event_dir);
-if ($error == 0) {
-    foreach my $log_line (@$result) {
+
+foreach my $log_line (@$result) {
+    if ($log_line =~ / succeed: /) {
         &main::daemon_log("0 DEBUG: ClientPackages - $log_line", 7);
-    }
-} else {
-    foreach my $log_line (@$result) {
+    } else {
         &main::daemon_log("0 ERROR: ClientPackages - $log_line", 1);
     }
+}
+# build vice versa event_hash, event_name => module
+my $event2module_hash = {};
+while (my ($module, $mod_events) = each %$event_hash) {
+    while (my ($event_name, $nothing) = each %$mod_events) {
+        $event2module_hash->{$event_name} = $module;
+    }
 
 }
 
@@ -153,18 +160,19 @@ $main::server_address = $server_address;
 sub get_module_info {
     my @info = ($server_address,
                 $ClientPackages_key,
+                $event_hash,
                 );
     return \@info;
 }
 
 
 #===  FUNCTION  ================================================================
-#         NAME:  read_configfile
+#         NAME:  local_read_configfile
 #   PARAMETERS:  cfg_file - string -
 #      RETURNS:  nothing
 #  DESCRIPTION:  read cfg_file and set variables
 #===============================================================================
-sub read_configfile {
+sub local_read_configfile {
     my $cfg;
     if( defined( $main::cfg_file) && ( (-s $main::cfg_file) > 0 )) {
         if( -r $main::cfg_file ) {
@@ -286,10 +294,10 @@ sub process_incoming_msg {
                 @out_msg_l = &here_i_am($msg, $msg_hash, $session_id)
             } else {
                 # a event exists with the header as name
-                if( exists $event_hash->{$header} ) {
-                    &main::daemon_log("$session_id INFO: found event '$header' at event-module '".$event_hash->{$header}."'", 5);
+                if( exists $event2module_hash->{$header} ) {
+                    &main::daemon_log("$session_id INFO: found event '$header' at event-module '".$event2module_hash->{$header}."'", 5);
                     no strict 'refs';
-                    @out_msg_l = &{$event_hash->{$header}."::$header"}($msg, $msg_hash, $session_id);
+                    @out_msg_l = &{$event2module_hash->{$header}."::$header"}($msg, $msg_hash, $session_id);
 
                 # if no event handler is implemented   
                 } else {
@@ -331,10 +339,10 @@ sub process_incoming_msg {
                 @out_msg_l = ();
             }  elsif ($out_msg_l[0] eq 'knownclienterror') {
                 &main::daemon_log("$session_id ERROR: no or more than 1 hits are found at known_clients_db with sql query: '$sql_events'", 1);
-                &main::daemon_log("$session_id WARNING: processing is aborted and message will not be forwarded");
+                &main::daemon_log("$session_id ERROR: processing is aborted and message will not be forwarded", 1);
                 @out_msg_l = ();
             } elsif ($out_msg_l[0] eq 'noeventerror') {
-                &main::daemon_log("$session_id WARNING: client '$target' is not registered for event '$header', processing is aborted", 1); 
+                &main::daemon_log("$session_id ERROR: client '$target' is not registered for event '$header', processing is aborted", 1); 
                 @out_msg_l = ();
             }
 
@@ -421,12 +429,19 @@ sub here_i_am {
     my $key_lifetime = @{$msg_hash->{key_lifetime}}[0];
 
     # Move forced hostname to heap - if used
-    #if ( defined($msg_hash->{'force-hostname'}[0]) &&
-    #   length($msg_hash->{'force-hostname'}[0]) > 0){
+    #FIXME: move to some global POE namespace - please
+    if ( defined($msg_hash->{'force-hostname'}[0]) &&
+       length($msg_hash->{'force-hostname'}[0]) > 0){
     #      $heap->{force-hostname}->{$mac_address}= $msg_hash->{'force-hostname'}[0];
-    #} else {
+           open (TFILE, ">/var/tmp/$mac_address");
+           print TFILE $msg_hash->{'force-hostname'}[0];
+           close (TFILE); 
+    } else {
     #      $heap->{force-hostname}->{$mac_address}= undef;
-    #}
+       if ( -e "/var/tmp/$mac_address") {
+               unlink("/var/tmp/$mac_address")
+       }; 
+    }
 
     # number of known clients
     my $nu_clients= $main::known_clients_db->count_dbentries('known_clients');
@@ -503,11 +518,24 @@ sub here_i_am {
             push(@out_msg_l, $new_ldap_config_out);
     }
 
+    # Send client hardware configuration
        my $hardware_config_out = &hardware_config($msg, $msg_hash, $session_id);
        if( $hardware_config_out ) {
                push(@out_msg_l, $hardware_config_out);
        }
 
+    # Send client ntp server
+    my $ntp_config_out = &new_ntp_config($mac_address, $session_id);
+    if ($ntp_config_out) {
+        push(@out_msg_l, $ntp_config_out);
+    }
+
+    # Send client syslog server
+    my $syslog_config_out = &new_syslog_config($mac_address, $session_id);
+    if ($syslog_config_out) {
+        push(@out_msg_l, $syslog_config_out);
+    }
+
     # notify registered client to all other server
     my %mydata = ( 'client' => $source, 'macaddress' => $mac_address);
     my $mymsg = &build_msg('new_foreign_client', $main::server_address, "KNOWN_SERVER", \%mydata);
@@ -568,6 +596,159 @@ sub who_has_i_do {
 }
 
 
+sub new_syslog_config {
+    my ($mac_address, $session_id) = @_;
+    my $syslog_msg;
+
+       # Build LDAP connection
+    my $ldap_handle = &main::get_ldap_handle($session_id);
+       if( not defined $ldap_handle ) {
+               &main::daemon_log("$session_id ERROR: cannot connect to ldap: $ldap_uri", 1);
+               return;
+       }
+
+       # Perform search
+    my $ldap_res = $ldap_handle->search( base   => $ldap_base,
+               scope  => 'sub',
+               attrs => ['gotoSyslogServer'],
+               filter => "(&(objectClass=GOhard)(macaddress=$mac_address))");
+       if($ldap_res->code) {
+               &main::daemon_log("$session_id ".$ldap_res->error, 1);
+               return;
+       }
+
+       # Sanity check
+       if ($ldap_res->count != 1) {
+               &main::daemon_log("$session_id ERROR: client with mac address $mac_address not found/unique/active - not sending syslog config".
+                "\n\tbase: $ldap_base".
+                "\n\tscope: sub".
+                "\n\tattrs: gotoSyslogServer".
+                "\n\tfilter: (&(objectClass=GOhard)(macaddress=$mac_address))", 1);
+               return;
+       }
+
+       my $entry= $ldap_res->entry(0);
+    my $filter_dn = &Net::LDAP::Util::escape_filter_value($entry->dn);
+       my $syslog_server = $entry->get_value("gotoSyslogServer");
+
+    # If no syslog server is specified at host, just have a look at the object group of the host
+    # Perform object group search
+    if (not defined $syslog_server) {
+        my $ldap_res = $ldap_handle->search( base   => $ldap_base,
+                scope  => 'sub',
+                attrs => ['gotoSyslogServer'],
+                filter => "(&(objectClass=gosaGroupOfNames)(member=$filter_dn))");
+        if($ldap_res->code) {
+            &main::daemon_log("$session_id ".$ldap_res->error, 1);
+            return;
+        }
+
+        # Sanity check
+        if ($ldap_res->count != 1) {
+            &main::daemon_log("$session_id ERROR: client with mac address $mac_address not found/unique/active - not sending syslog config".
+                    "\n\tbase: $ldap_base".
+                    "\n\tscope: sub".
+                    "\n\tattrs: gotoSyslogServer".
+                    "\n\tfilter: (&(objectClass=gosaGroupOfNames)(member=$filter_dn))", 1);
+            return;
+        }
+
+        my $entry= $ldap_res->entry(0);
+        $syslog_server= $entry->get_value("gotoSyslogServer");
+    }
+
+    # Return if no syslog server specified
+    if (not defined $syslog_server) {
+        &main::daemon_log("$session_id WARNING: no syslog server specified for this host '$mac_address'", 3);
+        return;
+    }
+
+    # Add syslog server to 'syslog_config' message
+    my $syslog_msg_hash = &create_xml_hash("new_syslog_config", $server_address, $mac_address);
+    &add_content2xml_hash($syslog_msg_hash, "server", $syslog_server);
+
+    return &create_xml_string($syslog_msg_hash);
+}
+
+
+sub new_ntp_config {
+    my ($address, $session_id) = @_;
+    my $ntp_msg;
+
+       # Build LDAP connection
+    my $ldap_handle = &main::get_ldap_handle($session_id);
+       if( not defined $ldap_handle ) {
+               &main::daemon_log("$session_id ERROR: cannot connect to ldap: $ldap_uri", 1);
+               return;
+       }
+
+       # Perform search
+    my $ldap_res = $ldap_handle->search( base   => $ldap_base,
+               scope  => 'sub',
+               attrs => ['gotoNtpServer'],
+               filter => "(&(objectClass=GOhard)(macaddress=$address))");
+       if($ldap_res->code) {
+               &main::daemon_log("$session_id ".$ldap_res->error, 1);
+               return;
+       }
+
+       # Sanity check
+       if ($ldap_res->count != 1) {
+               &main::daemon_log("$session_id ERROR: client with mac address $address not found/unique/active - not sending ntp config".
+                "\n\tbase: $ldap_base".
+                "\n\tscope: sub".
+                "\n\tattrs: gotoNtpServer".
+                "\n\tfilter: (&(objectClass=GOhard)(macaddress=$address))", 1);
+               return;
+       }
+
+       my $entry= $ldap_res->entry(0);
+    my $filter_dn = &Net::LDAP::Util::escape_filter_value($entry->dn);
+       my @ntp_servers= $entry->get_value("gotoNtpServer");
+
+    # If no ntp server is specified at host, just have a look at the object group of the host
+    # Perform object group search
+    if ((not @ntp_servers) || (@ntp_servers == 0)) {
+        my $ldap_res = $ldap_handle->search( base   => $ldap_base,
+                scope  => 'sub',
+                attrs => ['gotoNtpServer'],
+                filter => "(&(objectClass=gosaGroupOfNames)(member=$filter_dn))");
+        if($ldap_res->code) {
+            &main::daemon_log("$session_id ".$ldap_res->error, 1);
+            return;
+        }
+
+        # Sanity check
+        if ($ldap_res->count != 1) {
+            &main::daemon_log("$session_id ERROR: client with mac address $address not found/unique/active - not sending ntp config".
+                    "\n\tbase: $ldap_base".
+                    "\n\tscope: sub".
+                    "\n\tattrs: gotoNtpServer".
+                    "\n\tfilter: (&(objectClass=gosaGroupOfNames)(member=$filter_dn))", 1);
+            return;
+        }
+
+        my $entry= $ldap_res->entry(0);
+        @ntp_servers= $entry->get_value("gotoNtpServer");
+    }
+
+    # Return if no ntp server specified
+    if ((not @ntp_servers) || (@ntp_servers == 0)) {
+        &main::daemon_log("$session_id WARNING: no ntp server specified for this host '$address'", 3);
+        return;
+    }
+    # Add each ntp server to 'ntp_config' message
+    my $ntp_msg_hash = &create_xml_hash("new_ntp_config", $server_address, $address);
+    foreach my $ntp_server (@ntp_servers) {
+        &add_content2xml_hash($ntp_msg_hash, "server", $ntp_server);
+    }
+
+    return &create_xml_string($ntp_msg_hash);
+}
+
+
 #===  FUNCTION  ================================================================
 #         NAME:  new_ldap_config
 #   PARAMETERS:  address - string - ip address and port of a host
@@ -584,6 +765,7 @@ sub new_ldap_config {
        my $hit_counter = keys %{$res};
        if( not $hit_counter == 1 ) {
                &main::daemon_log("$session_id ERROR: more or no hit found in known_clients_db by query '$sql_statement'", 1);
+        return;
        }
 
     $address = $res->{1}->{hostname};
@@ -614,7 +796,7 @@ sub new_ldap_config {
 
        # Sanity check
        if ($mesg->count != 1) {
-               &main::daemon_log("$session_id WARNING: client with mac address $macaddress not found/unique/active - not sending ldap config".
+               &main::daemon_log("$session_id ERROR: client with mac address $macaddress not found/unique/active - not sending ldap config".
                 "\n\tbase: $ldap_base".
                 "\n\tscope: sub".
                 "\n\tattrs: dn, gotoLdapServer".
@@ -623,13 +805,14 @@ sub new_ldap_config {
        }
 
        my $entry= $mesg->entry(0);
-       my $dn= $entry->dn;
+       my $filter_dn= &Net::LDAP::Util::escape_filter_value($entry->dn);
        my @servers= $entry->get_value("gotoLdapServer");
        my $unit_tag= $entry->get_value("gosaUnitTag");
        my @ldap_uris;
        my $server;
        my $base;
        my $release;
+    my $dn= $entry->dn;
 
        # Fill release if available
        my $FAIclass= $entry->get_value("FAIclass");
@@ -642,18 +825,19 @@ sub new_ldap_config {
                $mesg = $ldap_handle->search( base   => $ldap_base,
                        scope  => 'sub',
                        attrs => ['dn', 'gotoLdapServer', 'FAIclass'],
-                       filter => "(&(objectClass=gosaGroupOfNames)(member=$dn))");
+                       filter => "(&(objectClass=gosaGroupOfNames)(member=$filter_dn))");
                if($mesg->code) {
-                       &main::daemon_log("$session_id ERROR: unable to search for '(&(objectClass=gosaGroupOfNames)(member=$dn))': ".$mesg->error, 1);
+                       &main::daemon_log("$session_id ERROR: unable to search for '(&(objectClass=gosaGroupOfNames)(member=$filter_dn))': ".$mesg->error, 1);
                        return;
                }
 
                # Sanity check
-               if ($mesg->count == 0) {
-                       &main::daemon_log("$session_id WARNING: no LDAP informations found for client  with filter '(&(objectClass=gosaGroupOfNames)(member=$dn))'", 3);
-                       return;
-               } elsif ($mesg->count >= 2) {
-            &main::daemon_log("$session_id ERROR: multiple LDAP informations found for client  with filter '(&(objectClass=gosaGroupOfNames)(member=$dn))'", 1);
+        if ($mesg->count != 1) {
+            &main::daemon_log("$session_id ERROR: client with mac address $macaddress not found/unique/active - not sending ldap config".
+                    "\n\tbase: $ldap_base".
+                    "\n\tscope: sub".
+                    "\n\tattrs: dn, gotoLdapServer, FAIclass".
+                    "\n\tfilter: (&(objectClass=gosaGroupOfNames)(member=$filter_dn))", 1);
             return;
         }
 
@@ -673,7 +857,7 @@ sub new_ldap_config {
 
     # complain if no ldap information found
     if (@servers == 0) {
-        &main::daemon_log("$session_id ERROR: no gotoLdapServer information for LDAP entry with filter '(&(objectClass=gosaGroupOfNames)(member=$dn))'");
+        &main::daemon_log("$session_id ERROR: no gotoLdapServer information for LDAP entry '$dn'", 1);
     }
 
        foreach $server (@servers){
@@ -805,7 +989,6 @@ sub hardware_config {
        
        } else {
                my $entry= $mesg->entry(0);
-               my $dn= $entry->dn;
                if (defined($entry->get_value("gotoHardwareChecksum"))) {
                        if (! $entry->get_value("gotoHardwareChecksum") eq $gotoHardwareChecksum) {
                                $entry->replace(gotoHardwareChecksum => $gotoHardwareChecksum);