index 0b00e52bcbfedbf579ae4dbdc19c6da77edc9ed1..ae3a97e0d9dce646df43c933f3f114e7270f6db1 100755 (executable)
use Config::IniFiles;
use POSIX;
-use Fcntl;
+use Fcntl qw/:flock/;
use IO::Socket::INET;
use IO::Handle;
use IO::Select;
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,
$wake_on_lan_passwd, $job_synchronization, $modified_jobs_loop_delay,
$arp_enabled, $arp_interface,
$opsi_enabled, $opsi_server, $opsi_admin, $opsi_password,
- $new_systems_ou,
+ $new_systems_ou, $logged_in_users_delay,
);
# additional variable which should be globaly accessable
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;
%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"],
"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, ""],
"key-lifetime" => [\$foreign_servers_register_delay, 120],
"job-synchronization-enabled" => [\$job_synchronization, "true"],
"synchronization-loop" => [\$modified_jobs_loop_delay, 5],
+ "report-logged-in-users" => [\$logged_in_users_delay, 600],
},
"ArpHandler" => {
"enabled" => [\$arp_enabled, "true"],
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){
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;
}
}
+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) = @_;
}
# 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+$/) {
$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'";
}
-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;
# 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);
######################
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);
$kernel->delay_set('watch_for_delivery_messages', $messaging_db_loop_delay);
$kernel->delay_set('watch_for_done_messages', $messaging_db_loop_delay);
$kernel->delay_set('watch_for_old_known_clients', $job_queue_loop_delay);
+ $kernel->delay_set('watch_for_logged_in_users', $logged_in_users_delay);
# Start opsi check
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?
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;
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 );
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'});
$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);
$kernel->delay_set('watch_for_next_tasks', 1);
}
+sub watch_for_logged_in_users {
+ my ($kernel,$heap) = @_[KERNEL, HEAP];
+
+ # Get list of currently logged in users
+ my $sql = "SELECT * FROM $login_users_tn WHERE regserver='localhost'";
+ my $res = $main::login_users_db->select_dbentry($sql);
+ my $msg_hash = &create_xml_hash("information_sharing", $server_address, "KNOWN_SERVER");
+ while (my ($hit_id, $hit) = each(%$res)) {
+ &add_content2xml_hash($msg_hash, 'user_db', $hit->{'client'}.";".$hit->{'user'});
+ }
+ my $msg = &create_xml_string($msg_hash);
+
+ # Inform all other server which users are logged in at clients registered at local server
+ my $sql_statement= "SELECT * FROM $known_server_tn";
+ my $query_res = $known_server_db->select_dbentry( $sql_statement );
+ while( my ($hit_num, $hit) = each %{ $query_res } ) {
+ my $host_name = $hit->{hostname};
+ my $host_key = $hit->{hostkey};
+ $msg =~ s/<target>\S+<\/target>/<target>$host_name<\/target>/g;
+ # TODO: get session_id
+ my $error = &send_msg_to_target($msg, $host_name, $host_key, "information_sharing", 0);
+ }
+
+ $kernel->delay_set('watch_for_logged_in_users', $logged_in_users_delay);
+}
sub get_ldap_handle {
my ($session_id) = @_;
$session_id = 0 if not defined $session_id;
# Set FAI state to localboot
my %mapActions= (
- reboot => '',
+ reboot => 'localboot',
update => 'softupdate',
localboot => 'localboot',
reinstall => 'install',
- rescan => '',
- wake => '',
+ rescan => 'localboot',
+ wake => 'localboot',
memcheck => 'memcheck',
sysinfo => 'sysinfo',
install => 'install',
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
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"){
# 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;
}
"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);
$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+) \$$/;
$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");
# 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 +3423,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();
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
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 +3542,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,
watch_for_done_jobs => \&watch_for_done_jobs,
watch_for_opsi_jobs => \&watch_for_opsi_jobs,
watch_for_old_known_clients => \&watch_for_old_known_clients,
+ watch_for_logged_in_users => \&watch_for_logged_in_users,
create_packages_list_db => \&run_create_packages_list_db,
create_fai_server_db => \&run_create_fai_server_db,
create_fai_release_db => \&run_create_fai_release_db,