X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=gosa-si%2Fgosa-si-bus;h=37d54002cfa8899372b8036ca35b34742401e97e;hb=2e1a7f272ac8f39bc8ebe2e6c33fe7bdd63ab03d;hp=a56a38e1a2f9a46763ab00bc46aa29040cb0fffd;hpb=e38d4123a43ac0f63d6b101f8f8e71b083110491;p=gosa.git diff --git a/gosa-si/gosa-si-bus b/gosa-si/gosa-si-bus index a56a38e1a..37d54002c 100755 --- a/gosa-si/gosa-si-bus +++ b/gosa-si/gosa-si-bus @@ -1,9 +1,9 @@ #!/usr/bin/perl #=============================================================================== # -# FILE: gosa-server +# FILE: gosa-si-bus # -# USAGE: ./gosa-server +# USAGE: ./gosa-si-bus # # DESCRIPTION: # @@ -25,46 +25,72 @@ use Config::IniFiles; use POSIX; use Time::HiRes qw( gettimeofday ); -use IO::Socket::INET; +use POE qw(Component::Server::TCP); +use Data::Dumper; use Crypt::Rijndael; +use IO::Socket::INET; +use NetAddr::IP; +use XML::Simple; use MIME::Base64; +use File::Basename; use Digest::MD5 qw(md5 md5_hex md5_base64); -use XML::Simple; -use Data::Dumper; -use Sys::Syslog qw( :DEFAULT setlogsock); -use Cwd; -use File::Spec; -use IPC::Shareable qw( :lock); -IPC::Shareable->clean_up_all; - -my ($cfg_file, $default_cfg_file, %cfg_defaults, $foreground, $verbose); -my ($bus_activ, $bus_passwd, $bus_ip, $bus_port, $bus_address, $bus, $bus_mac_address); -my ($pid_file, $procid, $pid, $log_file, $my_own_address); -my (%free_child, %busy_child, $child_max, $child_min, %child_alive_time, $child_timeout); -my ($xml, $bus_cipher, $known_daemons, $shmkh); -$foreground = 0 ; -$known_daemons = {}; -$shmkh = tie($known_daemons, 'IPC::Shareable', undef, {create => 1, - exclusive => 1, - mode => 0666, - destroy => 1, - }); -%cfg_defaults = -("general" => - {"log_file" => [\$log_file, "/var/run/".$0.".log"], - "pid_file" => [\$pid_file, "/var/run/".$0.".pid"], - "child_max" => [\$child_max, 10], - "child_min" => [\$child_min, 3], - "child_timeout" => [\$child_timeout, 180], +use GOSA::GosaSupportDaemon; +use GOSA::DBsqlite; + +my ($cfg_file, $default_cfg_file, %cfg_defaults, $foreground, $verbose, $pid_file, $procid, $pid, $log_file,); +my ($bus_address, $bus_key, $bus_ip, $bus_port, $bus_mac_address); +my ($bus_known_server_db, $bus_known_server_file_name, $bus_known_clients_db, $bus_known_clients_file_name); +my $xml; +our $prg= basename($0); +$foreground = 0 ; +%cfg_defaults = ( +"general" => { + "log_file" => [\$log_file, "/var/run/".$prg.".log"], + "pid_file" => [\$pid_file, "/var/run/".$prg.".pid"], }, -"bus" => - {"bus_activ" => [\$bus_activ, "on"], - "bus_passwd" => [\$bus_passwd, ""], - "bus_port" => [\$bus_port, "20080"], +"bus" => { + "key" => [\$bus_key, "secret-bus-password"], + "ip" => [\$bus_ip, "0.0.0.0"], + "port" => [\$bus_port, "20080"], + "known-servers" => [\$bus_known_server_file_name, "/var/lib/gosa-si/bus-servers.db"], + "known-clients" => [\$bus_known_clients_file_name, "/var/lib/gosa-si/bus-clients.db"], + }, +); + +#=== FUNCTIONS = functions ===================================================== + +#=== FUNCTION ================================================================ +# NAME: check_cmdline_param +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub check_cmdline_param () { + my @error_l; + my $error = 0; + + if( !$cfg_file ) { + $cfg_file = "/etc/gosa-si/bus.conf"; + } + if( not -f $cfg_file ) { + push(@error_l, "can not find file '$cfg_file'"); + $error++; + } + if( not -r $cfg_file) { + push(@error_l, "can not read file '$cfg_file'"); + $error++; } - ); + + if( $error > 0 ) { + &usage( "", 1 ); + print STDERR join("\n", @error_l); + print STDERR "\n"; + exit( -1 ); + } +} + #=== FUNCTION ================================================================ # NAME: read_configfile @@ -91,62 +117,6 @@ sub read_configfile { } } -#=== FUNCTION ================================================================ -# NAME: logging -# PARAMETERS: level - string - default 'info' -# msg - string - -# facility - string - default 'LOG_DAEMON' -# RETURNS: nothing -# DESCRIPTION: function for logging -#=============================================================================== -sub daemon_log { - my( $msg, $level ) = @_; - 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" )) { - print STDERR "cannot open $log_file: $!"; - return } - chomp($msg); - if($level <= $verbose){ - print LOG_HANDLE $msg."\n"; - if(defined $foreground) { print $msg."\n" } - } - } - close( LOG_HANDLE ); -# my ($msg, $level, $facility) = @_; -# if(not defined $msg) {return} -# if(not defined $level) {$level = "info"} -# if(not defined $facility) {$facility = "LOG_DAEMON"} -# openlog($0, "pid,cons,", $facility); -# syslog($level, $msg); -# closelog; -# return; -} - -#=== FUNCTION ================================================================ -# NAME: check_cmdline_param -# PARAMETERS: nothing -# RETURNS: nothing -# DESCRIPTION: validates commandline parameter -#=============================================================================== -sub check_cmdline_param () { - my $err_config; - my $err_counter = 0; - if( not defined( $cfg_file)) { - my $cwd = getcwd; - my $name = "/etc/gosa/gosa-si-bus.conf"; - $cfg_file = File::Spec->catfile( $cwd, $name ); - print STDERR "no conf file specified\n try to use default: $cfg_file\n"; - } - if( $err_counter > 0 ) { - &usage( "", 1 ); - if( defined( $err_config)) { print STDERR "$err_config\n"} - print STDERR "\n"; - exit( -1 ); - } -} #=== FUNCTION ================================================================ # NAME: check_pid @@ -205,7 +175,7 @@ sub check_pid { #=============================================================================== sub usage { print STDERR << "EOF" ; -usage: $0 [-hvf] [-c config] +usage: $prg [-hvf] [-c config] -h : this (help) message -c : config file @@ -217,346 +187,269 @@ EOF #=== FUNCTION ================================================================ -# NAME: sig_int_handler -# PARAMETERS: signal - string - signal arose from system -# RETURNS: noting -# DESCRIPTION: handels tasks to be done befor signal becomes active +# NAME: logging +# PARAMETERS: level - string - default 'info' +# msg - string - +# facility - string - default 'LOG_DAEMON' +# RETURNS: +# DESCRIPTION: #=============================================================================== -sub sig_int_handler { - my ($signal) = @_; - if($bus){ - close($bus); - print "$bus closed\n"; +sub daemon_log { + # log into log_file + my( $msg, $level ) = @_; + 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" )) { + print STDERR "cannot open $log_file: $!"; + return } + chomp($msg); + if($level <= $verbose){ + my ($seconds, $minutes, $hours, $monthday, $month, + $year, $weekday, $yearday, $sommertime) = localtime(time); + $hours = $hours < 10 ? $hours = "0".$hours : $hours; + $minutes = $minutes < 10 ? $minutes = "0".$minutes : $minutes; + $seconds = $seconds < 10 ? $seconds = "0".$seconds : $seconds; + my @monthnames = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); + $month = $monthnames[$month]; + $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; + $year+=1900; + + my $log_msg = "$month $monthday $hours:$minutes:$seconds $prg $msg\n"; + print LOG_HANDLE $log_msg; + if( $foreground ) { + print STDERR $log_msg; + } + } + close( LOG_HANDLE ); } - print "$signal\n"; - IPC::Shareable->clean_up; - exit(1); } -$SIG{INT} = \&sig_int_handler; #=== FUNCTION ================================================================ -# NAME: get_ip_and_mac -# PARAMETERS: nothing -# RETURNS: (ip, mac) -# DESCRIPTION: executes /sbin/ifconfig and parses the output, the first occurence -# of a inet address is returned as well as the mac address in the line -# above the inet address +# NAME: get_ip +# PARAMETERS: interface name (i.e. eth0) +# RETURNS: (ip address) +# DESCRIPTION: Uses ioctl to get ip address directly from system. #=============================================================================== -sub get_ip_and_mac { - my $ip = "0.0.0.0.0"; # Defualt-IP - my $mac_address = "00:00:00:00:00:00"; # Default-MAC - my @ifconfig = qx(/sbin/ifconfig); - foreach(@ifconfig) { - if (/Hardware Adresse (\S{2}):(\S{2}):(\S{2}):(\S{2}):(\S{2}):(\S{2})/) { - $mac_address = "$1:$2:$3:$4:$5:$6"; - next; - } - if (/inet Adresse:(\d+).(\d+).(\d+).(\d+)/) { - $ip = "$1.$2.$3.$4"; - last; +sub get_ip { + my $ifreq= shift; + my $result= ""; + my $SIOCGIFADDR= 0x8915; # man 2 ioctl_list + my $proto= getprotobyname('ip'); + + socket SOCKET, PF_INET, SOCK_DGRAM, $proto + or die "socket: $!"; + + if(ioctl SOCKET, $SIOCGIFADDR, $ifreq) { + my ($if, $sin) = unpack 'a16 a16', $ifreq; + my ($port, $addr) = sockaddr_in $sin; + my $ip = inet_ntoa $addr; + + if ($ip && length($ip) > 0) { + $result = $ip; } } - return ($ip, $mac_address); -} + return $result; +} #=== FUNCTION ================================================================ -# NAME: activating_child -# PARAMETERS: msg - string - incoming message -# host - string - host from which the incomming message comes -# RETURNS: nothing -# DESCRIPTION: handels the distribution of incoming messages to working childs +# NAME: get_interface_for_ip +# PARAMETERS: ip address (i.e. 192.168.0.1) +# RETURNS: array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else +# DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. #=============================================================================== -sub activating_child { - my ($msg, $host) = @_; - my $child = &get_processing_child(); - my $pipe_wr = $$child{'pipe_wr'}; - daemon_log("activating: childpid: $$child{'pid'}", 5); - print $pipe_wr $msg.".".$host."\n"; - return; +sub get_interface_for_ip { + my $result; + my $ip= shift; + if ($ip && length($ip) > 0) { + my @ifs= &get_interfaces(); + if($ip eq "0.0.0.0") { + $result = "all"; + } else { + foreach (@ifs) { + my $if=$_; + if(get_ip($if) eq $ip) { + $result = $if; + last; + } + } + } + } + return $result; } #=== FUNCTION ================================================================ -# NAME: get_processing_child -# PARAMETERS: nothing -# RETURNS: child - hash - holding the process id and the references to the pipe -# handles pipe_wr and pipe_rd -# DESCRIPTION: handels the forking, reactivating and keeping alive tasks +# NAME: get_interfaces +# PARAMETERS: none +# RETURNS: (list of interfaces) +# DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. #=============================================================================== -sub get_processing_child { - my $child; - # checking %busy_child{pipe_wr} if msg is 'done', then set child from busy to free - while(my ($key, $val) = each(%busy_child)) { - # check wether process still exists - my $exitus_pid = waitpid($key, WNOHANG); - if($exitus_pid != 0) { - delete $busy_child{$key}; - daemon_log( "prozess:$key wurde aus busy_child entfernt\n", 5); - next; - } +sub get_interfaces { + my @result; + my $PROC_NET_DEV= ('/proc/net/dev'); - # check wether process sitll works - my $fh = $$val{'pipe_rd'}; - $fh->blocking(0); - my $child_answer; - if(not $child_answer = <$fh>) { next } - chomp($child_answer); - if($child_answer eq "done") { - delete $busy_child{$key}; - $free_child{$key} = $val; - } - } + open(PROC_NET_DEV, "<$PROC_NET_DEV") + or die "Could not open $PROC_NET_DEV"; - while(my ($key, $val) = each(%free_child)) { - my $exitus_pid = waitpid($key, WNOHANG); - if($exitus_pid != 0) { - delete $free_child{$key}; - daemon_log( "prozess:$key wurde aus free_child entfernt\n", 5); - } - daemon_log("free child:$key\n", 5); - } - # check @free_child and @busy_child - my $free_len = scalar(keys(%free_child)); - my $busy_len = scalar(keys(%busy_child)); - daemon_log("free children $free_len, busy children $busy_len\n",5); - - # if there is a free child, let the child work - if($free_len > 0){ - my @keys = keys(%free_child); - $child = $free_child{$keys[0]}; - if(defined $child) { - $busy_child{$$child{'pid'}} = $child ; - delete $free_child{$$child{'pid'}}; - } - return $child; - } - - # no free child, try to fork another one - if($free_len + $busy_len < $child_max) { - - daemon_log("not enough children, create a new one\n",5); - - # New pipes for communication - my( $PARENT_wr, $PARENT_rd ); - my( $CHILD_wr, $CHILD_rd ); - pipe( $CHILD_rd, $PARENT_wr ); - pipe( $PARENT_rd, $CHILD_wr ); - $PARENT_wr->autoflush(1); - $CHILD_wr->autoflush(1); - - ############ - # fork child - ############ - my $child_pid = fork(); - - #CHILD - if($child_pid == 0) { - # Close unused pipes - close( $CHILD_rd ); - close( $CHILD_wr ); - while( 1 ) { - my $rbits = ""; - vec( $rbits, fileno $PARENT_rd , 1 ) = 1; - - # waiting child_timeout for jobs to do - my $nf = select($rbits, undef, undef, $child_timeout); - if($nf < 0 ) { - # if $nf < 1, error handling - die "select(): $!\n"; - } elsif (! $nf) { - # if already child_min childs are alive, then leave loop - $free_len = scalar(keys(%free_child)); - $busy_len = scalar(keys(%busy_child)); - if($free_len + $busy_len >= $child_min) { - last; - } else { - redo; - } - } - - # a job for a child arise - if ( vec $rbits, fileno $PARENT_rd, 1 ) { - # read everything from pipe - my $msg = ""; - $PARENT_rd->blocking(0); - while(1) { - my $read = <$PARENT_rd>; - if(not defined $read) { last} - $msg .= $read; - } + my @ifs = ; - # forward the job msg to another function - &process_incoming_msg($msg); - daemon_log("processing of msg finished", 5); + close(PROC_NET_DEV); - # important!!! wait until child says 'done', until then child is set from busy to free - print $PARENT_wr "done"; - redo; - } - } - # childs leaving the loop are allowed to die - exit(0); + # Eat first two line + shift @ifs; + shift @ifs; - #PARENT - } else { - # Close unused pipes - close( $PARENT_rd ); - close( $PARENT_wr ); - # add child to child alive hash - my %child_hash = ( - 'pid' => $child_pid, - 'pipe_wr' => $CHILD_wr, - 'pipe_rd' => $CHILD_rd, - ); - - $child = \%child_hash; - $busy_child{$$child{'pid'}} = $child; - return $child; - } + chomp @ifs; + foreach my $line(@ifs) { + my $if= (split /:/, $line)[0]; + $if =~ s/^\s+//; + push @result, $if; } + + return @result; } #=== FUNCTION ================================================================ -# NAME: process_incoming_msg -# PARAMETERS: crypted_msg - string - incoming crypted message -# RETURNS: nothing -# DESCRIPTION: handels the proceeded distribution to the appropriated functions +# NAME: get_mac +# PARAMETERS: interface name (i.e. eth0) +# RETURNS: (mac address) +# DESCRIPTION: Uses ioctl to get mac address directly from system. #=============================================================================== -sub process_incoming_msg { - my ($crypted_msg) = @_; - if(not defined $crypted_msg) { - daemon_log("function 'process_incoming_msg': got no msg", 7); - return; - } - $crypted_msg =~ /^([\s\S]*?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)$/; - $crypted_msg = $1; - my $host = sprintf("%s.%s.%s.%s", $2, $3, $4, $5); - - daemon_log("msg from host:\n\t$host", 1); - daemon_log("crypted_msg:\n\t$crypted_msg", 7); - - my @valid_keys; - my @daemon_keys = keys %$known_daemons; - foreach my $daemon_key (@daemon_keys) { - if($daemon_key =~ "^$daemon_key") { - push(@valid_keys, $daemon_key); - } - } - - my $l = @valid_keys; - daemon_log("number of valid daemons: $l\n", 7); - - my ($msg, $msg_hash); - my $msg_flag = 0; - - # collect addresses from possible incoming clients - foreach my $host_key (@valid_keys) { - eval{ - daemon_log( "daemon: $host_key\n", 7); - my $key_passwd = $known_daemons->{$host_key}->{passwd}; - daemon_log("daemon_passwd: $key_passwd\n", 7); - my $key_cipher = &create_ciphering($key_passwd); - $msg = &decrypt_msg($crypted_msg, $key_cipher); - daemon_log("daemon decrypted msg:$msg", 7); - $msg_hash = $xml->XMLin($msg, ForceArray=>1); - }; - if($@) { - daemon_log("msg processing raise error", 7); - daemon_log("error string: $@", 7); - $msg_flag += 1; +sub get_mac { + my $ifreq= shift; + my $result; + if ($ifreq && length($ifreq) > 0) { + if($ifreq eq "all") { + if(defined($bus_ip)) { + $result = &get_local_mac_for_remote_ip($bus_ip); + } + elsif ($bus_mac_address && length($bus_mac_address) > 0 && !($bus_mac_address eq "00:00:00:00:00:00")){ + $result = &client_mac_address; + } + else { + $result = "00:00:00:00:00:00"; + } } else { - last; - } - } - - if($msg_flag >= $l) { - daemon_log("\nERROR: do not understand the message:\n$msg" , 1); - return; - } + my $SIOCGIFHWADDR= 0x8927; # man 2 ioctl_list - my $header = &get_content_from_xml_hash($msg_hash, "header"); - my $target = &get_content_from_xml_hash($msg_hash, "target"); - - daemon_log("header from msg:\n\t$header", 1); - daemon_log("msg to process:\n\t$msg", 5); - daemon_log("msg is for: \n\t$target", 7); - - if($target eq $bus_address) { - # msg is for bus - if($header eq 'here_i_am'){ &here_i_am($msg_hash)} - elsif($header eq 'confirm_new_passwd'){ &confirm_new_passwd($msg_hash)} - elsif($header eq 'got_ping') { &got_ping($msg_hash)} - elsif($header eq 'ping') { &ping($msg_hash)} - elsif($header eq 'who_has') { &who_has($msg_hash)} - elsif($header eq 'new_client') { &new_client($msg_hash)} - elsif($header eq 'delete_client') { &delete_client($msg_hash)} - } else { - # msg is for any other server - my @targets = @{$msg_hash->{target}}; - my $len_targets = @targets; - - if ($len_targets == 0){ - # no targets specified - - daemon_log("ERROR: no target specified for msg $header", 1); - - } elsif ($targets[0] eq "*"){ - # all deamons in known_daemons are targets - - my $target = $targets[0]; - my $source = @{$msg_hash->{source}}[0]; - my @target_addresses = keys(%$known_daemons); - foreach my $target_address (@target_addresses) { - if ($target_address eq $source) { next; } - if ($target_address eq $bus_address) { next ; } - $msg_hash->{target} = [$target_address]; - &send_msg_hash2address($msg_hash, $target_address); - } + # A configured MAC Address should always override a guessed value + if ($bus_mac_address and length($bus_mac_address) > 0 and not($bus_mac_address eq "00:00:00:00:00:00")) { + $result= $bus_mac_address; + } + else { + socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip') + or die "socket: $!"; - } else { - # a list of targets is specified - - my $target_address; - foreach $target_address (@targets) { - if (exists $known_daemons->{$target_address}) { - &send_msg_hash2address($msg_hash, $target_address); - } else { - my @daemon_addresses = keys %$known_daemons; - my $daemon_address; - foreach $daemon_address (@daemon_addresses) { - if (exists $known_daemons->{$daemon_address}->{clients}->{$target_address}) { - my $header = &get_content_from_xml_hash($msg_hash, "header"); - &send_msg_hash2address($msg_hash, $daemon_address); - daemon_log("bus forwards msg $header for client $target_address to server $daemon_address", 3); - last; + if(ioctl SOCKET, $SIOCGIFHWADDR, $ifreq) { + my ($if, $mac)= unpack 'h36 H12', $ifreq; + + if (length($mac) > 0) { + $mac=~ m/^([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])$/; + $mac= sprintf("%s:%s:%s:%s:%s:%s", $1, $2, $3, $4, $5, $6); + $result = $mac; } } - } - } } } - - &print_known_daemons_hash(); - return; + return $result; } #=== FUNCTION ================================================================ -# NAME: get_content_of_known_daemons -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -#sub get_content_of_known_daemons { -# my ($host, $content) = @_; -# return; -#} - +# NAME: get_local_mac_for_remote_ip +# PARAMETERS: none (takes server_ip from global variable) +# RETURNS: (ip address from interface that is used for communication) +# DESCRIPTION: Uses ioctl to get routing table from system, checks which entry +# matches (defaultroute last). +#=============================================================================== +sub get_local_mac_for_remote_ip { + my $server_ip= shift; + my $result= "00:00:00:00:00:00"; + + if($server_ip =~ /^(\d\d?\d?\.){3}\d\d?\d?$/) { + my $PROC_NET_ROUTE= ('/proc/net/route'); + + open(PROC_NET_ROUTE, "<$PROC_NET_ROUTE") + or die "Could not open $PROC_NET_ROUTE"; + + my @ifs = ; + + close(PROC_NET_ROUTE); + + # Eat header line + shift @ifs; + chomp @ifs; + foreach my $line(@ifs) { + my ($Iface,$Destination,$Gateway,$Flags,$RefCnt,$Use,$Metric,$Mask,$MTU,$Window,$IRTT)=split(/\s/, $line); + my $destination; + my $mask; + my ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Destination); + $destination= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d)); + ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Mask); + $mask= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d)); + if(new NetAddr::IP($server_ip)->within(new NetAddr::IP($destination, $mask))) { + # destination matches route, save mac and exit + $result= &get_mac($Iface); + last; + } + } + } else { + daemon_log("get_local_mac_for_remote_ip was called with a non-ip parameter: $server_ip", 1); + } + return $result; +} + +sub bus_matches { + my $target = shift; + my $target_ip = sprintf("%s", $target =~ /^([0-9\.]*?):.*$/); + my $result = 0; + + if($bus_ip eq $target_ip) { + $result= 1; + } elsif ($bus_ip eq "0.0.0.0") { + if ($target_ip eq "127.0.0.1") { + $result= 1; + } else { + my $PROC_NET_ROUTE= ('/proc/net/route'); + + open(PROC_NET_ROUTE, "<$PROC_NET_ROUTE") + or die "Could not open $PROC_NET_ROUTE"; + + my @ifs = ; + + close(PROC_NET_ROUTE); + + # Eat header line + shift @ifs; + chomp @ifs; + foreach my $line(@ifs) { + my ($Iface,$Destination,$Gateway,$Flags,$RefCnt,$Use,$Metric,$Mask,$MTU,$Window,$IRTT)=split(/\s/, $line); + my $destination; + my $mask; + my ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Destination); + $destination= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d)); + ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Mask); + $mask= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d)); + if(new NetAddr::IP($target_ip)->within(new NetAddr::IP($destination, $mask))) { + # destination matches route, save mac and exit + $result= 1; + last; + } + } + } + } else { + &main::daemon_log("Target ip $target_ip does not match bus ip $bus_ip",1); + } + + return $result; +} #=== FUNCTION ================================================================ # NAME: create_passwd @@ -573,144 +466,144 @@ sub create_passwd { } -#=== FUNCTION ================================================================ -# NAME: create_ciphering -# PARAMETERS: passwd - string - used to create ciphering -# RETURNS: cipher - object -# DESCRIPTION: creates a Crypt::Rijndael::MODE_CBC object with passwd as key -#=============================================================================== sub create_ciphering { my ($passwd) = @_; + if((!defined($passwd)) || length($passwd)==0) { + $passwd = ""; + } $passwd = substr(md5_hex("$passwd") x 32, 0, 32); my $iv = substr(md5_hex('GONICUS GmbH'),0, 16); - - #daemon_log("iv: $iv", 7); - #daemon_log("key: $passwd", 7); my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC()); $my_cipher->set_iv($iv); return $my_cipher; } -#=== FUNCTION ================================================================ -# NAME: encrypt_msg -# PARAMETERS: msg - string - message to encrypt -# my_cipher - ref - reference to a Crypt::Rijndael object -# RETURNS: crypted_msg - string - crypted message -# DESCRIPTION: crypts the incoming message with the Crypt::Rijndael module -#=============================================================================== sub encrypt_msg { - my ($msg, $my_cipher) = @_; - if(not defined $my_cipher) { print "no cipher object\n"; } - $msg = "\0"x(16-length($msg)%16).$msg; - my $crypted_msg = $my_cipher->encrypt($msg); - chomp($crypted_msg = &encode_base64($crypted_msg)); - return $crypted_msg; + my ($msg, $key) = @_; + my $my_cipher = &create_ciphering($key); + my $len; + { + use bytes; + $len= 16-length($msg)%16; + } + $msg = "\0"x($len).$msg; + $msg = $my_cipher->encrypt($msg); + chomp($msg = &encode_base64($msg)); + # there are no newlines allowed inside msg + $msg=~ s/\n//g; + return $msg; } -#=== FUNCTION ================================================================ -# NAME: decrypt_msg -# PARAMETERS: crypted_msg - string - message to decrypt -# my_cipher - ref - reference to a Crypt::Rijndael object -# RETURNS: msg - string - decrypted message -# DESCRIPTION: decrypts the incoming message with the Crypt::Rijndael module -#=============================================================================== sub decrypt_msg { - my ($crypted_msg, $my_cipher) = @_ ; - $crypted_msg = &decode_base64($crypted_msg); - my $msg = $my_cipher->decrypt($crypted_msg); - $msg =~ s/^\0*//g; + + my ($msg, $key) = @_ ; + $msg = &decode_base64($msg); + my $my_cipher = &create_ciphering($key); + $msg = $my_cipher->decrypt($msg); + $msg =~ s/\0*//g; return $msg; } -#=== FUNCTION ================================================================ -# NAME: create_xml_hash -# PARAMETERS: header - string - message header (required) -# source - string - where the message come from (required) -# target - string - where the message should go to (required) -# [header_value] - string - something usefull (optional) -# RETURNS: hash - hash - nomen est omen -# DESCRIPTION: creates a key-value hash, all values are stored in a array -#=============================================================================== -sub create_xml_hash { - my ($header, $source, $target, $header_value) = @_ ; +sub send_msg_hash2address { + my ($msg_hash, $address, $encrypt_key) = @_ ; + my $msg = &create_xml_string($msg_hash); + my $header = @{$msg_hash->{'header'}}[0]; + &send_msg_to_target($msg, $address, $encrypt_key, $header); - if (not defined $header || not defined $source || not defined $target) { - daemon_log("ERROR: create_xml_hash function is invoked with uncompleted parameters", 7); + return; +} + + +sub send_msg_to_target { + my ($msg, $address, $encrypt_key, $msg_header) = @_ ; + my $error = 0; + my $header; + my $new_status; + my $act_status; + my ($sql_statement, $res); + + if( $msg_header ) { + $header = "'$msg_header'-"; + } + else { + $header = ""; } - my $hash = { - header => [$header], - source => [$source], - target => [$target], - $header => [$header_value], - }; - #daemon_log("create_xml_hash:", 7), - #chomp(my $tmp = Dumper $hash); - #daemon_log("\t$tmp\n", 7); - return $hash -} + # encrypt xml msg + my $crypted_msg = &encrypt_msg($msg, $encrypt_key); + # opensocket + my $socket = &open_socket($address); + if( !$socket ) { + daemon_log("cannot send ".$header."msg to $address , host not reachable", 1); + $error++; + } + + if( $error == 0 ) { + # send xml msg + print $socket $crypted_msg."\n"; -#=== FUNCTION ================================================================ -# NAME: create_xml_string -# PARAMETERS: xml_hash - hash - hash from function create_xml_hash -# RETURNS: xml_string - string - xml string representation of the hash -# DESCRIPTION: transform the hash to a string using XML::Simple module -#=============================================================================== -sub create_xml_string { - my ($xml_hash) = @_ ; - my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml'); - $xml_string =~ s/[\n]+//g; - return $xml_string; -} + daemon_log("send ".$header."msg to $address", 1); + daemon_log("message:\n$msg", 8); + } -#=== FUNCTION ================================================================ -# NAME: add_content2xml_hash -# PARAMETERS: xml_ref - ref - reference to a hash from function create_xml_hash -# element - string - key for the hash -# content - string - value for the hash -# RETURNS: nothing -# DESCRIPTION: add key-value pair to xml_ref, if key alread exists, then append value to list -#=============================================================================== -sub add_content2xml_hash { - my ($xml_ref, $element, $content) = @_; - if(not exists $$xml_ref{$element} ) { - $$xml_ref{$element} = []; + # close socket in any case + if( $socket ) { + close $socket; } - my $tmp = $$xml_ref{$element}; - push(@$tmp, $content); - return; -} + if( $error > 0 ) { $new_status = "down"; } + else { $new_status = $msg_header; } + + + # known_clients + $sql_statement = "SELECT * FROM bus_known_clients WHERE hostname='$address'"; + $res = $bus_known_clients_db->select_dbentry($sql_statement); + if( keys(%$res) > 0 ) { + $act_status = $res->{1}->{'status'}; + if( $act_status eq "down" ) { + $sql_statement = "DELETE FROM bus_known_clients WHERE hostname='$address'"; + $res = $bus_known_clients_db->del_dbentry($sql_statement); + daemon_log("WARNING: failed 2x to send msg to host '$address', delete host from bus_known_clients", 3); + } + else { + $sql_statement = "UPDATE bus_known_clients SET status='$new_status' WHERE hostname='$address'"; + $res = $bus_known_clients_db->update_dbentry($sql_statement); + daemon_log("INFO: set '$address' from status '$act_status' to '$new_status'", 5); + } + } -#=== FUNCTION ================================================================ -# NAME: get_content_from_xml_hash -# PARAMETERS: xml_ref - ref - reference of the xml hash -# element - string - key of the value you want -# RETURNS: value - string - if key is either header, target or source -# value - list - for all other keys in xml hash -# DESCRIPTION: -#=============================================================================== -sub get_content_from_xml_hash { - my ($xml_ref, $element) = @_; - my $result = $xml_ref->{$element}; - if( $element eq "header" || $element eq "target" || $element eq "source") { - return @$result[0]; + # known_server + $sql_statement = "SELECT * FROM bus_known_server WHERE hostname='$address'"; + $res = $bus_known_server_db->select_dbentry($sql_statement); + if( keys(%$res) > 0) { + $act_status = $res->{1}->{'status'}; + if( $act_status eq "down" ) { + $sql_statement = "DELETE FROM bus_known_clients WHERE hostname='$address'"; + $res = $bus_known_clients_db->del_dbentry($sql_statement); + daemon_log("WARNING: failed 2x to a send msg to host '$address', delete host from bus_known_server", 3); + } + else { + $sql_statement = "UPDATE bus_known_server SET status='$new_status' WHERE hostname='$address'"; + $res = $bus_known_server_db->update_dbentry($sql_statement); + daemon_log("INFO: set '$address' from status '$act_status' to '$new_status'", 5) + } } - return @$result; + + return; } #=== FUNCTION ================================================================ # NAME: open_socket -# PARAMETERS: PeerAddr - string - something like 192.168.1.1 or 192.168.1.1:10000 -# [PeerPort] - string - necessary if port not appended by PeerAddr -# RETURNS: socket - IO::Socket::INET -# DESCRIPTION: open a socket to PeerAddr +# PARAMETERS: PeerAddr string something like 192.168.1.1 or 192.168.1.1:10000 +# [PeerPort] string necessary if port not appended by PeerAddr +# RETURNS: socket IO::Socket::INET +# DESCRIPTION: open a socket to PeerAddr #=============================================================================== sub open_socket { my ($PeerAddr, $PeerPort) = @_ ; @@ -718,373 +611,302 @@ sub open_socket { $PeerAddr = $PeerAddr.":".$PeerPort; } my $socket; - $socket = new IO::Socket::INET(PeerAddr => $PeerAddr , - Porto => "tcp" , + $socket = new IO::Socket::INET(PeerAddr => $PeerAddr, + Porto => "tcp", Type => SOCK_STREAM, - Reuse => 1, Timeout => 5, ); if(not defined $socket) { return; } + &daemon_log("open_socket: $PeerAddr", 7); return $socket; } -#=== FUNCTION ================================================================ -# NAME: read_from_socket -# PARAMETERS: socket - fh - filehandel to read from -# RETURNS: result - string - readed characters from socket -# DESCRIPTION: reads data from socket in 16 byte steps -#=============================================================================== -sub read_from_socket { - my ($socket) = @_; - - $socket->blocking(1); - my $result = <$socket>; - $socket->blocking(0); - my $part_msg; - while ($part_msg = <$socket>) { - if (not defined $part_msg) { last; } - $result .= $part_msg; - } - - #my $result = ""; - #my $len = 16; - #while($len == 16){ - # my $char; - # $len = sysread($socket, $char, 16); - # if($len != 16) { last } - # if($len != 16) { last } - # $result .= $char; - #} - return $result; -} +sub check_key_and_xml_validity { + my ($crypted_msg, $module_key) = @_; +#print STDERR "crypted_msg:$crypted_msg\n"; +#print STDERR "modul_key:$module_key\n"; + my $msg; + my $msg_hash; + eval{ + $msg = &decrypt_msg($crypted_msg, $module_key); + &main::daemon_log("decrypted_msg: \n$msg", 8); -#=== FUNCTION ================================================================ -# NAME: send_msg_hash2address -# PARAMETERS: msg_hash - hash - xml_hash created with function create_xml_hash -# PeerAddr string - socket address to send msg -# PeerPort string - socket port, if not included in socket address -# RETURNS: nothing -# DESCRIPTION: ???? -#=============================================================================== -sub send_msg_hash2address { - my ($msg_hash, $address) = @_ ; + $msg_hash = $xml->XMLin($msg, ForceArray=>1); - # fetch header for logging - my $header = &get_content_from_xml_hash($msg_hash, "header"); - - # generate xml string - my $msg_xml = &create_xml_string($msg_hash); - - # fetch the appropriated passwd from hash - my $passwd = $known_daemons->{$address}->{passwd}; + # check header + my $header_l = $msg_hash->{'header'}; + if( 1 != @{$header_l} ) { + die 'no or more headers specified'; + } + my $header = @{$header_l}[0]; + if( 0 == length $header) { + die 'header has length 0'; + } - # create a ciphering object - my $act_cipher = &create_ciphering($passwd); + # check source + my $source_l = $msg_hash->{'source'}; + if( 1 != @{$source_l} ) { + die 'no or more sources specified'; + } + my $source = @{$source_l}[0]; + if( 0 == length $source) { + die 'source has length 0'; + } - # encrypt xml msg - my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher); + # check target + my $target_l = $msg_hash->{'target'}; + if( 1 != @{$target_l} ) { + die 'no or more targets specified '; + } + my $target = @{$target_l}[0]; + if( 0 == length $target) { + die 'target has length 0 '; + } - # open socket - my $socket = &open_socket($address); - if(not defined $socket){ - daemon_log("ERROR: cannot send '$header'-msg to $address , server not reachable", 1); - return; + }; + if($@) { + &main::daemon_log("WARNING: do not understand the message or msg is not gosa-si envelope conform:", 5); + &main::daemon_log("$@", 8); } - # send xml msg - print $socket $crypted_msg."\n"; - - close $socket; - daemon_log("send '$header'-msg to $address", 5); - daemon_log("crypted_msg:\n\t$crypted_msg", 7); - return; + return ($msg, $msg_hash); } -#=== FUNCTION ================================================================ -# NAME: send_msg_hash2all -# PARAMETERS: msg_hash - hash - xml_hash created with function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: send msg_hash to all registered daemons -#=============================================================================== -sub send_msg_hash2all { - my ($msg_hash) = @_; +sub input_from_new_server { + no strict "refs"; + my ($input) = @_ ; + my ($msg, $msg_hash); - # fetch header for logging - my $header = &get_content_from_xml_hash($msg_hash, "header"); + daemon_log("bus_known_server host_name: new host", 7); + daemon_log("bus_known_server host_key: $bus_key", 7); - # generate xml string - my $msg_xml = &create_xml_string($msg_hash); + # check if module can open msg envelope with key + ($msg, $msg_hash) = &check_key_and_xml_validity($input, $bus_key); - # fetch a list of all target addresses - my @targets = keys(%$known_daemons); + if( (!$msg) || (!$msg_hash) ) { + daemon_log("Incoming message is not from a new gosa-si-server", 5); + } - # itterates through the list an send each the msg - foreach my $target (@targets) { - if($target eq $bus_address) {next}; # do not send msg to bus + return ($msg, $msg_hash); +} - # fetch the appropriated passwd - my $passwd = $known_daemons->{$target}->{passwd}; - # create ciphering object - my $act_cipher = &create_ciphering($passwd); +sub input_from_known_server { + my ($input, $remote_ip) = @_ ; + my ($msg, $msg_hash); - # encrypt xml msg - my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher); + my $sql_statement= "SELECT * FROM bus_known_server"; + my $query_res = $bus_known_server_db->select_dbentry( $sql_statement ); - # open socket - my $socket = &open_socket($target); - if(not defined $socket){ - daemon_log("ERROR: cannot open socket to $target , server not reachable", 1); - &update_known_daemons_entry(hostname=>$target, status=>"down"); + while( my ($hit_num, $hit) = each %{ $query_res } ) { + my $host_name = $hit->{hostname}; + if( not $host_name =~ "^$remote_ip") { next; } + my $host_key = $hit->{hostkey}; + daemon_log("bus_known_server host_name: $host_name", 7); + daemon_log("bus_known_server host_key: $host_key", 7); - # send xml msg - print $socket $crypted_msg."\n"; + # check if module can open msg envelope with module key + my ($tmp_msg, $tmp_msg_hash) = &check_key_and_xml_validity($input, $host_key); + if( (!$tmp_msg) || (!$tmp_msg_hash) ) { + next; + } + else { + $msg = $tmp_msg; + $msg_hash = $tmp_msg_hash; + last; + } + } - close $socket; - daemon_log("send '$header'-msg to $target", 5); - daemon_log("crypted_msg:\n\t$crypted_msg", 7); + if( (!$msg) || (!$msg_hash) ) { + daemon_log("Incoming message is not from a known gosa-si-server", 5); } - return; + + return ($msg, $msg_hash); } -#=== FUNCTION ================================================================ -# NAME: here_i_am -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process the incoming msg 'here_i_am' -#=============================================================================== -sub here_i_am { - my ($msg_hash) = @_ ; - my $source = &get_content_from_xml_hash($msg_hash, "source"); - - my $new_passwd = &create_passwd(); - - # create known_daemons entry - &create_known_daemons_entry($source); - &update_known_daemons_entry(hostname=>$source, status=>"registered", passwd=>$bus_passwd); - - # create outgoing msg - my $out_hash = &create_xml_hash("new_passwd", "$bus_ip:$bus_port", $source, $new_passwd); - &send_msg_hash2address($out_hash, $source); - - # change passwd, reason - # &send_msg_hash2address takes $known_daemons->{"$source"}->{passwd} to cipher msg - &update_known_daemons_entry(hostname=>$source, status=>"new_passwd", passwd=>$new_passwd); - +sub _start { + my $kernel = $_[KERNEL]; + $kernel->alias_set('gosa_si_bus_session'); return; } - -#=== FUNCTION ================================================================ -# NAME: confirm_new_passwd -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub confirm_new_passwd { - my ($msg_hash) = @_ ; - my $source = &get_content_from_xml_hash($msg_hash, "source"); - &update_known_daemons_entry(hostname=>$source, status=>"confirmed_new_passwd"); +sub _default { + daemon_log("ERROR: can not handle incoming msg with header '$_[ARG0]'", 1); return; } -#=== FUNCTION ================================================================ -# NAME: ping -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub ping { - my ($msg_hash) = @_ ; - my $source = &get_content_from_xml_hash($msg_hash, "source"); - &update_known_daemons_entry(hostname=>$source, status=>"ping"); - my $out_hash = &create_xml_hash("got_ping", $bus_address, $source); - &send_msg_hash2address($out_hash, $source); - return; -} - +sub bus_input { + my ($kernel, $heap, $input, $wheel, $session) = @_[KERNEL, HEAP, ARG0, ARG1, SESSION]; + my ($msg, $msg_hash); + my $error = 0; + + daemon_log("Incoming msg:\n$input\n", 8); -#=== FUNCTION ================================================================ -# NAME: make ping -# PARAMETERS: address - string - address which should be pinged -# RETURNS: nothing -# DESCRIPTION: send ping message to address -#=============================================================================== -sub make_ping { - my ($address) = @_; - daemon_log("ping:$address\n", 1); - my $out_hash = &create_xml_hash("ping", "$bus_ip:$bus_port", $address); - &send_msg_hash2address($out_hash, $address); - return; -} + # msg is from a new gosa-si-server + ($msg, $msg_hash) = &input_from_new_server($input); + # msg is from a gosa-si-server or gosa-si-bus + if(( !$msg ) || ( !$msg_hash ) ){ + ($msg, $msg_hash) = &input_from_known_server($input, $heap->{'remote_ip'}); + } -#=== FUNCTION ================================================================ -# NAME: got_ping -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub got_ping { - my ($msg_hash) = @_; - my $source = &get_content_from_xml_hash($msg_hash, "source"); - &update_known_daemons_entry(hostname=>$source, status=>"got_ping"); - return; -} + # an error occurred + if(( !$msg ) || ( !$msg_hash )){ + $error++; + } + if( $error == 0) { + my @target_l = @{$msg_hash->{'target'}}; + my $source = @{$msg_hash->{'source'}}[0]; + my $header = @{$msg_hash->{header}}[0]; -#=== FUNCTION ================================================================ -# NAME: new_client -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub new_client { - my ($msg_hash) = @_ ; - my $source = &get_content_from_xml_hash($msg_hash, "source"); - my $header = &get_content_from_xml_hash($msg_hash, "header"); - my $new_client = (&get_content_from_xml_hash($msg_hash, $header))[0]; - - &update_known_daemons_entry(hostname=>$source, client=>$new_client); - return; -} + my $target_string = join(",", @target_l); + daemon_log("got msg '$header' with target '$target_string' from ".$heap->{'remote_ip'}, 3); + if( 1 == length(@target_l) && &bus_matches($target_l[0]) ) { + # msg is for bus +#print STDERR "msg is for bus\n"; + $kernel->post('gosa_si_bus_session', $header, $msg, $msg_hash); + } + else { + # msg is for someone else, deliver it + +#print STDERR "msg is for someone else\n"; + foreach my $target (@target_l) { + if( $target =~ /(\d{0,3}\.\d{0,3}\.\d{0,3}\.\d{0,3}:\d+)/ ) { + # target is a ip address + my ($sql_statement, $query_res); + + $sql_statement = "SELECT * FROM bus_known_server WHERE hostname='$target'"; + $query_res = $bus_known_server_db->select_dbentry( $sql_statement ); + if( 1 == keys(%$query_res) ) { + my $host_name = $query_res->{1}->{'hostname'}; + my $host_key = $query_res->{1}->{'hostkey'}; + &send_msg_to_target($msg, $host_name, $host_key, $header); + next; + } + + $sql_statement = "SELECT * FROM bus_known_clients WHERE hostname='$target'"; + $query_res = $bus_known_clients_db->select_dbentry( $sql_statement ); + if( 1 == keys(%$query_res) ) { + my $host_name = $query_res->{1}->{'hostname'}; + my $server_name = $query_res->{1}->{'registered'}; + # fetch correct key for server + my $sql_statement = "SELECT * FROM bus_known_server WHERE hostname='$server_name'"; + my $query_res = $bus_known_server_db->select_dbentry( $sql_statement ); + my $server_key = $query_res->{1}->{'hostkey'}; + &send_msg_to_target($msg, $server_name, $server_key, $header); + next; + } + + daemon_log("ERROR:unknown host, can not send message '$header' to target '$target'", 1); + } + elsif( $target =~ /([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})/ ) { + # target is a mac address + my $sql_statement = "SELECT * FROM bus_known_clients WHERE macaddress LIKE '$target'"; + my $query_res = $bus_known_clients_db->select_dbentry( $sql_statement ); + if( 1 > keys(%{$query_res})) { + daemon_log("ERROR: there are more than one hosts in bus_known_clients_db with mac address '$target'", 1); + } + elsif( 0 == keys(%{$query_res})) { + daemon_log("WARNING: no host found in bus_known_clients_db with mac address '$target'", 3); + } + else { + my $host_name = $query_res->{1}->{'hostname'}; + my $server_name = $query_res->{1}->{'registered'}; + my $out_msg = $msg; + $out_msg =~ s/$target<\/target>/$host_name<\/target>/; + + # fetch correct key for server + my $sql_statement = "SELECT * FROM bus_known_server WHERE hostname='$server_name'"; + my $query_res = $bus_known_server_db->select_dbentry( $sql_statement ); + my $server_key = $query_res->{1}->{'hostkey'}; + + &send_msg_to_target($out_msg, $server_name, $server_key, $header); + } + } + else { + daemon_log("ERROR: target address '$target' does not match neiter ". + "to ip address nor to mac address, can not send msg", 1); + } -#=== FUNCTION ================================================================ -# NAME: delete_client -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub delete_client { - my ($msg_hash) = @_ ; - my $source = &get_content_from_xml_hash($msg_hash, "source"); - my $header = &get_content_from_xml_hash($msg_hash, "header"); - my $del_client = (&get_content_from_xml_hash($msg_hash, $header))[0]; - - if (not exists $known_daemons->{$source}->{$del_client}) { - daemon_log + } + } } - delete $known_daemons->{$source}->{$del_client}; - - return; } -#=== FUNCTION ================================================================ -# NAME: print_known_daemons_hash -# PARAMETERS: nothing -# RETURNS: nothing -# DESCRIPTION: nome est omen -#=============================================================================== -sub print_known_daemons_hash { - my ($tmp) = @_; - print "####################################\n"; - print "# status of known_daemons\n"; - my $hosts; - my $host_hash; - $shmkh->shlock(LOCK_EX); - my @hosts = keys %$known_daemons; - foreach my $host (@hosts) { - my $status = $known_daemons->{$host}->{status} ; - my $passwd = $known_daemons->{$host}->{passwd}; - my $timestamp = $known_daemons->{$host}->{timestamp}; - my @clients = keys %{$known_daemons->{$host}->{clients}}; - my $client_string = join(", ", @clients); - print "$host\n"; - print "\tstatus: $status\n"; - print "\tpasswd: $passwd\n"; - print "\ttimestamp: $timestamp\n"; - print "\tclients: $client_string\n"; - - } - $shmkh->shunlock(LOCK_EX); - print "####################################\n\n"; - return; +sub here_i_am { + my ( $msg, $msg_hash ) = @_[ ARG0, ARG1 ]; + my $source = @{$msg_hash->{'source'}}[0]; + my $target = @{$msg_hash->{'target'}}[0]; + + my $new_key = &create_passwd(); + + # create bus_known_server entry + my $add_hash = { + table=>"bus_known_server", + primkey=>"hostname", + hostname=>$source, + status=>"registered", + hostkey=>$bus_key, + }; + $bus_known_server_db->add_dbentry($add_hash); + + # create outgoing msg + my $out_hash = &create_xml_hash("new_key", $target, $source, $new_key); + &send_msg_hash2address($out_hash, $source, $bus_key); + + # change hostkey, reason + my $where_str= " WHERE hostname='$source'"; + my $update_str= " SET hostkey='$new_key'"; + my $sql_statement= "UPDATE bus_known_server $update_str $where_str"; + $bus_known_server_db->update_dbentry($sql_statement); } -#=== FUNCTION ================================================================ -# NAME: create_known_daemons_entry -# PARAMETERS: hostname - string - ip address and port of host -# RETURNS: nothing -# DESCRIPTION: nome est omen -#=============================================================================== -sub create_known_daemons_entry { - my ($hostname) = @_; - $shmkh->shlock(LOCK_EX); - $known_daemons->{$hostname} = {}; - $known_daemons->{$hostname}->{status} = "none"; - $known_daemons->{$hostname}->{passwd} = "none"; - $known_daemons->{$hostname}->{timestamp} = "none"; - $known_daemons->{$hostname}->{clients} = {}; - $shmkh->shunlock(LOCK_EX); - return; +sub confirm_new_key { + my ( $msg, $msg_hash ) = @_[ ARG0, ARG1 ]; + my $source = @{$msg_hash->{'source'}}[0]; + daemon_log("'$source' confirms new key", 3); } -#=== FUNCTION ================================================================ -# NAME: update_known_daemons_entry -# PARAMETERS: hostname - string - ip address and port of host (required) -# status - string - (optional) -# passwd - string - (optional) -# client - string - ip address and port of client (optional) -# RETURNS: nothing -# DESCRIPTION: nome est omen and updates each time the timestamp of hostname -#=============================================================================== -sub update_known_daemons_entry { - my $arg = { - hostname => undef, status => undef, passwd => undef, - client => undef, - @_ }; - my $hostname = $arg->{hostname}; - my $status = $arg->{status}; - my $passwd = $arg->{passwd}; - my $client = $arg->{client}; - - if (not defined $hostname) { - daemon_log("ERROR: function add_content2known_daemons is not invoked with requiered parameter 'hostname'", 1); - return; - } +sub new_client { + my ($msg, $msg_hash) = @_[ ARG0, ARG1 ]; - my ($seconds, $minutes, $hours, $monthday, $month, - $year, $weekday, $yearday, $sommertime) = localtime(time); - $hours = $hours < 10 ? $hours = "0".$hours : $hours; - $minutes = $minutes < 10 ? $minutes = "0".$minutes : $minutes; - $seconds = $seconds < 10 ? $seconds = "0".$seconds : $seconds; - $month+=1; - $month = $month < 10 ? $month = "0".$month : $month; - $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; - $year+=1900; - my $t = "$year$month$monthday$hours$minutes$seconds"; - - $shmkh->shlock(LOCK_EX); - if (defined $status) { - $known_daemons->{$hostname}->{status} = $status; - } - if (defined $passwd) { - $known_daemons->{$hostname}->{passwd} = $passwd; - } - if (defined $client) { - $known_daemons->{$hostname}->{clients}->{$client} = ""; - } - $known_daemons->{$hostname}->{timestamp} = $t; - $shmkh->shunlock(LOCK_EX); - return; + my $new_client = @{$msg_hash->{'new_client'}}[0]; + my $source = @{$msg_hash->{'source'}}[0]; + my $mac_address = @{$msg_hash->{'macaddress'}}[0]; + my $act_timestamp = @{$msg_hash->{'timestamp'}}[0]; + + my $add_hash = { + table => "bus_known_clients", + primkey=>"hostname", + hostname=>$new_client, + status=>'activ', + registered=>$source, + macaddress=>$mac_address, + timestamp=>$act_timestamp, + }; + $bus_known_clients_db->add_dbentry($add_hash); + daemon_log("add new client '$new_client' to bus_known_clients_db", 3); } + #==== MAIN = main ============================================================== + # parse commandline options Getopt::Long::Configure( "bundling" ); GetOptions("h|help" => \&usage, @@ -1100,84 +922,80 @@ GetOptions("h|help" => \&usage, $SIG{CHLD} = 'IGNORE'; -# restart daemon log file -if(-e $log_file ) { unlink $log_file } -daemon_log("$0 started!"); -# Just fork, if we"re not in foreground mode -if( ! $foreground ) { $pid = fork(); } -else { $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 ) }; -} - -# detect own ip and mac address -($bus_ip, $bus_mac_address) = &get_ip_and_mac(); -if (not defined $bus_ip) { - die "EXIT: ip address of $0 could not be detected"; + if( !$foreground ) { + exit( 0 ) + }; } -daemon_log("bus ip address detected: $bus_ip", 1); -daemon_log("bus mac address detected: $bus_mac_address", 1); +# restart daemon log file +if(-e $log_file ) { unlink $log_file } +daemon_log(" ", 1); +daemon_log("started!", 1); -# setup xml parser -$xml = new XML::Simple(); +# delete old DBsqlite lock files +system('rm -f /tmp/gosa_si_lock*gosa-si-bus*'); -# create cipher object -$bus_cipher = &create_ciphering($bus_passwd); +#prepare other variables +$xml = new XML::Simple(); $bus_address = "$bus_ip:$bus_port"; -# create reading and writing vectors -my $rbits = my $wbits = my $ebits = ""; - -# open the bus socket -if($bus_activ eq "on") { - $bus = IO::Socket::INET->new(LocalPort => $bus_port, - Type => SOCK_STREAM, - Reuse => 1, - Listen => 20, - ) or die "kann kein TCP-Server an Port $bus_port sein: $@\n"; - vec($rbits, fileno $bus, 1) = 1; - vec($wbits, fileno $bus, 1) = 1; - print "start bus at $bus_ip:$bus_port\n"; -} - -# add bus to known_daemons -&create_known_daemons_entry($bus_address); -&update_known_daemons_entry(hostname=>$bus_address, status=>"bus", passwd=>$bus_passwd); - - -while(1) { - my $nf = select($rbits, $wbits, undef, undef); - # error handling - if($nf < 0 ) { - } - - # something is coming in - if(vec $rbits, fileno $bus, 1 ) { - my $client = $bus->accept(); - my $other_end = getpeername($client); - if(not defined $other_end) { - daemon_log("Gegenstelle konnte nicht identifiziert werden: $!\n"); - } else { - my ($port, $iaddr) = unpack_sockaddr_in($other_end); - my $actual_ip = inet_ntoa($iaddr); - daemon_log("\naccept client from $actual_ip\n", 5); - my $in_msg = &read_from_socket($client); - if(defined $in_msg){ - &activating_child($in_msg, $actual_ip); - } else { - daemon_log("cannot read from $actual_ip\n",1); - } - } - close($client); - } - -} - - +# detect ip and mac address and complete host address +my $network_interface= &get_interface_for_ip($bus_ip); +$bus_mac_address= &get_mac($network_interface); +daemon_log("gosa-si-bus ip address detected: $bus_ip", 1); +daemon_log("gosa-si-bus mac address detected: $bus_mac_address", 1); + +# connect to bus_known_server_db +my @server_col_names = ('hostname', 'status', 'hostkey', 'timestamp'); +$bus_known_server_db = GOSA::DBsqlite->new($bus_known_server_file_name); +$bus_known_server_db->create_table('bus_known_server', \@server_col_names); + +my @clients_col_names = ('hostname', 'status', 'registered', 'macaddress', 'timestamp'); +$bus_known_clients_db = GOSA::DBsqlite->new($bus_known_clients_file_name); +$bus_known_clients_db->create_table('bus_known_clients', \@clients_col_names); + +# create socket for incoming xml messages +POE::Component::Server::TCP->new( + Alias => 'gosa-si-bus_socket', + Port => $bus_port, + ClientInput => \&bus_input, +); +daemon_log("start socket for incoming xml messages at port '$bus_port' ", 1); + +# start session +POE::Session->create( + inline_states => { + _start => \&_start, + _default => \&_default, + here_i_am => \&here_i_am, + confirm_new_key => \&confirm_new_key, + new_client => \&new_client, + } +); + +POE::Kernel->run(); +exit;