X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=trunk%2Fgosa-si%2Fgosa-si-server;h=b3c88c1d8f32cf13cfe9164aab04b9a9d12fe0f0;hb=c796562e33cfd80c94524abe95d3a87dd4842c3d;hp=514e8b1bde1f54442d4e053c6c7d3d9025959613;hpb=6b66bae334926c1329955b9abc458f4d4d45d285;p=gosa.git diff --git a/trunk/gosa-si/gosa-si-server b/trunk/gosa-si/gosa-si-server index 514e8b1bd..b3c88c1d8 100755 --- a/trunk/gosa-si/gosa-si-server +++ b/trunk/gosa-si/gosa-si-server @@ -28,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; @@ -79,11 +79,10 @@ my ($xml); my $sources_list; my $max_clients; my %repo_files=(); -my $repo_path; my %repo_dirs=(); # Variables declared in config file are always set to 'our' -our (%cfg_defaults, $log_file, $pid_file, +our (%cfg_defaults, $log_file, $pid_file, $repo_basepath, $server_ip, $server_port, $ClientPackages_key, $dns_lookup, $arp_activ, $gosa_unit_tag, $GosaPackages_key, $gosa_timeout, @@ -127,7 +126,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'", @@ -140,7 +139,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", @@ -212,6 +211,8 @@ our $client_fai_log_dir = "/var/log/fai"; my @msgs_to_decrypt = qw(); my $max_children = 2; +# Allow 50 POE Childs +sub MAX_CONCURRENT_TASKS () { 50 } # loop delay for job queue to look for opsi jobs my $job_queue_opsi_delay = 10; @@ -226,8 +227,9 @@ our $logged_in_user_date_of_expiry = 600; %cfg_defaults = ( "general" => { - "log-file" => [\$log_file, "/var/run/".$prg.".log"], - "pid-file" => [\$pid_file, "/var/run/".$prg.".pid"], + "log-file" => [\$log_file, "/var/run/".$prg.".log"], + "pid-file" => [\$pid_file, "/var/run/".$prg.".pid"], + "repo-basepath" => [\$repo_basepath, "/srv/www"], }, "server" => { "ip" => [\$server_ip, "0.0.0.0"], @@ -242,7 +244,6 @@ our $logged_in_user_date_of_expiry = 600; "messaging" => [\$messaging_file_name, '/var/lib/gosa-si/messaging.db'], "foreign-clients" => [\$foreign_clients_file_name, '/var/lib/gosa-si/foreign_clients.db'], "source-list" => [\$sources_list, '/etc/apt/sources.list'], - "repo-path" => [\$repo_path, '/srv/www/repository'], "ldap-uri" => [\$ldap_uri, ""], "ldap-base" => [\$ldap_base, ""], "ldap-admin-dn" => [\$ldap_admin_dn, ""], @@ -324,11 +325,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){ @@ -344,7 +351,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; } @@ -499,27 +509,33 @@ sub password_check { } +sub clean_shutdown +{ + unlink($pid_file) if (-w $pid_file); + unlink($packages_list_under_construction) if (-w $packages_list_under_construction); +} -#=== FUNCTION ================================================================ -# NAME: sig_int_handler -# PARAMETERS: signal - string - signal arose from system -# RETURNS: nothing -# DESCRIPTION: handels tasks to be done befor signal becomes active -#=============================================================================== -sub sig_int_handler { +sub sig_int_or_term_handler +{ my ($signal) = @_; + daemon_log("Got SIG${signal} - shutting down gosa-si-server", 1); + clean_shutdown(); + POE::Kernel->signal('gosa-si_server_session', 'KILL'); + POE::Kernel->signal('TCP_SERVER', 'KILL'); + return 1; +} -# if (defined($ldap_handle)) { -# $ldap_handle->disconnect; -# } - # TODO alle verbliebenden ldap verbindungen aus allen heaps beenden - - - daemon_log("shutting down gosa-si-server", 1); - system("kill `ps -C gosa-si-server -o pid=`"); +sub sig_warn_handler +{ + my @loc = caller(0); + daemon_log( "SIGWARN line " . $loc[2] . ": " . $_[0], 1 ); + 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{'USR1'} = 'IGNORE'; sub check_key_and_xml_validity { my ($crypted_msg, $module_key, $session_id) = @_; @@ -599,7 +615,7 @@ sub check_outgoing_xml_validity { } # Check if source contains hostname instead of ip address - if(not $source =~ /^[a-z0-9\.]+:\d+$/i) { + if($source =~ /^[a-z][a-z0-9\.]+:\d+$/i) { my ($hostname,$port) = split(/:/, $source); my $ip_address = inet_ntoa(scalar gethostbyname($hostname)); if(defined($ip_address) && $ip_address =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ && $port =~ /^\d+$/) { @@ -942,6 +958,10 @@ sub send_msg_to_target { $sql_statement = "DELETE FROM known_server WHERE hostname='$address'"; $res = $known_server_db->del_dbentry($sql_statement); daemon_log("$session_id WARNING: failed 2x to send a message to host '$address', delete host from known_server", 3); + + # Remove the registered clients of the server as well + $sql_statement = "DELETE FROM foreign_clients WHERE regserver='$address'"; + $res = $foreign_clients_db->del_dbentry($sql_statement); } else { $sql_statement = "UPDATE known_server SET status='$new_status', timestamp='$timestamp' WHERE hostname='$address'"; @@ -1041,14 +1061,6 @@ sub reactivate_job_with_delay { } -sub sig_handler { - my ($kernel, $signal) = @_[KERNEL, ARG0] ; - daemon_log("0 INFO got signal '$signal'", 1); - $kernel->sig_handled(); - return; -} - - sub msg_to_decrypt { my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP]; my $session_id = $session->ID; @@ -1376,8 +1388,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); ###################### @@ -1549,12 +1561,12 @@ sub process_task { sub session_start { my ($kernel) = $_[KERNEL]; + $kernel->alias_set('gosa-si_server_session'); $global_kernel = $kernel; $kernel->yield('register_at_foreign_servers'); $kernel->yield('create_fai_server_db', $fai_server_tn ); $kernel->yield('create_fai_release_db', $fai_release_tn ); $kernel->yield('watch_for_next_tasks'); - $kernel->sig(USR1 => "sig_handler"); $kernel->sig(USR2 => "recreate_packages_db"); $kernel->delay_set('watch_for_new_jobs', $job_queue_loop_delay); $kernel->delay_set('watch_for_done_jobs', $job_queue_loop_delay); @@ -1568,9 +1580,14 @@ sub session_start { if ($opsi_enabled eq "true") { $kernel->delay_set('watch_for_opsi_jobs', $job_queue_opsi_delay); } - } +sub session_stop { + my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP]; + $kernel->alias_remove($heap->{alias}); + $kernel->alarm_remove_all(); + $kernel->post($heap->{child_session}, '_stop'); +} sub watch_for_done_jobs { #CHECK: $heap for what? @@ -1780,8 +1797,7 @@ sub watch_for_new_jobs { my $res_2 = $job_db->exec_statement( $sql_statement_2 ); 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='".&calc_timestamp(&get_time(), 'plus', 30)."' WHERE macaddress LIKE '$macaddress' AND headertag = 'trigger_action_reinstall'"); + $job_db->exec_statement("UPDATE $job_queue_tn SET status='waiting', timestamp='".&calc_timestamp(&get_time(), 'plus', 30)."' WHERE macaddress LIKE '$macaddress' AND headertag = 'trigger_action_reinstall'"); } } next; @@ -1928,7 +1944,8 @@ sub watch_for_delivery_messages { my ($kernel, $heap) = @_[KERNEL, HEAP]; # select outgoing messages - my $sql_statement = "SELECT * FROM $messaging_tn WHERE ( flag='p' AND direction='out' )"; + my $timestamp= &get_time(); + my $sql_statement = "SELECT * FROM $messaging_tn WHERE ( flag='p' AND direction='out' AND delivery_time<$timestamp)"; #&daemon_log("0 DEBUG: $sql", 7); my $res = $messaging_db->exec_statement( $sql_statement ); @@ -2061,7 +2078,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'}); @@ -2076,7 +2093,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); @@ -2759,7 +2776,10 @@ sub run_create_packages_list_db { sub create_packages_list_db { my ($ldap_handle, $sources_file, $session_id) = @_; - + + # Cleanup repo basepath + $repo_basepath = File::Spec->canonpath($repo_basepath); + # 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 # which is tested befor recreation can be started @@ -2979,7 +2999,10 @@ sub parse_package_info { my ($baseurl, $dist, $section, $session_id)= @_; my ($package); if (not defined $session_id) { $session_id = 0; } - my ($path) = ($baseurl =~ m%://[^/]*(.*)$%); + my ($path) = ($baseurl =~ m%://[^/]*/(.*)$%); + + my $repo_path = File::Spec->join($repo_basepath, $path); + $repo_dirs{ "${repo_path}/pool" } = 1; foreach $package ("Packages.gz"){ @@ -3073,6 +3096,8 @@ sub parse_package { # Trigger for filename if ($line =~ /^Filename:\s/){ my ($filename) = ($line =~ /^Filename: (.*)$/); + # Construct real path + my $repo_path = File::Spec->join($repo_basepath, $srv_path); store_fileinfo( $package, $filename, $dist, $srv_path, $version, $repo_path ); next; } @@ -3193,6 +3218,10 @@ GetOptions("h|help" => \&usage, "no-arp+" => \$no_arp, ); +# Prepare UID / GID as daemon_log may need it quite early +$root_uid = getpwnam('root'); +$adm_gid = getgrnam('adm'); + # read and set config parameters &check_cmdline_param ; &read_configfile($cfg_file, %cfg_defaults); @@ -3200,33 +3229,40 @@ GetOptions("h|help" => \&usage, $SIG{CHLD} = 'IGNORE'; -# 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 /: $!"; + if (! chdir('/')) { + daemon_log("Can't chdir to /: $!", 1); + exit( 1 ); + } + umask( 0 ); $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 ) { + # Parent: put PID into the $pid_file open( LOCK_FILE, ">$pid_file" ); print LOCK_FILE "$pid\n"; close( LOCK_FILE ); if( !$foreground ) { - exit( 0 ) - }; + exit( 0 ); +} +} +else { + # Child + open( STDIN, '+>/dev/null' ); + open( STDOUT, '+>&STDIN' ); + open( STDERR, '+>&STDIN' ); + if (! POSIX::setsid()) { + daemon_log("Can't start a new session: $!"); + exit( 1 ); + } + $poe_kernel->has_forked() if ($poe_kernel->can('has_forked')); } + # parse head url and revision from svn my $server_status_hash = { 'developmental'=>'revision', 'stable'=>'release'}; $server_version =~ /^\$HeadURL: (\S+) \$:\$Rev: (\d+) \$$/; @@ -3239,10 +3275,10 @@ if ($server_headURL =~ /\/tag\// || $server_status = "developmental" ; } -# Prepare log file -$root_uid = getpwnam('root'); -$adm_gid = getgrnam('adm'); -chmod(0640, $log_file); +# Prepare log file and set permissons +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"); @@ -3293,60 +3329,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); @@ -3359,7 +3396,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(); @@ -3418,7 +3454,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 @@ -3429,10 +3465,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, } ); } @@ -3479,8 +3515,8 @@ daemon_log("0 INFO: start socket for incoming xml messages at port '$server_port POE::Session->create( inline_states => { _start => \&session_start, + _stop => \&session_stop, register_at_foreign_servers => \®ister_at_foreign_servers, - sig_handler => \&sig_handler, next_task => \&next_task, task_result => \&handle_task_result, task_done => \&handle_task_done,