Code

new fifo at gosa-si-client, all input is wrapped in a gosa-si valid envelope and...
[gosa.git] / gosa-si / gosa-si-client
index 454b1b765996b4ee94a73cdd8e317d7b1b17d6dc..27de3ab341ee1a12ad2ad98bf5a3c441f7166097 100755 (executable)
@@ -25,7 +25,7 @@ use Config::IniFiles;
 use POSIX;
 use Time::HiRes qw( gettimeofday );
 
-use POE qw(Component::Server::TCP);
+use POE qw(Component::Server::TCP Wheel::FollowTail);
 use IO::Socket::INET;
 use NetAddr::IP;
 use Data::Dumper;
@@ -35,6 +35,7 @@ use Digest::MD5  qw(md5_hex md5 md5_base64);
 use MIME::Base64;
 use XML::Simple;
 use Net::DNS;
+use File::Basename;
 
 my $event_dir = "/usr/lib/gosa-si/client/events";
 use lib "/usr/lib/gosa-si/client/events";
@@ -47,6 +48,8 @@ my $default_server_key;
 my $event_hash;
 my @servers;
 my $gotoHardwareChecksum;
+my $gosa_si_client_fifo;
+my %files_to_watch;
 $verbose= 1;
 
 # globalise variables which are used in imported events
@@ -58,15 +61,20 @@ our $server_key;
 # default variables
 our $REGISTERED = 0;
 
+# path to fifo for non-gosa-si-client messages to gosa-si-server
+$gosa_si_client_fifo = "/tmp/gosa-si-client-fifo";
+%files_to_watch = (fifo => $gosa_si_client_fifo); 
+
 # in function register_at_gosa_si_server, after which period of seconds a new registration should be tried if a registration was 
 # not successful until now
 my $delay_set_time = 5;
+our $prg= basename($0);
 
 %cfg_defaults = (
 "general" =>
-    {"log-file"           => [\$log_file, "/var/run/".$0.".log"],
-    "pid-file"            => [\$pid_file, "/var/run/".$0.".pid"],
-    "opts-file"            => [\$opts_file, "/var/run/".$0.".opts"],
+    {"log-file"           => [\$log_file, "/var/run/".$prg.".log"],
+    "pid-file"            => [\$pid_file, "/var/run/".$prg.".pid"],
+    "opts-file"            => [\$opts_file, "/var/run/".$prg.".opts"],
     },
 "client" => 
     {"port"        => [\$client_port, "20083"],
@@ -222,10 +230,8 @@ sub daemon_log {
                 $month = $monthnames[$month];
                 $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday;
                 $year+=1900;
-                my $name = $0;
-                $name =~ s/\.\///;
 
-                my $log_msg = "$month $monthday $hours:$minutes:$seconds $name $msg\n";
+                my $log_msg = "$month $monthday $hours:$minutes:$seconds $prg $msg\n";
                 print LOG_HANDLE $log_msg;
                 if( $foreground ) { 
                     print STDERR $log_msg;
@@ -809,11 +815,11 @@ sub write_to_file {
     my $error = 0;
 
     if( not defined $file || not -f $file ) {
-        &main::daemon_log("ERROR: $0: check '-f file' failed: $file", 1);
+        &main::daemon_log("ERROR: $prg: check '-f file' failed: $file", 1);
         $error++;
     }
     if( not defined $string || 0 == length($string)) {
-        &main::daemon_log("ERROR: $0: empty string to write to file '$file'", 1);
+        &main::daemon_log("ERROR: $prg: empty string to write to file '$file'", 1);
         $error++;
     }
     
@@ -913,10 +919,13 @@ sub register_at_gosa_si_server {
                                        unlink($opts_file);
                                }
                                my $opts_file_FH;
+                               my $hostname= $dnsname;
+                               $hostname =~ s/\..*$//;
                                open($opts_file_FH, ">$opts_file");
                                print $opts_file_FH "MAC=\"$local_mac\"\n";
                                print $opts_file_FH "IPADDRESS=\"$client_ip\"\n";
-                               print $opts_file_FH "HOSTNAME=\"$dnsname\"\n";
+                               print $opts_file_FH "HOSTNAME=\"$hostname\"\n";
+                               print $opts_file_FH "FQDN=\"$dnsname\"\n";
                                close($opts_file_FH);
                                last;
                        } else {
@@ -955,6 +964,7 @@ sub check_key_and_xml_validity {
 
         $msg_hash = $xml->XMLin($msg, ForceArray=>1);
 
+        ##############
         # check header
         my $header_l = $msg_hash->{'header'};
         if( 1 != @{$header_l} ) {
@@ -965,36 +975,102 @@ sub check_key_and_xml_validity {
             die 'header has length 0';
         }
 
+        ##############
         # check source
         my $source_l = $msg_hash->{'source'};
         if( 1 != @{$source_l} ) {
-            die 'no or more sources specified';
+            die 'no or more than 1 sources specified';
         }
         my $source = @{$source_l}[0];
         if( 0 == length $source) {
             die 'source has length 0';
         }
-
-        # check target
+        unless( $source =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$/ ) {
+            die "source '$source' is neither a complete ip-address with port nor 'GOSA'";
+        }
+        
+        ##############
+        # check target  
         my $target_l = $msg_hash->{'target'};
         if( 1 != @{$target_l} ) {
-            die 'no or more targets specified ';
+            die 'no or more than 1 targets specified ';
         }
         my $target = @{$target_l}[0];
         if( 0 == length $target) {
             die 'target has length 0 ';
         }
-
+        unless( $target =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$/ ){
+            die "source is neither a complete ip-address with port nor 'GOSA'";
+        }
     };
     if($@) {
         &main::daemon_log("WARNING: do not understand the message or msg is not gosa-si envelope conform:", 5);
         &main::daemon_log("$@", 8);
+        $msg = undef;
+        $msg_hash = undef;
     }
 
     return ($msg, $msg_hash);
 }
 
 
+sub check_outgoing_xml_validity {
+    my ($msg) = @_;
+
+    my $msg_hash;
+    eval{
+        $msg_hash = $xml->XMLin($msg, ForceArray=>1);
+
+        ##############
+        # check header
+        my $header_l = $msg_hash->{'header'};
+        if( 1 != @{$header_l} ) {
+            die 'no or more than one headers specified';
+        }
+        my $header = @{$header_l}[0];
+        if( 0 == length $header) {
+            die 'header has length 0';
+        }
+
+        ##############
+        # check source
+        my $source_l = $msg_hash->{'source'};
+        if( 1 != @{$source_l} ) {
+            die 'no or more than 1 sources specified';
+        }
+        my $source = @{$source_l}[0];
+        if( 0 == length $source) {
+            die 'source has length 0';
+        }
+        unless( $source =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$/ ||
+                $source =~ /^GOSA$/i ) {
+            die "source '$source' is neither a complete ip-address with port";
+        }
+        
+        ##############
+        # check target  
+        my $target_l = $msg_hash->{'target'};
+        if( 1 != @{$target_l} ) {
+            die "no or more than one targets specified";
+        }
+        foreach my $target (@$target_l) {
+            if( 0 == length $target) {
+                die "target has length 0";
+            }
+            unless( $target =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$/ ) {
+                die "target '$target' is not a complete ip-address with port or a valid target name";
+            }
+        }
+    };
+    if($@) {
+        daemon_log("WARNING: outgoing msg is not gosa-si envelope conform", 5);
+        daemon_log("$@ $msg", 8);
+        $msg_hash = undef;
+    }
+    return ($msg_hash);
+}
+
+
 sub import_events {
 
     if (not -e $event_dir) {
@@ -1033,10 +1109,56 @@ sub trigger_new_key {
 }
 
 
+sub generic_file_reset {
+    my ( $heap, $wheel_id ) = @_[ HEAP, ARG0 ];
+
+    my $service = $heap->{services}->{$wheel_id};
+    daemon_log("INFO: '$service' watching reset", 5);
+    return;
+}
+
+sub generic_file_error {
+    my ( $heap, $operation, $errno, $error_string, $wheel_id ) =
+      @_[ HEAP, ARG0, ARG1, ARG2, ARG3 ];
+
+    my $service = $heap->{services}->{$wheel_id};
+    daemon_log("ERROR: '$service' watcher $operation error $errno: $error_string", 1);
+    daemon_log("ERROR: shutting down '$service' file watcher", 1);
+
+    delete $heap->{services}->{$wheel_id};
+    delete $heap->{watchers}->{$wheel_id};
+    return;
+}
+
+sub fifo_got_record {
+    my $file_record = $_[ARG0];
+    print STDERR "$file_record\n";
+
+    my $clmsg_hash = &create_xml_hash("CLMSG_$file_record", $client_address, $server_address);
+    my $clmsg = &create_xml_string($clmsg_hash);
+    &send_msg_to_target($clmsg, $server_address, $server_key);
+    return;
+}
+
+
 sub _start {
-    my ($kernel) = $_[KERNEL];
+    my ($kernel, $heap) = @_[KERNEL, HEAP];
     $kernel->alias_set('client_session');
+    
+    # force a registration at a gosa-si-server
     $kernel->yield('register_at_gosa_si_server');
+    
+    # install all file watcher defined
+    while( my($file_name, $file) = each %files_to_watch ) {
+        my $file_watcher = POE::Wheel::FollowTail->new(
+            Filename   => $file,
+            InputEvent => $file_name."_record",
+            ResetEvent => "file_reset",
+            ErrorEvent => "file_error",
+            );
+        $heap->{services}->{ $file_watcher->ID } = $file_name;
+        $heap->{watchers}->{ $file_watcher->ID } = $file_watcher;
+    }
 }
 
 
@@ -1074,21 +1196,31 @@ sub server_input {
     ########
     # answer
     if( $answer ) {
-        # preprocessing
-        if( $answer =~ "<header>registered</header>") {
-            # set registered flag to true to stop sending further registered msgs
-            $REGISTERED = 1;
-        } 
-        else {
-            &send_msg_to_target($answer, $server_address, $server_key);
-        }
-        # postprocessing
-        if( $answer =~ "<header>new_key</header>") {
-            # set new key to global variable
-            $answer =~ /<new_key>(\S*?)<\/new_key>/;
-            my $new_key = $1;
-            $server_key = $new_key;
+
+        #check gosa-si envelope validity
+        my $answer_hash = &check_outgoing_xml_validity($answer);
+
+        if( $answer_hash ) {
+            # answer is valid            
+
+            # preprocessing
+            if( $answer =~ "<header>registered</header>") {
+                # set registered flag to true to stop sending further registered msgs
+                $REGISTERED = 1;
+            } 
+            else {
+                &send_msg_to_target($answer, $server_address, $server_key);
+            }
+
+            # postprocessing
+            if( $answer =~ "<header>new_key</header>") {
+                # set new key to global variable
+                $answer =~ /<new_key>(\S*?)<\/new_key>/;
+                my $new_key = $1;
+                $server_key = $new_key;
+            }
         }
+
     }
 
     return;
@@ -1138,7 +1270,7 @@ if( 0 != $pid ) {
 }
 
 daemon_log(" ", 1);
-daemon_log("$0 started!", 1);
+daemon_log("$prg started!", 1);
 
 # delete old DBsqlite lock files
 system('rm -f /tmp/gosa_si_lock*gosa-si-client*');
@@ -1197,6 +1329,8 @@ else {
 }
 
 
+# open fifo for non-gosa-si-client-msgs to gosa-si-server
+POSIX::mkfifo("$gosa_si_client_fifo", "0600");
 
 
 POE::Session->create(
@@ -1204,6 +1338,13 @@ POE::Session->create(
                _start => \&_start, 
         register_at_gosa_si_server => \&register_at_gosa_si_server,
         trigger_new_key => \&trigger_new_key,
+        
+        # handle records from each defined file differently
+        fifo_record => \&fifo_got_record,
+
+        # handle file resets and errors the same way for each file
+        file_reset => \&generic_file_reset,
+        file_error => \&generic_file_error,
        }
 );