X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=trunk%2Fgosa-si%2Fgosa-si-client;h=5ce0d368fc429a0d9661857f1952bbafb510f8e3;hb=9ee3014961c5f44c31802e4e6d1883023954b807;hp=8142b35a0b753691e907d54913c9e1807f16d8ca;hpb=79f6721d8cea6f0d447f0833041348ca76dddf16;p=gosa.git diff --git a/trunk/gosa-si/gosa-si-client b/trunk/gosa-si/gosa-si-client index 8142b35a0..5ce0d368f 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,15 @@ our $client_mac_address; our $client_dnsname; our $client_force_hostname; our $server_key; +our $opts_dnslookup; + +our $FIFO_FD = undef; # 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 +93,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 +125,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 +175,6 @@ sub check_cmdline_param () { } } - #=== FUNCTION ================================================================ # NAME: check_pid # PARAMETERS: @@ -212,15 +223,43 @@ 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("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; +} + +sub sig_warn_handler +{ + my @loc = caller(0); + daemon_log( "SIGWARN line " . $loc[2] . ": " . $_[0], 1 ); + return 1; +} - daemon_log("shutting down gosa-si-client", 1); - system("kill `ps -C gosa-si-client -o pid=`"); +sub sig_die_handler +{ + my @loc = caller(0); + daemon_log( "SIGDIE line " . $loc[2] . ": " . $_[0], 1 ); + clean_shutdown(); + return 1; } -$SIG{INT} = \&sig_int_handler; +$SIG{'INT'} = \&sig_int_or_term_handler; +$SIG{'TERM'} = \&sig_int_or_term_handler; +$SIG{'__WARN__'} = \&sig_warn_handler; +$SIG{'__DIE__'} = \&sig_die_handler; +$SIG{'USR1'} = 'IGNORE'; +$SIG{'USR2'} = 'IGNORE'; #=== FUNCTION ================================================================ # NAME: logging @@ -317,7 +356,6 @@ sub get_mac { } - #=== FUNCTION ================================================================ # NAME: get_local_mac_for_remote_ip # PARAMETERS: none (takes server_ip from global variable) @@ -329,6 +367,14 @@ sub get_local_mac_for_remote_ip { my $server_ip= shift; my $result= "00:00:00:00:00:00"; + 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}/) { + # Write ip address to $server_ip variable + $server_ip = $ip_address; + } + } + if($server_ip =~ /^(\d\d?\d?\.){3}\d\d?\d?$/) { my $PROC_NET_ROUTE= ('/proc/net/route'); @@ -452,7 +498,7 @@ 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'); + $global_kernel->post('client_session', 'register_at_gosa_si_server'); } $error++; @@ -528,14 +574,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'); @@ -544,21 +591,20 @@ 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 ); + 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); } @@ -602,9 +648,9 @@ 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") { + if(defined($res) and $res eq "0") { # reset try_to_register - $try_to_register = 0; + $REGISTRATION_TRIES = 0; # Set fixed client address and mac address $client_ip= &get_local_ip_for_remote_ip(sprintf("%s", $server =~ /^([0-9\.]*?):.*$/)); @@ -614,15 +660,13 @@ 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)) ) { &write_to_file("gosa-si-no-server-available", $fai_logpath); $kernel->delay_set('register_at_gosa_si_server', $delay_set_time); @@ -780,8 +824,16 @@ 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"); + $FIFO_FD = undef + if (! defined $FIFO_FD && ! defined open($FIFO_FD, '>', $gosa_si_client_fifo)); + if (! defined $FIFO_FD) { + daemon_log("ERROR: unable to open fifo for writing: $!", 1); + $kernel->delay_set('trigger_logged_in_users_report', 30); + } + else { + print($FIFO_FD 'CURRENTLY_LOGGED_IN ' . join(" ", @logged_in_user_list)); $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); @@ -795,7 +847,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 @@ -839,9 +891,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); } } @@ -890,7 +941,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); } @@ -901,6 +952,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"); @@ -912,6 +964,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"); @@ -941,27 +998,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'); @@ -985,6 +1033,17 @@ 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'); + close( $FIFO_FD ) if( defined $FIFO_FD ); +} + + sub _default { daemon_log("ERROR: can not handle incoming msg with header '$_[ARG0]'", 1); return; @@ -1011,9 +1070,17 @@ 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; $kernel->post('client_session', 'register_at_gosa_si_server'); } @@ -1025,6 +1092,9 @@ sub server_input { ###################### # 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]; @@ -1054,6 +1124,7 @@ sub server_input { if( $answer =~ "
registered
") { # set registered flag to true to stop sending further registered msgs $REGISTERED = 1; + $REGISTRATION_IN_PROGRESS = 0; } else { $answer =~ /
(\S+)<\/header>/; @@ -1074,6 +1145,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 @@ -1089,34 +1245,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+) \$$/; @@ -1145,6 +1273,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); @@ -1183,74 +1357,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