X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=trunk%2Fgosa-si%2Fgosa-si-client;h=9ee49e936f764ea16fdd3dd501b6299d00869b87;hb=807dd230de1f74c3d1daa3bb6715333b110d9e39;hp=4d109684f37373877307f7613457f0acda37d2ac;hpb=1ca5cc895c1a78173839776ce575beb3c38ad829;p=gosa.git diff --git a/trunk/gosa-si/gosa-si-client b/trunk/gosa-si/gosa-si-client index 4d109684f..9ee49e936 100755 --- a/trunk/gosa-si/gosa-si-client +++ b/trunk/gosa-si/gosa-si-client @@ -60,6 +60,7 @@ my @servers; my $gotoHardwareChecksum; my $gosa_si_client_fifo; my %files_to_watch; +my $servers_string; $verbose= 1; # globalise variables which are used in imported events @@ -73,9 +74,13 @@ our $client_mac_address; our $client_dnsname; our $client_force_hostname; our $server_key; +our $opts_dnslookup; # default variables our $REGISTERED = 0; +our $REGISTRATION_IN_PROGRESS = 0; +our $REGISTRATION_TRIES = 0; +our $FAILED_CRYPTO = 0; # path to fifo for non-gosa-si-client messages to gosa-si-server $gosa_si_client_fifo = "/var/run/gosa-si-client.socket"; @@ -86,6 +91,10 @@ $gosa_si_client_fifo = "/var/run/gosa-si-client.socket"; my $delay_set_time = 10; our $prg= basename($0); +# Threshold for the max number of wrong crypted packages, when triggered +# a new server is choosen +my $max_failed_crypto_messages = 5; + # all n seconds the client reports logged_in users to gosa-si-server my $trigger_logged_in_users_report_delay = 600; @@ -114,11 +123,12 @@ my $fai_log_dir = "/var/log/fai"; "force-hostname" => [\$client_force_hostname, "false"], }, "server" => { - "ip" => [\$server_ip, "127.0.0.1"], + "ip" => [\$servers_string, "127.0.0.1"], "port" => [\$server_port, "20081"], "key" => [\$server_key, ""], "timeout" => [\$server_timeout, 10], "key-lifetime" => [\$server_key_lifetime, 600], + "dns-lookup" => [\$opts_dnslookup, "true"], }, ); @@ -163,7 +173,6 @@ sub check_cmdline_param () { } } - #=== FUNCTION ================================================================ # NAME: check_pid # PARAMETERS: @@ -212,15 +221,34 @@ sub check_pid { } } +sub clean_shutdown +{ + unlink($pid_file) if (-w $pid_file); + unlink($gosa_si_client_fifo) if (-S $gosa_si_client_fifo); +} -sub sig_int_handler { +sub sig_int_or_term_handler +{ my ($signal) = @_; - - daemon_log("shutting down gosa-si-client", 1); - system("kill `ps -C gosa-si-client -o pid=`"); + daemon_log("Got SIG${signal} - shutting down gosa-si-client", 1); + clean_shutdown(); + POE::Kernel->signal('client_session', 'KILL'); + POE::Kernel->signal('gosa-si-client', 'KILL'); + return 1; } -$SIG{INT} = \&sig_int_handler; +sub sig_warn_handler +{ + my @loc = caller(0); + daemon_log( "SIGWARN line " . $loc[2] . ": " . $_[0], 1 ); + return 1; +} + +$SIG{'INT'} = \&sig_int_or_term_handler; +$SIG{'TERM'} = \&sig_int_or_term_handler; +$SIG{'__WARN__'} = \&sig_warn_handler; +$SIG{'USR1'} = 'IGNORE'; +$SIG{'USR2'} = 'IGNORE'; #=== FUNCTION ================================================================ # NAME: logging @@ -317,7 +345,6 @@ sub get_mac { } - #=== FUNCTION ================================================================ # NAME: get_local_mac_for_remote_ip # PARAMETERS: none (takes server_ip from global variable) @@ -331,7 +358,7 @@ sub get_local_mac_for_remote_ip { if($server_ip =~ /^[a-z][a-z0-9\.]$/i) { my $ip_address = inet_ntoa(scalar gethostbyname($server_ip)); - if(defined($ip_address) && $ip_address =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ && $port =~ /^\d+$/) { + if(defined($ip_address) && $ip_address =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) { # Write ip address to $server_ip variable $server_ip = $ip_address; } @@ -460,7 +487,8 @@ sub send_msg_to_target { if ($REGISTERED == 1) { $REGISTERED = 0; # if server is not available, cause reregistering daemon_log("INFO: cause reregistering at gosa-si-server", 5); - $global_kernel->yield('register_at_gosa_si_server'); + sleep(2); + $global_kernel->post('client_session', 'register_at_gosa_si_server'); } $error++; @@ -536,14 +564,15 @@ sub open_socket { #=============================================================================== sub register_at_gosa_si_server { my ($kernel) = $_[KERNEL]; - my $try_to_register = 0; - + # if client is already registered, stop registration process if ($REGISTERED) { $kernel->delay('register_at_gosa_si_server'); # client is not registered, start registration process } else { + $REGISTRATION_IN_PROGRESS = 1; + # clear all other triggered events and wait till registration was successful $kernel->delay('trigger_new_key'); @@ -552,21 +581,21 @@ sub register_at_gosa_si_server { my $events = join( ",", keys %{$event_hash} ); while(1) { - $try_to_register++; - - # after one complete round through all server, stop trying to register - if( $try_to_register > @servers ) { last; } + $REGISTRATION_TRIES++; # fetch first gosa-si-server from @servers # append shifted gosa-si-server at the end of @servers, so looking for servers never stop if # a registration never occured my $server = shift(@servers); - push( @servers, $server ); + &main::daemon_log("INFO: Trying to register with server $server", 3); + push(@servers, $server); + ($server_ip = $server) =~ s/:.*$//; + $server_address = $server; # Check if our ip is resolvable - if not: don't try to register if(!(defined($server) && $server =~ m/^[0-9\.]*?:.*$/)) { &main::daemon_log("ERROR: Server with address '".defined($server)?$server:""."' is invalid!", 1); - if (length(@servers) == 1) { + if (scalar(@servers) == 1) { &main::daemon_log("ERROR: No valid servers found!", 1); exit(1); } @@ -610,9 +639,7 @@ sub register_at_gosa_si_server { my $res = &send_msg_hash_to_target($register_hash, $server, $default_server_key); # if delivery of registration msg succeed - if($res eq "0") { - # reset try_to_register - $try_to_register = 0; + if(defined($res) and $res eq "0") { # Set fixed client address and mac address $client_ip= &get_local_ip_for_remote_ip(sprintf("%s", $server =~ /^([0-9\.]*?):.*$/)); @@ -622,17 +649,18 @@ sub register_at_gosa_si_server { last; # delivery of registration msg failed - } else { - # wait 1 sec until trying to register again - sleep(1); - next; + } elsif($REGISTRATION_TRIES > scalar(@servers)) { + last; } } # end of while # one circle through all servers finished and no registration succeed - if ( $try_to_register >= @servers ) { + if ( $REGISTRATION_TRIES > (scalar(@servers)) ) { + $REGISTRATION_TRIES = 0; &write_to_file("gosa-si-no-server-available", $fai_logpath); - $kernel->delay_set('register_at_gosa_si_server', $delay_set_time); + daemon_log("WARNING: Could not register with any of the servers, waiting $delay_set_time seconds",3); + sleep($delay_set_time); + $kernel->post('client_session', 'register_at_gosa_si_server'); # delivery of registraion msg succeed, waiting for server response } else { @@ -655,6 +683,9 @@ sub check_key_and_xml_validity { my $msg_hash; eval{ $msg = &decrypt_msg($crypted_msg, $module_key); + if ($msg !~ /^/i ) { + die 'could not decrypt message'; + } &main::daemon_log("decrypted_msg: \n$msg", 9); $msg_hash = $xml->XMLin($msg, ForceArray=>1); @@ -788,8 +819,15 @@ sub trigger_logged_in_users_report { @logged_in_user_list = split(/\s/, $result); } - system("echo 'CURRENTLY_LOGGED_IN ".join(" ", @logged_in_user_list)."' > /var/run/gosa-si-client.socket"); - $kernel->delay_set('trigger_logged_in_users_report', $trigger_logged_in_users_report_delay); + if (!open(FIFO_FD, '>', $gosa_si_client_fifo)) { + daemon_log("ERROR: unable to open fifo for writing: $!", 1); + $kernel->delay_set('trigger_logged_in_users_report', 30); + } + else { + printf(FIFO_FD "CURRENTLY_LOGGED_IN %s\n", join(" ", @logged_in_user_list)); + close(FIFO_FD); + $kernel->delay_set('trigger_logged_in_users_report', $trigger_logged_in_users_report_delay); + } } else { # try it in 10 sec again $kernel->delay_set('trigger_logged_in_users_report', 10); @@ -803,7 +841,7 @@ sub trigger_seen_messages { # Select all files under /tmp with prefix 'goto_notify' my $goto_dir = "/tmp"; opendir(DIR, $goto_dir); - my @goto_files = grep { /^goto_notify_/ && -f "$goto_dir/$_" } readdir(DIR); + my @goto_files = grep { /.goto_notify$/ && -f "$goto_dir/$_" } readdir(DIR); closedir DIR; # Check if file has 'seen' tag @@ -847,9 +885,8 @@ sub trigger_seen_messages { my $send_error = &send_msg_to_target($confirm_msg, $server_address, $server_key); # Delete file - if (not $send_error) { - system("rm $goto_dir/$goto_file"); - } + unlink("$goto_dir/$goto_file") + if (! $send_error); } } @@ -877,7 +914,7 @@ sub fifo_got_record { my $file_record = $_[ARG0]; my $header; my $content = ""; - daemon_log("DEBUG: fifo got record: $file_record", 7); + daemon_log("INFO: fifo got record: $file_record", 3); $file_record =~ /^(\S+)[ ]?([\s\S]+)?$/; if( defined $1 ) { @@ -898,7 +935,7 @@ sub fifo_got_record { &send_msg_to_target($clmsg, $server_address, $server_key, "CLMSG_$header"); # if installation finished, save all log files - if ($file_record eq "TASKBEGIN finish") { + if ($file_record eq "TASKBEGIN savelog") { &save_fai_log($fai_log_dir); } @@ -909,6 +946,7 @@ sub fifo_got_record { sub save_fai_log { my ($fai_log_dir) = @_ ; my $FAI_DIR; + my $fai_action; # Directory for log files after a softupdate my $log_dir = File::Spec->catdir($fai_log_dir, "localhost/last"); @@ -920,6 +958,11 @@ sub save_fai_log { daemon_log("ERROR: cannot open directory $log_dir", 1); return; } + $fai_action = "install"; + } + else { + # If we already have a logdir, we can assume that this is a softupdate + $fai_action = "softupdate"; } opendir($FAI_DIR, "$log_dir"); @@ -949,27 +992,18 @@ sub save_fai_log { my $all_log_string = join("\n", @log_list); my $msg_hash = &create_xml_hash("CLMSG_save_fai_log", $client_address, $server_address, $all_log_string); &add_content2xml_hash($msg_hash, "macaddress", $client_mac_address); + &add_content2xml_hash($msg_hash, "fai_action", $fai_action); my $msg = &create_xml_string($msg_hash); &send_msg_to_target($msg, $server_address, $server_key, "CLMSG_save_fai_log"); } -sub sig_handler { - my ($kernel, $signal) = @_[KERNEL, ARG0] ; - daemon_log("0 INFO got signal '$signal'", 1); - $kernel->sig_handled(); - return; -} - - sub _start { my ($kernel, $heap) = @_[KERNEL, HEAP]; $kernel->alias_set('client_session'); $global_kernel = $kernel; # this is used to throw events at each point of the skript - $kernel->sig(USR1 => "sig_handler"); - # force a registration at a gosa-si-server $kernel->yield('register_at_gosa_si_server'); @@ -993,6 +1027,16 @@ sub _start { } +sub _stop { + my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP]; + delete $heap->{'services'}; + delete $heap->{'watchers'}; + $kernel->alias_remove($heap->{alias}); + $kernel->alarm_remove_all(); + $kernel->post($heap->{child_session}, '_stop'); +} + + sub _default { daemon_log("ERROR: can not handle incoming msg with header '$_[ARG0]'", 1); return; @@ -1004,12 +1048,18 @@ sub server_input { my $remote_ip = $heap->{'remote_ip'}, my $error = 0; my $answer; + my $msg; + my $msg_hash; - daemon_log("INFO: Incoming msg from '$remote_ip'", 5); + daemon_log("INFO: Incoming msg from '$remote_ip', server_ip: $server_ip", 5); daemon_log("DEBUG: Incoming msg:\n$input\n", 9); - my ($msg, $msg_hash) = &check_key_and_xml_validity($input, $server_key); + if (not "$remote_ip" eq "$server_ip" and "$server_ip" ne "127.0.0.1") { + daemon_log("INFO: Incoming msg not from server ($server_ip), ignoring", 5); + $error++; + } else { + ($msg, $msg_hash) = &check_key_and_xml_validity($input, $server_key); if( (!$msg) || (!$msg_hash) ) { daemon_log("WARNING: Deciphering of incoming msg failed", 3); if($server_address =~ /$remote_ip/) { @@ -1019,20 +1069,32 @@ sub server_input { # if client is alread in a registration process, that means not registered, do nothing # if not, cause re-registration - if (not $REGISTERED) { + if ($REGISTRATION_IN_PROGRESS) { &daemon_log("WARNING: gosa-si-client is already in a registration process so ignore this message", 3); } else { + if ($FAILED_CRYPTO > $max_failed_crypto_messages) { + # Force usage of a new server + daemon_log("Failed to decrypt a total of $max_failed_crypto_messages messages from the server. Trying to switch to another one", 3); + $REGISTRATION_TRIES = $max_failed_crypto_messages; + my $server = shift(@servers); + push(@servers, $server); + } + $FAILED_CRYPTO++; $REGISTERED = 0; + sleep(2); $kernel->post('client_session', 'register_at_gosa_si_server'); } } $error++; } - + } ###################### # process incoming msg if( $error == 0 ) { + # Reset failed crypto messages state + $FAILED_CRYPTO = 0; + my $header = @{$msg_hash->{header}}[0]; my $source = @{$msg_hash->{source}}[0]; @@ -1062,6 +1124,11 @@ sub server_input { if( $answer =~ "
registered
") { # set registered flag to true to stop sending further registered msgs $REGISTERED = 1; + $REGISTRATION_IN_PROGRESS = 0; + if( $server_ip eq "127.0.0.1") { + $server_ip = $remote_ip; + daemon_log("INFO: Registered at localhost, setting server_ip to $server_ip",3); + } } else { $answer =~ /
(\S+)<\/header>/; @@ -1082,6 +1149,91 @@ sub server_input { return; } +sub find_servers { + # add gosa-si-server address from config file at first position of server list + my $server_check_cfg = Config::IniFiles->new( -file => $cfg_file ); + + # Parse servers string + my @conf_servers = split(',', $servers_string); + + # Now search for fallback servers in the configuration + foreach my $cur_server (@conf_servers) { + # Remove spaces from the IP + $cur_server =~ s/\s//g; + + my $ip = $cur_server; + if(not $cur_server =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) { + my $ip_address = inet_ntoa(scalar gethostbyname($ip)); + if(defined($ip_address) && $ip_address =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) { + # Write ip address to $server_ip variable + $ip = $ip_address; + } + } + + my $server_addr = sprintf("%s:%s", $ip, $server_port); + if (not grep { $_ eq $server_addr } @servers) { + push(@servers, $server_addr); + } + } + + my $servers_string = join(", ", @servers); + daemon_log("INFO: found servers in configuration file: $servers_string", 1); + + # Last but not least search for fallback servers in the DNS + if (defined($opts_dnslookup) and $opts_dnslookup eq "true") { + my @tmp_servers; + if ( !$server_domain) { + # Try our DNS Searchlist + my @domain_list = &get_dns_domains(); + my $tmp_domains; + my $error_string; + for my $domain (@domain_list) { + chomp($domain); + ($tmp_domains, $error_string) = &get_server_addresses($domain); + if(@$tmp_domains) { + for my $tmp_server(@$tmp_domains) { + push @tmp_servers, $tmp_server; + } + } + } + + if (0 == @tmp_servers) { + daemon_log("INFO: No servers found in DNS.", 1); + } + else { + my $servers_string = join(", ", @tmp_servers); + daemon_log("INFO: found servers in DNS: $servers_string", 1); + } + } else { + @tmp_servers = &get_server_addresses($server_domain); + if( 0 == @tmp_servers ) { + daemon_log("INFO: No servers found in DNS for domain '$server_domain'",1); + } + } + + if ( 0 != @tmp_servers ) { + foreach my $server_addr (@tmp_servers) { + if (not grep { $_ eq $server_addr } @servers) { + push(@servers, $server_addr); + } + } + } + } + + if (0 == scalar(@servers)) { + daemon_log("ERROR: No servers found in the configuration or DNS.", 1); + exit(1); + } + + # Define first server as server_ip + $server_ip = $servers[0]; + + # prepare variables + if( inet_aton($server_ip) ){ $server_ip = inet_ntoa(inet_aton($server_ip)); } + if (defined $server_ip && defined $server_port) { + $server_address = $server_ip.":".$server_port; + } +} #==== MAIN = main ============================================================== # parse commandline options @@ -1097,34 +1249,6 @@ GetOptions("h|help" => \&usage, &read_configfile($cfg_file, %cfg_defaults); &check_pid; - -# forward error messages to logfile -if ( ! $foreground ) { - open( STDIN, '+>/dev/null' ); - open( STDOUT, '+>&STDIN' ); - open( STDERR, '+>&STDIN' ); -} - -# Just fork, if we are not in foreground mode -if( ! $foreground ) { - chdir '/' or die "Can't chdir to /: $!"; - $pid = fork; - setsid or die "Can't start a new session: $!"; - umask 0; -} else { - $pid = $$; -} - -# Do something useful - put our PID into the pid_file -if( 0 != $pid ) { - open( LOCK_FILE, ">$pid_file" ); - print LOCK_FILE "$pid\n"; - close( LOCK_FILE ); - if( !$foreground ) { - exit( 0 ) - }; -} - # parse head url and revision from svn my $client_status_hash = { 'developmental'=>'revision', 'stable'=>'release'}; $client_version =~ /^\$HeadURL: (\S+) \$:\$Rev: (\d+) \$$/; @@ -1153,6 +1277,52 @@ daemon_log("INFO: ".$client_status_hash->{$client_status}.": $client_revision", # delete old DBsqlite lock files system('rm -f /tmp/gosa_si_lock*gosa-si-client*'); +# (re-)create FIFO +if (-e $gosa_si_client_fifo) { + daemon_log("INFO: $gosa_si_client_fifo exists - deleting", 5); + if (1 != unlink($gosa_si_client_fifo)) { + daemon_log("ERROR: unable to delete '$gosa_si_client_fifo': $!", 1); + exit( 1 ); + } +} +if (! defined POSIX::mkfifo($gosa_si_client_fifo, "0600")) { + daemon_log("ERROR: failed creating fifo: $!", 1); + exit( 1 ); +} + +# Just fork, if we are not in foreground mode +if( ! $foreground ) { + if (! chdir('/')) { + daemon_log("ERROR: Can't chdir to /: $!"); + exit( 1 ); + } + umask( 0 ); + $pid = fork; +} else { + $pid = $$; +} + +if( 0 != $pid ) { + # Parent: put our PID into the $pid_file + open( LOCK_FILE, ">$pid_file" ); + print LOCK_FILE "$pid\n"; + close( LOCK_FILE ); + if( !$foreground ) { + exit( 0 ); + } +} +else { + # Child + open( STDIN, '+>/dev/null' ); + open( STDOUT, '+>&STDIN' ); + open( STDERR, '+>&STDIN' ); + if (! POSIX::setsid()) { + deamon_log("ERROR: Can't start a new session: $!", 1); + exit( 1 ); + } + $poe_kernel->has_forked() if ($poe_kernel->can('has_forked')); +} + # detect ip and mac address and complete host address $client_address = $client_ip.":".$client_port; my $network_interface= &get_interface_for_ip($client_ip); @@ -1191,74 +1361,17 @@ POE::Component::Server::TCP->new( ); daemon_log("INFO: start socket for incoming xml messages at port '$client_port' ", 1); - -# prepare variables -if( inet_aton($server_ip) ){ $server_ip = inet_ntoa(inet_aton($server_ip)); } -if (defined $server_ip && defined $server_port) { - $server_address = $server_ip.":".$server_port; -} $xml = new XML::Simple(); $default_server_key = $server_key; - -# add gosa-si-server address from config file at first position of server list -my $server_check_cfg = Config::IniFiles->new( -file => $cfg_file ); -my $server_check = (defined($server_check_cfg))?$server_check_cfg->val( "server", "ip"):undef; -if( defined $server_check ) { - unshift(@servers, $server_address); - my $servers_string = join(", ", @servers); - daemon_log("INFO: found servers in configuration file: $servers_string", 1); -} else { - my @tmp_servers; - if ( !$server_domain) { - # Try our DNS Searchlist - my @domain_list = &get_dns_domains(); - my $tmp_domains; - my $error_string; - for my $domain (@domain_list) { - chomp($domain); - ($tmp_domains, $error_string) = &get_server_addresses($domain); - if(@$tmp_domains) { - for my $tmp_server(@$tmp_domains) { - push @tmp_servers, $tmp_server; - } - } - } - if (0 == @tmp_servers) { - my $log_string = "no gosa-si-server found!"; - $log_string .= "\n\tdetermined domains out of /etc/resolv.conf: ".join(", ", @domain_list) if (@domain_list); - $log_string .= "\n\tdetermined server addresses in domains: ".join(", ",@$tmp_domains) if (defined($tmp_domains)); - daemon_log("ERROR: $log_string", 1) if (defined($log_string)); - daemon_log("ERROR: $error_string", 1) if (defined($error_string)); - daemon_log("ERROR: please specify a gosa-si-server address or a domain in config file", 1); - kill 2, $$; - } - } else { - @tmp_servers = &get_server_addresses($server_domain); - if( 0 == @tmp_servers ) { - daemon_log("ERROR: no gosa-si-server found in DNS for domain '$server_domain'",1); - daemon_log("ERROR: please specify a gosa-si-server address or a domain in config file", 1); - kill 2, $$; - } - } - - foreach my $server (@tmp_servers) { - unshift(@servers, $server); - } - my $servers_string = join(", ", @servers); - daemon_log("INFO: found servers in DNS: $servers_string", 1); -} - - -# open fifo for non-gosa-si-client-msgs to gosa-si-server -POSIX::mkfifo("$gosa_si_client_fifo", "0600"); - +# Find servers from config and DNS +&find_servers; POE::Session->create( inline_states => { _start => \&_start, + _stop => \&_stop, _default => \&_default, - sig_handler => \&sig_handler, register_at_gosa_si_server => \®ister_at_gosa_si_server, # trigger periodical tasks