Code

update!
authorrettenbe <rettenbe@594d385d-05f5-0310-b6e9-bd551577e9d8>
Tue, 27 Nov 2007 14:38:45 +0000 (14:38 +0000)
committerrettenbe <rettenbe@594d385d-05f5-0310-b6e9-bd551577e9d8>
Tue, 27 Nov 2007 14:38:45 +0000 (14:38 +0000)
msg forwarding from bus to server and from server to client (include broadcasting)
who_has-function working version

git-svn-id: https://oss.gonicus.de/repositories/gosa/trunk@7914 594d385d-05f5-0310-b6e9-bd551577e9d8

contrib/daemon/gosa-sc
contrib/daemon/gosa-sc.cfg
contrib/daemon/gosa-sd
contrib/daemon/gosa-sd-bus
contrib/daemon/gosa-sd.cfg

index 03084d26f4ead0b14d4b99d96b2d8e8ee6256b5b..89139bf191274f39a7897ae90f310f9903475762 100755 (executable)
@@ -31,29 +31,37 @@ use Crypt::Rijndael;
 use XML::Simple;
 use Data::Dumper;
 use Sys::Syslog qw( :DEFAULT setlogsock);
+use File::Spec;
+use Cwd;
+
 
 
 my ($cfg_file, %cfg_defaults, $foreground, $verbose, $pid_file, $procid, $pid, $log_file);
-my ($server_address, $server_ip, $server_port, $server_passwd, $server_cipher, $server_timeout);
-my ($my_address, $my_ip, $my_port, $input_socket, $rbits, $wbits, $ebits, $xml, $known_hosts);
+my ($server_address, $server_ip, $server_port, $server_domain, $server_passwd, $server_cipher, $server_timeout);
+my ($client_address, $client_ip, $client_port, $mac_address);
+my ($input_socket, $rbits, $wbits, $ebits, $xml, $known_hosts);
 
 # default variables
 $known_hosts = {};
 $foreground = 0 ;
-$my_ip = "10.89.1.155";
-$my_port = "10010";
 %cfg_defaults =
 ("general" =>
     {"log_file" => [\$log_file, "/var/run/".$0.".log"],
     "pid_file" => [\$pid_file, "/var/run/".$0.".pid"],
 
+    },
+"client" => 
+    {"client_ip" => [\$client_ip, "10.89.1.155"],
+    "client_port" => [\$client_port, "10010"],
+    "mac_address" => [\$mac_address, ""],
     },
 "server" =>
     {"server_ip" => [\$server_ip, "10.89.1.155"],
     "server_port" => [\$server_port, "10001"],
     "server_passwd" => [\$server_passwd, "tester"],
     "server_timeout" => [\$server_timeout, 10],
-    }
+    "server_domain" => [\$server_domain, "intranet.gonicus.de"],
+    },
     );
 
 
@@ -128,8 +136,12 @@ sub check_cmdline_param () {
     my $err_config;
     my $err_counter = 0;
     if( not defined( $cfg_file)) {
-        $err_config = "please specify a config file";
-        $err_counter += 1;
+        #$err_config = "please specify a config file";
+        #$err_counter += 1;
+        my $cwd = getcwd;
+        my $name = "gosa-sc.cfg";
+        $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 );
@@ -205,12 +217,52 @@ usage: $0 [-hvf] [-c config]
 
     -h        : this (help) message
     -c <file> : config file
+    -f        : foreground, process will not be forked to background
     -v        : be verbose (multiple to increase verbosity)
 EOF
         }
         print "\n" ;
 }
 
+#===  FUNCTION  ================================================================
+#         NAME:  get_server_addresses
+#   PARAMETERS:  
+#      RETURNS:  
+#  DESCRIPTION:  
+#===============================================================================
+sub get_server_addresses {
+    my $domain= shift;
+    my @result;
+    my $dig_cmd= 'dig +nocomments srv _gosad._tcp.'.$domain;
+
+    my $output= `$dig_cmd 2>&1`;
+    open (PIPE, "$dig_cmd 2>&1 |");
+    while(<PIPE>) {
+        chomp $_;
+        # If it's not a comment
+        if($_ =~ m/^[^;]/) {
+            my @matches= split /\s+/;
+
+            # Push hostname with port
+            if($matches[3] eq 'SRV') {
+                push @result, $matches[7].':'.$matches[6];
+            } elsif ($matches[3] eq 'A') {
+                my $i=0;
+
+                # Substitute the hostname with the ip address of the matching A record
+                foreach my $host (@result) {
+                    if ((split /\:/, $host)[0] eq $matches[0]) {
+                        $result[$i]= $matches[4].':'.(split /\:/, $host)[1];
+                    }
+                    $i++;
+                }
+            }
+        }
+    }
+    close(PIPE);
+    return @result;
+}
+
 
 #===  FUNCTION  ================================================================
 #         NAME:  register_at_server
@@ -225,44 +277,53 @@ sub register_at_server {
     my $new_server_passwd = &create_passwd();
     my $new_server_cipher;
 
+    # detect all client accepted events
+    opendir(DIR, "/etc/gosac/events") 
+        or daemon_log("cannot find directory /etc/gosac/events!\ngosac starts without any accepting events!", 1);
+    my $file_name;
+    my @events = ();
+    while(defined($file_name = readdir(DIR))){
+        if ($file_name eq "." || $file_name eq "..") {
+            next;
+        }
+        push(@events, $file_name);
+    }
+    my $events = join(",", @events);
+    #print "debug: events: $events\n";
+
+
     # fill in all possible servers
-    my @servers = ($server_address);
+    my @servers;
+    if (defined $server_domain) {
+        my @tmp_servers = &get_server_addresses($server_domain);
+        foreach my $server (@tmp_servers) { unshift(@servers, $server); }
+    }
+    # add server address from config file at first position of server list
+    if (defined $server_address) {
+        unshift(@servers, $server_address);
+    }
+    daemon_log("found servers in configuration file and via DNS:", 5);
+    foreach my $server (@servers) {
+        daemon_log("\t$server", 5);
+    }
 
     my ($rout, $wout, $reg_server);
     foreach my $server (@servers) {
-        #   sende xml anfrage
-        my $msg_hash = &create_xml_hash("here_i_am", $my_address, $server_address);
-        &add_content2xml_hash($msg_hash, "new_passwd", $new_server_passwd);
-
-        # fetch header for logging
-        my $header = &get_content_from_xml_hash($msg_hash, "header");
-        # generiere xml string
-        my $msg_xml = &create_xml_string($msg_hash);
-        # erzeuge ein ciphering object
-        $server_cipher = &create_ciphering($server_passwd);
-
-        # encrypt xml msg
-        my $crypted_msg = &encrypt_msg($msg_xml, $server_cipher);
-        # öffne socket
-        my $socket = &open_socket($server);
-        if(not defined $socket){
-            print "cannot send '$header'-msg to $server , server not reachable\n";
-            last;
-        }
-        # versende xml msg
-        print $socket $crypted_msg."\n";
-        # schließe socket
-        close $socket;
-
-        daemon_log("send '$header'-msg to $server", 5);
-        daemon_log("crypted_msg:\n\t$crypted_msg", 7);
-
+        # create msg hash
+        my $register_hash = &create_xml_hash("here_i_am", $client_address, $server);
+        &add_content2xml_hash($register_hash, "new_passwd", $new_server_passwd);
+        &add_content2xml_hash($register_hash, "mac_address", $mac_address);
+        &add_content2xml_hash($register_hash, "events", $events);
+
+        # send xml hash to server with general server passwd
+        my $answer = &send_msg_hash2address($register_hash, $server, $server_passwd);
+        
+        # sending fails, no sens to wait for response
+        if ($answer ne "done") { next; }
+    
         # waiting for response
-        daemon_log("waiting for response...", 5);
+        daemon_log("waiting for response...\n", 5);
         my $nf = select($rout=$rbits, $wout=$wbits, undef, $server_timeout);
-        # error handling
-        if($nf < 0 ) {
-        }
 
         # something is coming in
         if(vec $rout, fileno $input_socket, 1) {
@@ -287,6 +348,7 @@ sub register_at_server {
             
             # validate acknowledge msg from server
             $new_server_cipher = &create_ciphering($new_server_passwd);
+            my $msg_hash;
             eval {
                 my $decrypted_msg = &decrypt_msg($crypted_msg, $new_server_cipher);
                 $msg_hash = $xml->XMLin($decrypted_msg, ForceArray=>1);
@@ -295,10 +357,15 @@ sub register_at_server {
                 daemon_log("cannot register at $server", 1);
                 daemon_log("ERROR: do not understand the message:\n\t$crypted_msg" , 5);   
             } else {
+                print "debug: register_at_server: incoming msg konnte geparst werden\n";
                 my $header = &get_content_from_xml_hash($msg_hash, "header");
+                print "debug: header: $header\n";
                 if($header eq "registered") {
                     $reg_server = $server;
                     last;
+                } elsif($header eq "denied") {
+                    my $reason = (&get_content_from_xml_hash($msg_hash, "denied"))[0];
+                    daemon_log("registration at $server denied: $reason", 1);
                 } else {
                     daemon_log("cannot register at $server", 1);
                 }
@@ -317,6 +384,7 @@ sub register_at_server {
     }
 
     # update the global available variables
+    $server_address = $reg_server;
     $server_passwd = $new_server_passwd;
     $server_cipher = $new_server_cipher;
     return;
@@ -330,12 +398,12 @@ sub register_at_server {
 #  DESCRIPTION:
 #===============================================================================
 sub create_xml_hash {
-    my ($header, $source, $target) = @_;
+    my ($header, $source, $target, $header_value) = @_;
     my $hash = {
             header => [$header],
             source => [$source],
             target => [$target],
-            $header => [],
+            $header => [$header_value],
     };
     daemon_log("create_xml_hash:", 7),
     chomp(my $tmp = Dumper $hash);
@@ -353,7 +421,7 @@ sub create_xml_hash {
 sub create_xml_string {
     my ($xml_hash) = @_ ;
     my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml');
-    $xml_string =~ s/[\s]+//g;
+    $xml_string =~ s/[\n]+//g;
     daemon_log("create_xml_string:\n\t$xml_string\n", 7);
     return $xml_string;
 }
@@ -378,19 +446,37 @@ sub add_content2xml_hash {
 
 #===  FUNCTION  ================================================================
 #         NAME:  get_content_from_xml_hash
-#   PARAMETERS:  
-#      RETURNS:
-#  DESCRIPTION:
+#   PARAMETERS:  ref : reference to the xml hash
+#                string: key of the value you want
+#      RETURNS:  STRING AND ARRAY
+#  DESCRIPTION:  if key of the hash is either 'header', 'target' or 'source' the 
+#                function returns a string cause it is expected that these keys
+#                do just have one value, all other keys returns an array!!!
 #===============================================================================
 sub get_content_from_xml_hash {
     my ($xml_ref, $element) = @_;
     my $result = $xml_ref->{$element};
-    if( @$result == 1) {
-        $result = @$result[0];
+    if( $element eq "header" || $element eq "target" || $element eq "source") {
+        return @$result[0];
     }
-    return $result;
+    return @$result;
 }
 
+#    my ($xml_ref, $element) = @_;
+#    if (exists $xml_ref->{$element}) {
+#        my $result = $xml_ref->{$element};
+#        if( $element eq "header" || $element eq "target" || $element eq "source") {
+#            return @$result[0];
+#        } else {
+#            return @$result;
+#        }
+#        
+#    } else {
+#        my $result = ();
+#        return @$result;
+#    }
+#}
+
 
 #===  FUNCTION  ================================================================
 #         NAME:  encrypt_msg
@@ -401,7 +487,7 @@ sub get_content_from_xml_hash {
 sub encrypt_msg {
     my ($msg, $my_cipher) = @_;
     if(not defined $my_cipher) { print "no cipher object\n"; }
-    $msg =~ s/[\s]+//g;
+    $msg =~ s/[\n]+//g;
     my $msg_length = length($msg);
     my $multiplier = int($msg_length / 16) + 1;
     my $extension = 16*$multiplier - $msg_length;
@@ -470,33 +556,50 @@ sub create_passwd {
 #  DESCRIPTION:  ????
 #===============================================================================
 sub send_msg_hash2address {
-    my ($msg_hash, $address) = @_ ;
+    my ($msg_hash, $address, $passwd) = @_ ;
 
     # fetch header for logging
     my $header = &get_content_from_xml_hash($msg_hash, "header");
+
     # generiere xml string
     my $msg_xml = &create_xml_string($msg_hash);
+
     # hole das entsprechende passwd aus dem hash
-    my $passwd = $known_hosts->{$address}->{passwd};
+    if(not defined $passwd) {
+        if(exists $known_hosts->{$address}) {
+            $passwd = $known_hosts->{$address}->{passwd};
+        } elsif ($address eq $server_address) {
+            $passwd = $server_passwd;
+        } else {
+            daemon_log("$address not known, neither as server nor as client", 1);
+            return "failed";
+        }
+    }
+
     # erzeuge ein ciphering object
     my $act_cipher = &create_ciphering($passwd);
+
     # encrypt xml msg
     my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher);
+
     # öffne socket
     my $socket = &open_socket($address);
     if(not defined $socket){
-        print "cannot send '$header'-msg to $address , server not reachable\n";
-        return;
+        daemon_log("cannot open socket to $address, server not reachable", 1);
+        daemon_log("cannot send '$header'-msg", 1);
+        return "failed";
     }
+
     # versende xml msg
     print $socket $crypted_msg."\n";
+
     # schließe socket
     close $socket;
 
     daemon_log("send '$header'-msg to $address", 5);
     daemon_log("crypted_msg:\n\t$crypted_msg", 7);
 
-    return
+    return "done";
 }
 
 
@@ -557,7 +660,7 @@ sub read_from_socket {
 sub print_known_hosts_hash {
     my ($tmp) = @_;
     print "####################################\n";
-    print "# status of $known_hosts\n";
+    print "# status of known_hosts\n";
     my $hosts;
     my $host_hash;
     my @hosts = keys %$known_hosts;
@@ -575,7 +678,12 @@ sub print_known_hosts_hash {
     return;
 }
 
-
+#===  FUNCTION  ================================================================
+#         NAME:  
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
 sub create_known_hosts_entry {
     my ($hostname) = @_;
     $known_hosts->{$hostname} = {};
@@ -585,18 +693,25 @@ sub create_known_hosts_entry {
     return;  
 }
 
+
+#===  FUNCTION  ================================================================
+#         NAME:  
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
 sub update_known_hosts_entry {
     my ($hostname, $status, $passwd, $timestamp) = @_;
-    my ($Sekunden, $Minuten, $Stunden, $Monatstag, $Monat,
-    $Jahr, $Wochentag, $Jahrestag, $Sommerzeit) = localtime(time);
-    $Stunden = $Stunden < 10 ? $Stunden = "0".$Stunden : $Stunden;
-    $Minuten = $Minuten < 10 ? $Minuten = "0".$Minuten : $Minuten;
-    $Sekunden = $Sekunden < 10 ? $Sekunden = "0".$Sekunden : $Sekunden;
-    $Monat+=1;
-    $Monat = $Monat < 10 ? $Monat = "0".$Monat : $Monat;
-    $Monatstag = $Monatstag < 10 ? $Monatstag = "0".$Monatstag : $Monatstag;
-    $Jahr+=1900;
-    my $t = "$Jahr$Monat$Monatstag$Stunden$Minuten$Sekunden";
+    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";
 
     if($status) {
         $known_hosts->{$hostname}->{status} = $status;
@@ -612,6 +727,208 @@ sub update_known_hosts_entry {
 }
 
 
+#===  FUNCTION  ================================================================
+#         NAME:  
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
+sub add_content2known_hosts {
+    my ($hostname, $element, $content) = @_;
+    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";
+    
+    $known_hosts->{$hostname}->{$element} = $content;
+    $known_hosts->{$hostname}->{timestamp} = $t;
+    return;
+}
+
+
+#===  FUNCTION  ================================================================
+#         NAME:  
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
+sub process_incoming_msg {
+    my ($crypted_msg) = @_;
+    if(not defined $crypted_msg) {
+        daemon_log("function 'process_incoming_msg': got no msg", 7);
+    }
+    $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:", 1);
+    daemon_log("\t$host", 1);
+    daemon_log("crypted msg:", 7);
+    daemon_log("\t$crypted_msg", 7);
+
+    # try to decrypt incoming msg
+    my ($msg, $msg_hash);
+    eval{
+        $msg = &decrypt_msg($crypted_msg, $server_cipher);
+        $msg_hash = $xml->XMLin($msg, ForceArray=>1);
+    };
+    if($@) {
+        daemon_log("ERROR: incoming msg cannot be decrypted with server passwd", 1);
+        return;
+    } 
+
+    my $header = &get_content_from_xml_hash($msg_hash, "header");
+    
+    daemon_log("header from msg:", 1);
+    daemon_log("\t$header", 1);
+    daemon_log("msg to process:", 7);
+    daemon_log("\t$msg", 7);
+
+    if ($header eq 'new_ldap_config') { &new_ldap_config($msg_hash)}
+    elsif ($header eq 'ping') { &got_ping($msg_hash) }
+    elsif ($header eq 'wake_up') { &execute_event($msg_hash)}
+    elsif ($header eq 'new_passwd') { &new_passwd()}
+    else { daemon_log("ERROR: no function assigned to msg $header", 5) }
+
+    return;
+}
+
+
+#===  FUNCTION  ================================================================
+#         NAME:  
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
+sub update_status { 
+    my ($new_status) = @_ ;
+    #print "debug: update_status: client_address: $client_address\n";
+    #print "debug: update_status: server_address: $server_address\n";
+    my $out_hash = &create_xml_hash("update_status", $client_address, $server_address);      
+    &add_content2xml_hash($out_hash, "update_status", $new_status);
+    &send_msg_hash2address($out_hash, $server_address);
+    return;
+}
+
+
+#===  FUNCTION  ================================================================
+#         NAME:  
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
+sub server_leaving {
+    my ($msg_hash) = @_ ;
+    my $source = &get_content_from_xml_hash("source");
+    my $header = &get_content_from_xml_hash("header");
+    
+    daemon_log("gosa daemon $source is going down, cause registration procedure", 1);
+    my $server_address = "none";
+    my $server_passwd = "none";
+    my $server_cipher = "none";
+
+    # reinitialization of default values in config file
+    &read_configfile;
+    
+    # registrated at new daemon
+    &register_at_server();
+       
+    return;   
+}
+
+
+sub got_ping {
+    my ($msg_hash) = @_ ;
+
+    my $source = &get_content_from_xml_hash($msg_hash, 'source');
+    my $target = &get_content_from_xml_hash($msg_hash, 'target');
+    my $header = &get_content_from_xml_hash($msg_hash, 'header');    
+    
+    &add_content2known_hosts(hostname=>$target, status=>$header);
+    
+    my $out_hash = &create_xml_hash("got_ping", $target, $source);
+    &send_msg_hash2address($out_hash, $source, $server_passwd);
+
+    return;
+}
+
+
+sub new_ldap_config {
+    my ($msg_hash) = @_ ;
+
+    my @gotoLdapServer = &get_content_from_xml_hash($msg_hash, "new_ldap_config");
+    print Dumper @gotoLdapServer;
+
+
+    return;
+
+}
+
+
+sub execute_event {
+    my ($msg_hash)= @_;
+    my $configdir= '/etc/gosac/events/';
+    my $result;
+
+    my $header = &get_content_from_xml_hash($msg_hash, 'header');
+    my $source = &get_content_from_xml_hash($msg_hash, 'source');
+    my $target = &get_content_from_xml_hash($msg_hash, 'target');
+
+
+    if((not defined $source)
+            && (not defined $target)
+            && (not defined $header)) {
+        daemon_log("ERROR: Entries missing in XML msg for gosa events under /etc/gosac/events");
+    } else {
+        my $parameters="";
+        my @params = &get_content_from_xml_hash($msg_hash, $header);
+        my $params = join(", ", @params);
+        daemon_log("execute_event: got parameters: $params", 5);
+
+        if (@params) {
+            foreach my $param (@params) {
+                my $param_value = (&get_content_from_xml_hash($msg_hash, $param))[0];
+                daemon_log("execute_event: parameter -> value: $param -> $param_value", 7);
+                $parameters.= " ".$param_value;
+            }
+        }
+
+        my $cmd= $configdir.$header."$parameters";
+        daemon_log("execute_event: executing cmd: $cmd", 7);
+        $result= "";
+        open(PIPE, "$cmd 2>&1 |");
+        while(<PIPE>) {
+            $result.=$_;
+        }
+        close(PIPE);
+    }
+
+    # process the event result
+
+
+    return;
+}
+
+
+sub new_passwd {
+    # my ($msg_hash) = @_ ;
+    my $new_server_passwd = &create_passwd();
+    my $new_server_cipher = &create_ciphering($new_server_passwd);
+
+    my $out_hash = &create_xml_hash("new_passwd", $client_address, $server_address, $new_server_passwd);
+    
+    &send_msg_hash2address($out_hash, $server_address, $server_passwd);
+
+    $server_passwd = $new_server_passwd;
+    $server_cipher = $new_server_cipher;
+    return; 
+}
+
 
 
 
@@ -626,8 +943,8 @@ GetOptions("h|help" => \&usage,
            );
 
 #  read and set config parameters
-&read_configfile;
 &check_cmdline_param ;
+&read_configfile;
 &check_pid;
 
 # restart daemon log file
@@ -647,23 +964,25 @@ if( 0 != $pid ) {
 }
 
 # prepare variables
-$my_address = $my_ip.":".$my_port;
-$server_address = $server_ip.":".$server_port;
+if (defined $server_ip && defined $server_port) {
+    $server_address = $server_ip.":".$server_port;
+}
+$client_address = $client_ip.":".$client_port;
 
 # setup xml parser
 $xml = new XML::Simple();
 
 # create input socket
 $rbits = $wbits = $ebits = "";
-$input_socket = IO::Socket::INET->new(LocalPort => $my_port,
+$input_socket = IO::Socket::INET->new(LocalPort => $client_port,
         Type => SOCK_STREAM,
         Reuse => 1,
         Listen => 20,
         ); 
 if(not defined $input_socket){
-    daemon_log("cannot be a tcp server at $my_port : $@\n");
+    daemon_log("cannot be a tcp server at $client_port : $@\n");
 } else {
-    daemon_log("start server:\n\t$server_ip:$my_port",1) ;
+    daemon_log("start server:\n\t$server_ip:$client_port",1) ;
     vec($rbits, fileno $input_socket, 1) = 1;
     vec($wbits, fileno $input_socket, 1) = 1;
 }
@@ -672,6 +991,12 @@ if(not defined $input_socket){
 &register_at_server();
 
 
+##############
+# Debugging
+#############
+#sleep(2);
+#&update_status("ich_bin_ein_neuer_status");
+
 ###################################
 #everything ready, okay, lets start
 ###################################
@@ -685,9 +1010,24 @@ while(1) {
 
     # something is coming in
     if(vec $rout, fileno $input_socket, 1) {
-        print "debug: es ist was rein gekommen\n";
-    }
+        my $client = $input_socket->accept();
+        my $other_end = getpeername($client);
+        
+        if(not defined $other_end) {
+            daemon_log("client cannot be identified: $!");
+        } else {
+            my ($port, $iaddr) = unpack_sockaddr_in($other_end);
+            my $actual_ip = inet_ntoa($iaddr);
+            daemon_log("accept client from $actual_ip", 5);
+            my $in_msg = &read_from_socket($client);
+            if(defined $in_msg){
+                chomp($in_msg);
+                $in_msg = $in_msg.".".$actual_ip;
+                &process_incoming_msg($in_msg);
 
+            }
+        }
+    }
 }
  
 
index 66f4cee2c1e6f56046fa3ff4911f66a47c464510..c243dc8a5164d5c88a6c43ca6751ccbfcbcc954d 100644 (file)
@@ -2,8 +2,14 @@
 log_file = /var/log/gosa-sc.log
 pid_file = /var/run/gosa-sc.pid
 
+[client]
+client_ip = 10.89.1.155
+client_port = 10010
+mac_address = 00:1B:77:04:8A:6C
+
 [server]
 server_ip = 10.89.1.155
 server_port = 10001
 server_passwd = tester
-
+server_timeout = 5
+server_domain = intranet.gonicus.de
index 0e91af98adb7acac2381837ac58e88830c9dd851..c5a6575e070e4b8866f5977b3334419bf3b593a9 100755 (executable)
@@ -22,7 +22,8 @@
 # TODO 2007-11-12: nachrichten senden an buss kann so nicht funktionieren, kind setzt $msg_to_bus, der elter testet aber, ob in $msg_to_bus was enthalten ist um es dorthin zu senden, so kann das nicht gehen, alternativ müsste das kind dem elter über die pipe die msg schicken und der elter müsste dann die variabel $msg_to_bus setzten, dann würde es so gehen
 # wird als zu aufwändig vorerst verworfen, es wäre nötig global ein dic/2 arrays bereitzustellen, maximal child_max groß in dem dann die erzeugten pipe-enden beim forken zugewiesen werden. die namen müssten aber vorher festgelegt sein, damit der elter die bereits existierenden und die noch nicht oder wieder nicht existierenden pipes checken kann ob dort was anliegt. kurzum, das pipe-handling wäre sehr aufwändig zu programmieren, wenn also kein zeitlicher bedarf besteht, dann eher hinten anstellen.
 
-# TODO 2007-11-19: ich hab zwei hashes, known_hosts und known_clients. 1. known_hosts in known_server umändern, 2. lösung suchen für print known_hosts_hash usw. ich kann zwar den hash als parameter übergeben, aber nicht nicht zb. die shm variablen zum sperren des shm, evtl. anstatt hash nur einen key übergeben, bei dem dann hash und shm variablen abgelegt sind, allerdings müsste dieser hash dann auch wieder von überall aus erreichbar sein, evtl. zuviel speicher overhead, alternative bedeutet nur mehr tipparbeit
+# TODO 2007-11-19: ich hab zwei hashes, known_daemons und known_clients. 1. known_daemons in known_server umändern, 2. lösung suchen für print known_daemons_hash usw. ich kann zwar den hash als parameter übergeben, aber nicht nicht zb. die shm variablen zum sperren des shm, evtl. anstatt hash nur einen key übergeben, bei dem dann hash und shm variablen abgelegt sind, allerdings müsste dieser hash dann auch wieder von überall aus erreichbar sein, evtl. zuviel speicher overhead, alternative bedeutet nur mehr tipparbeit
+
 
 use strict;
 use warnings;
@@ -37,26 +38,42 @@ use Crypt::Rijndael;
 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, %cfg_defaults, $foreground, $verbose);
+my ($cfg_file, %cfg_defaults, $foreground, $verbose, $ping_timeout);
 my ($bus_activ, $bus_passwd, $bus_ip, $bus_port, $bus, $bus_address, $msg_to_bus, $bus_cipher);
-my ($server_address, $server_activ, $server_port, $server, $server_ip, $server_passwd);
-my ($known_hosts, $shmkh, $known_clients, $shmcl);
-my ($clientmax);
+my ($server_address, $server_activ, $server_port, $server, $server_ip, $server_passwd, $server_mac, $server_events);
+my ($known_daemons, $shmda, $known_clients, $shmcl);
+my ($max_clients);
 my ($pid_file, $procid, $pid, $log_file);
 my (%free_child, %busy_child, $child_max, $child_min, %child_alive_time, $child_timeout);
 my ($xml);
 my ($arp_activ, $arp_fifo, $arp_fifo_path);
 
+# specifies the verbosity of the daemon_log
 $verbose = 0 ;
+
+# if foreground is not null, script will be not forked to background
 $foreground = 0 ;
-$known_hosts = {};
-$shmkh = tie($known_hosts, 'IPC::Shareable', undef, {create => 1, 
+
+# specifies the timeout seconds while checking the online status of a registrating client
+$ping_timeout = 5;
+
+# specifies the listening port while checking the online status of a registrating client
+# this port HAS to be different to server_port!
+my $ping_port = "12345";
+
+# holds all other gosa-sd as well as the gosa-sd-bus
+$known_daemons = {};
+$shmda = tie($known_daemons, 'IPC::Shareable', undef, {create => 1, 
                                                             exclusive => 1, 
                                                             mode => 0666, 
                                                             destroy => 1,
                                                             });
+# holds all registrated clients
 $known_clients = {};
 $shmcl = tie($known_clients, 'IPC::Shareable', undef, {create => 1, 
                                                             exclusive => 1, 
@@ -84,6 +101,7 @@ $shmcl = tie($known_clients, 'IPC::Shareable', undef, {create => 1,
     "server_ip" => [\$server_ip, ""],
     "server_port" => [\$server_port, ""],
     "server_passwd" => [\$server_passwd, ""],
+    "max_clients" => [\$max_clients, 100],
     },
 
 "arp" =>
@@ -162,7 +180,7 @@ sub daemon_log {
             return }
             chomp($msg);
             if($level <= $verbose){
-                print LOG_HANDLE $msg."\n";
+                print LOG_HANDLE "$level $msg\n";
                 if(defined $foreground) { print $msg."\n" }
             }
     }
@@ -189,8 +207,12 @@ sub check_cmdline_param () {
     my $err_config;
     my $err_counter = 0;
     if( not defined( $cfg_file)) {
-        $err_config = "please specify a config file";
-        $err_counter += 1;
+        #$err_config = "please specify a config file";
+        #$err_counter += 1;
+        my $cwd = getcwd;
+        my $name = "gosa-sd.cfg";
+        $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 );
@@ -260,12 +282,12 @@ sub sig_int_handler {
     my ($signal) = @_;
     if($server){
         close($server);
-        daemon_log("child closed\n", 1);
+        daemon_log("child closed", 1);
     }
     if( -p $arp_fifo_path ) {
         close $arp_fifo  ;
         unlink($arp_fifo_path) ;
-        daemon_log("FIFO closed\n", 1) ;
+        daemon_log("FIFO closed", 1) ;
     }
 
     print "$signal\n";
@@ -288,7 +310,7 @@ sub activating_child {
 
     daemon_log("activating: childpid:$$child{'pid'}", 5);
 
-    my $msg2write = $msg.".".$host."\n";
+    #my $msg2write = $msg.".".$host."\n";
 
     print $pipe_wr $msg.".".$host."\n";
     return;
@@ -331,7 +353,7 @@ sub get_processing_child {
             delete $free_child{$key};
             print "prozess:$key wurde aus free_child entfernt\n";
         }
-        daemon_log( "free child:$key\n", 5);
+        daemon_log("free child:$key", 5);
     }
     # teste @free_child und @busy_child
     my $free_len = scalar(keys(%free_child));
@@ -402,7 +424,7 @@ sub get_processing_child {
                     }
                     &process_incoming_msg($msg);
                     daemon_log("processing of msg finished", 5);
-                    daemon_log(" \n", 5);
+                    daemon_log(" ", 5);
                     print $PARENT_wr "done"."\n";
                     redo;
                 }
@@ -446,12 +468,14 @@ sub process_incoming_msg {
     $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);
-
+    daemon_log("msg from host:", 1);
+    daemon_log("\t$host", 1);
+    daemon_log("crypted msg:", 7);
+    daemon_log("\t$crypted_msg", 7);
 
+    # collect addresses from possible incoming clients
     my @valid_keys;
-    my @host_keys = keys %$known_hosts;
+    my @host_keys = keys %$known_daemons;
     foreach my $host_key (@host_keys) {    
         if($host_key =~ "^$host") {
             push(@valid_keys, $host_key);
@@ -463,22 +487,25 @@ sub process_incoming_msg {
             push(@valid_keys, $client_key);
         }
     }
+    push(@valid_keys, $server_address);
     
     my $l = @valid_keys;
     my ($msg, $msg_hash);
     my $msg_flag = 0;    
 
-    # ermittle alle in frage kommenden known_hosts einträge
+    # determine the correct passwd for deciphering of the incoming msgs
     foreach my $host_key (@valid_keys) {
         eval{
-            daemon_log( "key: $host_key\n", 7);
+            daemon_log( "key: $host_key", 7);
             my $key_passwd;
-            if(exists $known_hosts->{$host_key}) {
-                $key_passwd = $known_hosts->{$host_key}->{passwd};
-            } else {
+            if (exists $known_daemons->{$host_key}) {
+                $key_passwd = $known_daemons->{$host_key}->{passwd};
+            } elsif (exists $known_clients->{$host_key}) {
                 $key_passwd = $known_clients->{$host_key}->{passwd};
-            }
-            daemon_log("key_passwd: $key_passwd\n", 7);
+            } elsif ($host_key eq $server_address) {
+                $key_passwd = $server_passwd;
+            } 
+            daemon_log("key_passwd: $key_passwd", 7);
             my $key_cipher = &create_ciphering($key_passwd);
             $msg = &decrypt_msg($crypted_msg, $key_cipher);
             $msg_hash = $xml->XMLin($msg, ForceArray=>1);
@@ -492,22 +519,92 @@ sub process_incoming_msg {
     } 
     
     if($msg_flag >= $l)  {
-        daemon_log("\nERROR: do not understand the message:\n\t$msg" , 1);
+        daemon_log("ERROR: do not understand the message:", 1);
+        daemon_log("\t$msg", 1);
         return;
     }
 
+    # process incoming msg
     my $header = &get_content_from_xml_hash($msg_hash, "header");
-    
-    daemon_log("header from msg:\n\t$header", 1);
-    daemon_log("msg to process:\n\t$msg", 7);
+    daemon_log("header from msg:", 1);
+    daemon_log("\t$header", 1);
+    daemon_log("msg to process:", 7);
+    daemon_log("\t$msg", 7);
+
+    my @targets = @{$msg_hash->{target}};
+    my $len_targets = @targets;
+    if ($len_targets == 0){     
+        daemon_log("ERROR: no target specified for msg $header", 1);
+
+    } elsif ($len_targets == 1){
+        # we have only one target symbol
+
+        my $target = @targets[0];
+        daemon_log("msg is for:", 7);
+        daemon_log("\t$target", 7);
+
+        if ($target eq $server_address) {
+            # msg is for server
+
+            if ($header eq 'new_passwd'){ &new_passwd($msg_hash)}
+            elsif ($header eq 'here_i_am') { &here_i_am($msg_hash)}
+            elsif ($header eq 'who_has') { &who_has($msg_hash) }
+            elsif ($header eq 'who_has_i_do') { &who_has_i_do($msg_hash)}
+            elsif ($header eq 'update_status') { &update_status($msg_hash) }
+            elsif ($header eq 'got_ping') { &got_ping($msg_hash)}
+            elsif ($header eq 'get_load') { &execute_actions($msg_hash)}
+            else { daemon_log("ERROR: no function assigned to this msg", 5) }
+        } elsif ($target eq "*") {
+            # msg is for all clients
+
+            my $source = @{$msg_hash->{source}}[0];
+            print "debug: process_incoming_msg: source: $source\n";
+            my @target_addresses = keys(%$known_clients);
+            foreach my $target_address (@target_addresses) {
+                if ($target_address eq $source) { next; }
+                $msg_hash->{target} = [$target_address];
+                &send_msg_hash2address($msg_hash, $target_address);
+            }           
+        } else {
+            # msg is for one client
+
+            if (exists $known_clients->{$target}) {
+                # target is known
+
+                &send_msg_hash2address($msg_hash, $target);
+            } else {
+                # target is not known
 
-    if($header eq 'new_passwd'){ &new_passwd($msg_hash)}
-    elsif($header eq 'ping'){ &got_ping($msg_hash)}
-    elsif($header eq 'here_i_am') { &here_i_am($msg_hash)}
+                daemon_log("ERROR: target $target is not known in known_clients", 1);
+            }
+        }
+    } else {
+        # we have multiple target symbols
+
+        my $target_string = join(", ", @targets);
+        daemon_log("msg is for:", 7);
+        daemon_log("\t$target_string", 7);
+        
+        my $target_address;
+        foreach $target_address (@targets) {
+            if (exists $known_clients->{$target_address}) {
+                # target_address is known
+
+                &send_msg_hash2address($msg_hash, $target_address);
+                daemon_log("server forwards msg $header to client $target_address", 3);
+            } else {
+                # target is not known
+
+                daemon_log("ERROR: target $target_address is not known in known_clients", 1);
+            }
+        }
+
+
+    }
 
-    &print_known_hosts_hash();
+    &print_known_daemons_hash();
     &print_known_clients();
-    daemon_log(" \n\n", 1);
+    daemon_log(" ", 1);
     return;
 }
 
@@ -531,10 +628,10 @@ sub open_socket {
             Timeout => 5,
             );
     if(not defined $socket) {
-        #daemon_log("cannot connect to socket at $PeerAddr, $@\n");
         return;
     }
-    daemon_log("open_socket:\n\t$PeerAddr", 7);
+    daemon_log("open_socket:", 7);
+    daemon_log("\t$PeerAddr", 7);
     return $socket;
 }
 
@@ -569,16 +666,16 @@ sub read_from_socket {
 #  DESCRIPTION:
 #===============================================================================
 sub create_xml_hash {
-    my ($header, $source, $target) = @_;
+    my ($header, $source, $target, $header_value) = @_;
     my $hash = {
             header => [$header],
             source => [$source],
             target => [$target],
-            $header => [],
+            $header => [$header_value],
     };
     daemon_log("create_xml_hash:", 7),
     chomp(my $tmp = Dumper $hash);
-    daemon_log("\t$tmp\n", 7);
+    daemon_log("\t$tmp", 7);
     return $hash
 }
 
@@ -592,8 +689,9 @@ sub create_xml_hash {
 sub create_xml_string {
     my ($xml_hash) = @_ ;
     my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml');
-    $xml_string =~ s/[\s]+//g;
-    daemon_log("create_xml_string:\n\t$xml_string\n", 7);
+    $xml_string =~ s/[\n]+//g;
+    daemon_log("create_xml_string:",7);
+    daemon_log("\t$xml_string\n", 7);
     return $xml_string;
 }
 
@@ -624,10 +722,10 @@ sub add_content2xml_hash {
 sub get_content_from_xml_hash {
     my ($xml_ref, $element) = @_;
     my $result = $xml_ref->{$element};
-    if( @$result == 1) {
-        $result = @$result[0];
+    if( $element eq "header" || $element eq "target" || $element eq "source") {
+        return @$result[0];
     }
-    return $result;
+    return @$result;
 }
 
 
@@ -640,7 +738,7 @@ sub get_content_from_xml_hash {
 sub encrypt_msg {
     my ($msg, $my_cipher) = @_;
     if(not defined $my_cipher) { print "no cipher object\n"; }
-    $msg =~ s/[\s]+//g;
+    $msg =~ s/[\n]+//g;
     my $msg_length = length($msg);
     my $multiplier = int($msg_length / 16) + 1;
     my $extension = 16*$multiplier - $msg_length;
@@ -692,39 +790,48 @@ sub create_ciphering {
 #  DESCRIPTION:  ????
 #===============================================================================
 sub send_msg_hash2address {
-    my ($msg_hash, $address) = @_ ;
+    my ($msg_hash, $address, $passwd) = @_ ;
 
-# fetch header for logging
+    # fetch header for logging
     my $header = &get_content_from_xml_hash($msg_hash, "header");
-# generiere xml string
+    
+    # generiere xml string
     my $msg_xml = &create_xml_string($msg_hash);
-# hole das entsprechende passwd aus dem hash
-    my $passwd;
-    if(exists $known_hosts->{$address}) {
-        $passwd = $known_hosts->{$address}->{passwd};
-    } elsif(exists $known_clients->{$address}) {
-        $passwd = $known_clients->{$address}->{passwd};
-    } else {
-        daemon_log("$address not known, neither as server nor as client", 1);
-        return;
+    
+    # hole das entsprechende passwd aus dem hash
+    if(not defined $passwd) {
+        if(exists $known_daemons->{$address}) {
+            $passwd = $known_daemons->{$address}->{passwd};
+        } elsif(exists $known_clients->{$address}) {
+            $passwd = $known_clients->{$address}->{passwd};
+        } else {
+            daemon_log("$address not known, neither as server nor as client", 1);
+            return;
+        }
     }
-# erzeuge ein ciphering object
+    
+    # erzeuge ein ciphering object
     my $act_cipher = &create_ciphering($passwd);
-# encrypt xml msg
+    
+    # encrypt xml msg
     my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher);
-# öffne socket
+    
+    # öffne socket
     my $socket = &open_socket($address);
     if(not defined $socket){
-        daemon_log( "cannot send '$header'-msg to $address , server not reachable\n", 5);
+        daemon_log( "cannot send '$header'-msg to $address , server not reachable", 5);
         return;
     }
-# versende xml msg
+    
+    # versende xml msg
     print $socket $crypted_msg."\n";
-# schließe socket
+    
+    # schließe socket
     close $socket;
 
     daemon_log("send '$header'-msg to $address", 5);
-    daemon_log("crypted_msg:\n\t$crypted_msg", 7);
+    daemon_log("crypted_msg:",7);
+    daemon_log("\t$crypted_msg", 7);
 
     return
 }
@@ -737,19 +844,34 @@ sub send_msg_hash2address {
 #  DESCRIPTION:
 #===============================================================================
 sub send_msg_hash2bus {
-    my($msg_hash) = @_;
+    my($msg_hash, $target) = @_;
 
-# fetch header for logging
+    # fetch header for logging
     my $header = &get_content_from_xml_hash($msg_hash, "header");    
-# generiere xml string
+
+    # generiere xml string
     my $msg_xml = $xml->XMLout($msg_hash, RootName => 'xml');
-# encrypt xml msg 
+
+    # encrypt xml msg 
     my $crypted_msg = &encrypt_msg($msg_xml, $bus_cipher);
-# setze msg_to_bus
-    #$msg_to_bus = $crypted_msg;
+
+    # öffne socket
+    my $socket = &open_socket($bus_address);
+    if(not defined $socket){
+        daemon_log( "cannot send '$header'-msg to $bus_address , bus not reachable", 5);
+        return;
+    }
+    
+    # versende xml msg
+    print $socket $crypted_msg."\n";
+    
+    # schließe socket
+    close $socket;
+   
 
     daemon_log("send '$header'-msg to bus", 1);
-    daemon_log("crypted msg:\n\t$crypted_msg", 7);
+    daemon_log("crypted msg:",7);
+    daemon_log("\t$crypted_msg", 7);
 
     return;
 }
@@ -766,9 +888,9 @@ sub send_msg_hash2bus {
 sub register_at_bus {
     my ($tmp) = @_;
 
-    # create known_hosts entry
-    &create_known_hosts_entry($bus_address);
-    &update_known_hosts_entry($bus_address, "register_at_bus", $bus_passwd);
+    # create known_daemons entry
+    &create_known_daemons_entry($bus_address);
+    &add_content2known_daemons(hostname=>$bus_address, status=>"register_at_bus", passwd=>$bus_passwd);
 
     my $msg_hash = &create_xml_hash("here_i_am", "$server_ip:$server_port", $bus_address);
     &send_msg_hash2address($msg_hash, $bus_address);
@@ -786,13 +908,23 @@ sub new_passwd {
     my ($msg_hash) = @_;
     
     my $source = &get_content_from_xml_hash($msg_hash, "source");
-    my $passwd = &get_content_from_xml_hash($msg_hash, "new_passwd");
+    my $passwd = (&get_content_from_xml_hash($msg_hash, "new_passwd"))[0];
+
+    if (exists $known_daemons->{$source}) {
+        &add_content2known_daemons(hostname=>$source, status=>"new_passwd", passwd=>$passwd);
+        $bus_cipher = &create_ciphering($passwd);
+        my $hash = &create_xml_hash("confirm_new_passwd", "$server_ip:$server_port", "$source");
+        &send_msg_hash2address($hash, $source);
 
-    &update_known_hosts_entry($source, "new_passwd", $passwd);
+    } elsif (exists $known_clients->{$source}) {
+        &add_content2known_clients(hostname=>$source, status=>"new_passwd", passwd=>$passwd);
+        #my $hash = &create_xml_hash("confirm_new_passwd", "$server_ip:$server_port", "$source");
+        #&send_msg_hash2address($hash, $source);
+
+    } else {
+        daemon_log("ERROR: $source not known, neither in known_daemons nor in known_clients", 1)   
+    }
 
-    $bus_cipher = &create_ciphering($passwd);
-    my $hash = &create_xml_hash("confirm_new_passwd", "$server_ip:$server_port", "$source");
-    &send_msg_hash2address($hash, $source);
     return
 }
 
@@ -827,15 +959,12 @@ sub got_ping {
     my $target = &get_content_from_xml_hash($msg_hash, 'target');
     my $header = &get_content_from_xml_hash($msg_hash, 'header');    
     
-    if(exists $known_hosts->{$target}) {
-        &update_known_hosts_entry($target, $header);
+    if(exists $known_daemons->{$source}) {
+        &add_content2known_daemons(hostname=>$source, status=>$header);
     } else {
-       &update_known_clients($target, $header);
+        &add_content2known_clients(hostname=>$source, status=>$header);
     }
     
-    my $out_hash = &create_xml_hash("got_ping", $target, $source);
-    &send_msg_hash2address($out_hash, $source);
-    
     return;
 }
 
@@ -850,45 +979,290 @@ sub here_i_am {
     my ($msg_hash) = @_;
 
     my $source = &get_content_from_xml_hash($msg_hash, "source");
-    my $new_passwd = &get_content_from_xml_hash($msg_hash, "new_passwd");
+    my $mac_address = (&get_content_from_xml_hash($msg_hash, "mac_address"))[0]; 
+    my $out_hash;
+
+    # number of known clients
+    my $nu_clients = keys %$known_clients;
+
+    # check wether client address or mac address is already known
+    if (exists $known_clients->{$source}) {
+        daemon_log("WARNING: $source is already known as a client", 1);
+        daemon_log("WARNING: values for $source are being overwritten", 1);   
+        $nu_clients --;
+    }
+
+    # number of actual activ clients
+    my $act_nu_clients = $nu_clients;
+
+    daemon_log("number of actual activ clients: $act_nu_clients", 5);
+    daemon_log("number of maximal allowed clients: $max_clients", 5);
 
-    # create known_hosts entry
+    if($max_clients <= $act_nu_clients) {
+        my $out_hash = &create_xml_hash("denied", $server_address, $source);
+        &add_content2xml_hash($out_hash, "denied", "I_cannot_take_any_more_clients!");
+        my $passwd = (&get_content_from_xml_hash($msg_hash, "new_passwd"))[0];
+        &send_msg_hash2address($out_hash, $source, $passwd);
+        return;
+    }
+    
+    # new client accepted
+    my $new_passwd = (&get_content_from_xml_hash($msg_hash, "new_passwd"))[0];
+
+    # create known_daemons entry
+    my $events = (&get_content_from_xml_hash($msg_hash, "events"))[0];
     &create_known_client($source);
-    &update_known_clients($source, "registered", $new_passwd);
+    &add_content2known_clients(hostname=>$source, events=>$events, mac_address=>$mac_address, 
+                                status=>"registered", passwd=>$new_passwd);
 
     # return acknowledgement to client
-    my $out_hash = &create_xml_hash("registered", $server_address, $source);
+    $out_hash = &create_xml_hash("registered", $server_address, $source);
     &send_msg_hash2address($out_hash, $source);
 
+    # notify registered client to bus
+    $out_hash = &create_xml_hash("new_client", $server_address, $bus_address, $source);
+    &send_msg_hash2bus($out_hash);
+
+    # give the new client his ldap config
+    &new_ldap_config($source);
+
+    return;
+}
+
+
+#===  FUNCTION  ================================================================
+#         NAME:  who_has
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
+sub who_has {
+    my ($msg_hash) = @_ ;
+    
+    # what is your search pattern
+    my $search_pattern = (&get_content_from_xml_hash($msg_hash, "who_has"))[0];
+    my $search_element = (&get_content_from_xml_hash($msg_hash, $search_pattern))[0];
+    daemon_log("who_has-msg looking for $search_pattern $search_element", 7);
+
+    # scanning known_clients for search_pattern
+    my @host_addresses = keys %$known_clients;
+    my $known_clients_entries = length @host_addresses;
+    print "debug: who_has: $known_clients_entries entries in known_clients\n";
+    my $host_address;
+    foreach my $host (@host_addresses) {
+        #print "debug: who_has: $host_address\n";
+        my $client_element = $known_clients->{$host}->{$search_pattern};
+        print "debug: who_has: host $host with pattern $search_pattern and value $client_element\n";   
+        if ($search_element eq $client_element) {
+            $host_address = $host;
+            last;
+        }
+    }
+        
+    # search was successful
+    if (defined $host_address) {
+        print "debug: who_has: result: host $host_address has $search_pattern $search_element\n";
+        my $source = @{$msg_hash->{source}}[0];
+        my $out_msg = &create_xml_hash("who_has_i_do", $server_address, $source, "mac_address");
+        &add_content2xml_hash($out_msg, "mac_address", $search_element);
+        &send_msg_hash2address($out_msg, $bus_address);
+    }
+    return;
+}
+
+
+sub who_has_i_do {
+    my ($msg_hash) = @_ ;
+    my $header = &get_content_from_xml_hash($msg_hash, "header");
+    my $source = &get_content_from_xml_hash($msg_hash, "source");
+    my $search_param = (&get_content_from_xml_hash($msg_hash, $header))[0];
+    my $search_value = (&get_content_from_xml_hash($msg_hash, $search_param))[0];
+    print "\ngot msg $header:\nserver $source has client with $search_param $search_value\n";
+}
+
+
+#===  FUNCTION  ================================================================
+#         NAME:  update_status
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
+sub update_status {
+    my ($msg_hash) = @_;
+    my $header = &get_content_from_xml_hash($msg_hash, "header");
+    my $source = &get_content_from_xml_hash($msg_hash, "source");
+    my $new_status = (&get_content_from_xml_hash($msg_hash, "update_status"))[0];
+    
+    
+    # find the source
+    my $act_known_hash;
+    if (exists $known_daemons->{$source}) {
+        &add_content2known_daemons(hostname=>$source, status=>$new_status);
+    } elsif (exists $known_clients->{$source}) {
+        &add_content2known_clients(hostname=>$source, status=>$new_status);
+    } else {
+        daemon_log("ERROR: got $header-msg, but cannot find $source in my hashes, unable to update status", 1);
+        return;
+    }
+
+    
+}
+
+
+#===  FUNCTION  ================================================================
+#         NAME:  new_ldap_config
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
+sub new_ldap_config {
+    my ($address) = @_ ;
+    
+    if (not exists $known_clients->{$address}) {
+        daemon_log("ERROR: $address does not exist in known_clients, cannot send him his ldap config", 1);
+        return;
+    }
+    
+    my $mac_address = $known_clients->{$address}->{"mac_address"};
+    if (not defined $mac_address) {
+        daemon_log("ERROR: no mac address found for client $address", 1);
+        return;
+    }
+
+    # fetch dn
+    my $goHard_cmd = "ldapsearch -x '(&(objectClass=goHard)(macAddress=00:11:22:33:44:57))' dn gotoLdapServer";
+    #my $output= `$goHard_cmd 2>&1`;
+    my $dn;
+    my @gotoLdapServer;
+    open (PIPE, "$goHard_cmd 2>&1 |");
+    while(<PIPE>) {
+        chomp $_;
+        # If it's a comment, goto next
+        if ($_ =~ m/^[#]/) { next;}
+        if ($_ =~ m/^dn: ([\S]+?)$/) {
+            $dn = $1;
+        } elsif ($_ =~ m/^gotoLdapServer: ([\S]+?)$/) {
+            push(@gotoLdapServer, $1);
+        }
+    }
+    close(PIPE);
+    
+    # no dn found
+    if (not defined $dn) {
+        daemon_log("ERROR: no dn arose from command: $goHard_cmd", 1);
+        return;
+    }
+    
+    # no gotoLdapServer found
+    my $gosaGroupOfNames_cmd = "ldapsearch -x '(&(objectClass=gosaGroupOfNames)(member=$dn))' gotoLdapServer";
+    if (@gotoLdapServer == 0) {
+        #print "debug: new_ldap_config: gotoLdapServer ist leer\n";
+        open (PIPE, "$gosaGroupOfNames_cmd 2>&1 |");
+        while(<PIPE>) {
+            chomp $_;
+            if ($_ =~ m/^[#]/) { next; }
+            if ($_ =~ m/^gotoLdapServer: ([\S]+?)$/) {
+                push(@gotoLdapServer, $1);
+            }
+        }
+        close(PIPE);
+    }
+
+    # still no gotoLdapServer found
+    if (@gotoLdapServer == 0) {
+        daemon_log("ERROR: cannot find gotoLdapServer entry in command: $gosaGroupOfNames_cmd", 1);
+        return;
+    }
+
+    # sort @gotoLdapServer and then split of ranking
+    my @sorted_gotoLdapServer = sort(@gotoLdapServer);
+    @gotoLdapServer = reverse(@sorted_gotoLdapServer);
+    foreach (@gotoLdapServer) {
+        $_ =~ s/^\d://;
+    }
+
+    #print "debug: new_ladp_config: dn: $dn\n";
+    my $t = join(" ", @gotoLdapServer);
+    #print "debug: new_ldap_config: gotoLdapServer: $t\n";
+    my $out_hash = &create_xml_hash("new_ldap_config", $server_address, $address);
+    map(&add_content2xml_hash($out_hash, "new_ldap_config", $_), @gotoLdapServer);
+    &send_msg_hash2address($out_hash, $address);
+
+    return;
+}
+
+
+sub execute_actions {
+    my ($msg_hash) = @_ ;
+    my $configdir= '/etc/gosad/actions/';
+    my $result;
+
+    my $header = &get_content_from_xml_hash($msg_hash, 'header');
+    my $source = &get_content_from_xml_hash($msg_hash, 'source');
+    my $target = &get_content_from_xml_hash($msg_hash, 'target');
+
+
+    if((not defined $source)
+            && (not defined $target)
+            && (not defined $header)) {
+        daemon_log("ERROR: Entries missing in XML msg for gosad actions under /etc/gosad/actions");
+    } else {
+        my $parameters="";
+        my @params = &get_content_from_xml_hash($msg_hash, $header);
+        my $params = join(", ", @params);
+        daemon_log("execute_actions: got parameters: $params", 5);
+
+        if (@params) {
+            foreach my $param (@params) {
+                my $param_value = (&get_content_from_xml_hash($msg_hash, $param))[0];
+                daemon_log("execute_actions: parameter -> value: $param -> $param_value", 7);
+                $parameters.= " ".$param_value;
+            }
+        }
+
+        my $cmd= $configdir.$header."$parameters";
+        daemon_log("execute_actions: executing cmd: $cmd", 7);
+        $result= "";
+        open(PIPE, "$cmd 2>&1 |");
+        while(<PIPE>) {
+            $result.=$_;
+        }
+        close(PIPE);
+    }
+
+    # process the event result
+    print "debug: execute_actions: $header: $result\n";
+
     return;
 }
 
 
 #===  FUNCTION  ================================================================
-#         NAME:  print_known_hosts_hash
+#         NAME:  print_known_daemons_hash
 #   PARAMETERS:
 #      RETURNS: 
 #  DESCRIPTION: 
 #===============================================================================
-sub print_known_hosts_hash {
+sub print_known_daemons_hash {
     my ($hash) = @_;
     print "####################################\n";
-    print "# status of known_hosts\n";
+    print "# status of known_daemons\n";
     my $hosts;
     my $host_hash;
-    $shmkh->shlock(LOCK_EX);
-    my @hosts = keys %$known_hosts;
+    $shmda->shlock(LOCK_EX);
+    my @hosts = keys %$known_daemons;
     foreach my $host (@hosts) {
-        #my @elements = keys %$known_hosts->{$host};
-        my $status = $known_hosts->{$host}->{status} ;
-        my $passwd = $known_hosts->{$host}->{passwd};
-        my $timestamp = $known_hosts->{$host}->{timestamp};
+        #my @elements = keys %$known_daemons->{$host};
+        my $status = $known_daemons->{$host}->{status} ;
+        my $passwd = $known_daemons->{$host}->{passwd};
+        my $timestamp = $known_daemons->{$host}->{timestamp};
         print "$host\n";
         print "\t$status\n";
         print "\t$passwd\n";
         print "\t$timestamp\n";
     }
-    $shmkh->shunlock(LOCK_EX);
+    $shmda->shunlock(LOCK_EX);
     print "####################################\n";
     return;
 }
@@ -908,15 +1282,20 @@ sub print_known_clients {
     my $host_hash;
     $shmcl->shlock(LOCK_EX);
     my @hosts = keys %$known_clients;
-    foreach my $host (@hosts) {
-        #my @elements = keys %$known_hosts->{$host};
-        my $status = $known_clients->{$host}->{status} ;
-        my $passwd = $known_clients->{$host}->{passwd};
-        my $timestamp = $known_clients->{$host}->{timestamp};
-        print "$host\n";
-        print "\t$status\n";
-        print "\t$passwd\n";
-        print "\t$timestamp\n";
+    if (@hosts) {
+        foreach my $host (@hosts) {
+            my $status = $known_clients->{$host}->{status} ;
+            my $passwd = $known_clients->{$host}->{passwd};
+            my $timestamp = $known_clients->{$host}->{timestamp};
+            my $mac_address = $known_clients->{$host}->{mac_address};
+            my $events = $known_clients->{$host}->{events};
+            print "$host\n";
+            print "\tstatus:      $status\n";
+            print "\tpasswd:      $passwd\n";
+            print "\ttime:        $timestamp\n";
+            print "\tmac_address: $mac_address\n";
+            print "\tevents:      $events\n";
+        }
     }
     $shmcl->shunlock(LOCK_EX);
     print "####################################\n";
@@ -924,18 +1303,30 @@ sub print_known_clients {
 }
 
 
-sub create_known_hosts_entry {
+#===  FUNCTION  ================================================================
+#         NAME:  create_known_daemons_entry
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
+sub create_known_daemons_entry {
     my ($hostname) = @_;
-    $shmkh->shlock(LOCK_EX);
-    $known_hosts->{$hostname} = {};
-    $known_hosts->{$hostname}->{status} = "none";
-    $known_hosts->{$hostname}->{passwd} = "none";
-    $known_hosts->{$hostname}->{timestamp} = "none";
-    $shmkh->shunlock(LOCK_EX); 
+    $shmda->shlock(LOCK_EX);
+    $known_daemons->{$hostname} = {};
+    $known_daemons->{$hostname}->{status} = "none";
+    $known_daemons->{$hostname}->{passwd} = "none";
+    $known_daemons->{$hostname}->{timestamp} = "none";
+    $shmda->shunlock(LOCK_EX); 
     return;  
 }
 
 
+#===  FUNCTION  ================================================================
+#         NAME:  create_known_client
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
 sub create_known_client {
     my ($hostname) = @_;
     $shmcl->shlock(LOCK_EX);
@@ -943,68 +1334,115 @@ sub create_known_client {
     $known_clients->{$hostname}->{status} = "none";
     $known_clients->{$hostname}->{passwd} = "none";
     $known_clients->{$hostname}->{timestamp} = "none";
+    $known_clients->{$hostname}->{mac_address} = "none";
+    $known_clients->{$hostname}->{events} = "none";
     $shmcl->shunlock(LOCK_EX); 
     return;  
 }
 
 
-sub update_known_hosts_entry {
-    my ($hostname, $status, $passwd, $timestamp) = @_;
-    my ($Sekunden, $Minuten, $Stunden, $Monatstag, $Monat,
-    $Jahr, $Wochentag, $Jahrestag, $Sommerzeit) = localtime(time);
-    $Stunden = $Stunden < 10 ? $Stunden = "0".$Stunden : $Stunden;
-    $Minuten = $Minuten < 10 ? $Minuten = "0".$Minuten : $Minuten;
-    $Sekunden = $Sekunden < 10 ? $Sekunden = "0".$Sekunden : $Sekunden;
-    $Monat+=1;
-    $Monat = $Monat < 10 ? $Monat = "0".$Monat : $Monat;
-    $Monatstag = $Monatstag < 10 ? $Monatstag = "0".$Monatstag : $Monatstag;
-    $Jahr+=1900;
-    my $t = "$Jahr$Monat$Monatstag$Stunden$Minuten$Sekunden";
-
-    $shmkh->shlock(LOCK_EX);
-    if($status) {
-        $known_hosts->{$hostname}->{status} = $status;
+#===  FUNCTION  ================================================================
+#         NAME:  add_content2known_daemons
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
+sub add_content2known_daemons {
+    my $arg = {
+        hostname => undef, status => undef, passwd => undef,
+        mac_address => undef, events => undef, 
+        @_ };
+    my $hostname = $arg->{hostname};
+    my $status = $arg->{status};
+    my $passwd = $arg->{passwd};
+    my $mac_address = $arg->{mac_address};
+    my $events = $arg->{events};
+
+    if (not defined $hostname) {
+        daemon_log("ERROR: function add_content2known_daemons is not invoked with requiered parameter 'hostname'", 1);
+        return;
     }
-    if($passwd) {
-        $known_hosts->{$hostname}->{passwd} = $passwd;
+
+    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";
+    
+    $shmda->shlock(LOCK_EX);
+    if (defined $status) {
+        $known_daemons->{$hostname}->{status} = $status;
     }
-    if($timestamp) {
-        $t = $timestamp;
+    if (defined $passwd) {
+        $known_daemons->{$hostname}->{passwd} = $passwd;
     }
-    $known_hosts->{$hostname}->{timestamp} = $t;
-    $shmkh->shunlock(LOCK_EX); 
-    return;  
+    if (defined $mac_address) {
+        $known_daemons->{$hostname}->{mac_address} = $mac_address;
+    }
+    if (defined $events) {
+        $known_daemons->{$hostname}->{events} = $events;
+    }
+    $known_daemons->{$hostname}->{timestamp} = $t;
+    $shmda->shlock(LOCK_EX);
+    return;
 }
 
-sub update_known_clients {
-    my ($hostname, $status, $passwd, $timestamp) = @_;
-    my ($Sekunden, $Minuten, $Stunden, $Monatstag, $Monat,
-    $Jahr, $Wochentag, $Jahrestag, $Sommerzeit) = localtime(time);
-    $Stunden = $Stunden < 10 ? $Stunden = "0".$Stunden : $Stunden;
-    $Minuten = $Minuten < 10 ? $Minuten = "0".$Minuten : $Minuten;
-    $Sekunden = $Sekunden < 10 ? $Sekunden = "0".$Sekunden : $Sekunden;
-    $Monat+=1;
-    $Monat = $Monat < 10 ? $Monat = "0".$Monat : $Monat;
-    $Monatstag = $Monatstag < 10 ? $Monatstag = "0".$Monatstag : $Monatstag;
-    $Jahr+=1900;
-    my $t = "$Jahr$Monat$Monatstag$Stunden$Minuten$Sekunden";
 
+#===  FUNCTION  ================================================================
+#         NAME:  add_content2known_clients
+#   PARAMETERS:
+#      RETURNS: 
+#  DESCRIPTION: 
+#===============================================================================
+sub add_content2known_clients {
+    my $arg = {
+        hostname => undef, status => undef, passwd => undef,
+        mac_address => undef, events => undef, 
+        @_ };
+    my $hostname = $arg->{hostname};
+    my $status = $arg->{status};
+    my $passwd = $arg->{passwd};
+    my $mac_address = $arg->{mac_address};
+    my $events = $arg->{events};
+
+    if (not defined $hostname) {
+        daemon_log("ERROR: function add_content2known_clients is not invoked with requiered parameter 'hostname'", 1);
+        return;
+    }
+
+    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";
+    
     $shmcl->shlock(LOCK_EX);
-    if($status) {
+    if (defined $status) {
         $known_clients->{$hostname}->{status} = $status;
     }
-    if($passwd) {
+    if (defined $passwd) {
         $known_clients->{$hostname}->{passwd} = $passwd;
     }
-    if($timestamp) {
-        $t = $timestamp;
+    if (defined $mac_address) {
+        $known_clients->{$hostname}->{mac_address} = $mac_address;
+    }
+    if (defined $events) {
+        $known_clients->{$hostname}->{events} = $events;
     }
     $known_clients->{$hostname}->{timestamp} = $t;
-    $shmcl->shunlock(LOCK_EX); 
-    return;  
+    $shmcl->shlock(LOCK_EX);
+    return;
 }
-
       
 
 #===  FUNCTION  ================================================================
@@ -1016,11 +1454,11 @@ sub update_known_clients {
 sub open_fifo {
     my ($fifo_path) = @_ ;
     if( -p $fifo_path ) {
-        daemon_log("FIFO at $fifo_path already exists\n", 1);
+        daemon_log("FIFO at $fifo_path already exists", 1);
         return 0;
     }
     POSIX::mkfifo($fifo_path, 0666) or die "can't mkfifo $fifo_path: $!";
-    daemon_log( "\nFIFO started at $fifo_path\n", 1) ;
+    daemon_log( "FIFO started at $fifo_path", 1) ;
     return 1;
 }
 
@@ -1040,8 +1478,8 @@ GetOptions("h|help" => \&usage,
            );
 
 #  read and set config parameters
-&read_configfile;
 &check_cmdline_param ;
+&read_configfile;
 &check_pid;
 
 $SIG{CHLD} = 'IGNORE';
@@ -1081,15 +1519,13 @@ if($server_activ eq "on"){
             Listen => 20,
             ); 
     if(not defined $server){
-        daemon_log("cannot be a tcp server at $server_port : $@\n");
+        daemon_log("cannot be a tcp server at $server_port : $@");
     } else {
-        daemon_log("start server:\n\t$server_ip:$server_port",1) ;
+        daemon_log("start server:", 1);
+        daemon_log("\t$server_ip:$server_port",1) ;
         vec($rbits, fileno $server, 1) = 1;
         vec($wbits, fileno $server, 1) = 1;
     }
-
-    &create_known_client($server_address);
-    &update_known_clients($server_address, "server", $server_passwd);
     &print_known_clients()
 }
 
@@ -1125,18 +1561,18 @@ while(1) {
         my $client = $server->accept();
         my $other_end = getpeername($client);
         if(not defined $other_end) {
-            daemon_log("client cannot be identified: $!\n");
+            daemon_log("client cannot be identified: $!");
         } else {
             my ($port, $iaddr) = unpack_sockaddr_in($other_end);
             my $actual_ip = inet_ntoa($iaddr);
-            daemon_log("\naccept client from $actual_ip\n", 5);
+            daemon_log("accept client from $actual_ip", 5);
             #my $in_msg = <$client>;
             my $in_msg = &read_from_socket($client);
             if(defined $in_msg){
                 chomp($in_msg);
                 &activating_child($in_msg, $actual_ip);
             } else {
-                daemon_log("cannot read from $actual_ip\n", 5);
+                daemon_log("cannot read from $actual_ip", 5);
             }
         }
         close($client);
@@ -1145,13 +1581,23 @@ while(1) {
     if($arp_activ eq "on" && vec($rout, fileno $arp_fifo, 1)) {
         my $in_msg = <$arp_fifo>;
         print "arp_activ: msg: $in_msg\n";
-        my $act_passwd = $known_hosts->{$bus_address}->{passwd};
+        my $act_passwd = $known_daemons->{$bus_address}->{passwd};
         print "arp_activ: arp_passwd: $act_passwd\n";
-        my $arp_cipher = &create_ciphering($act_passwd);
-        my $crypted_msg = &encrypt_msg($in_msg, $arp_cipher);
-        print "arp_activ: server_ip:$server_ip\n";
-        &activating_child($crypted_msg, $server_ip);
-        
+
+        my $in_msg_hash = $xml->XMLin($in_msg, ForceArray=>1);
+
+        my $target = &get_content_from_xml_hash($in_msg_hash, 'target');
+
+        if ($target eq $server_address) { 
+             print "arp_activ: forward to server\n";
+            my $arp_cipher = &create_ciphering($act_passwd);
+            my $crypted_msg = &encrypt_msg($in_msg, $arp_cipher);
+            &activating_child($crypted_msg, $server_ip);
+        } else {
+            print "arp_activ: send to bus\n";
+            &send_msg_hash2address($in_msg_hash, $bus_address);
+        }
+        print "\n";
     }
 
 
index 2f3a075335af4a3033c9cb8171d7ca60dc5e0894..1dd9e82765c4eb1eaa83e40f07a721f2250f1843 100755 (executable)
@@ -30,24 +30,24 @@ use Crypt::Rijndael;
 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, %cfg_defaults, $foreground, $verbose);
+my ($cfg_file, $default_cfg_file, %cfg_defaults, $foreground, $verbose);
 my ($bus_activ, $bus_passwd, $bus_ip, $bus_port, $bus_address, $bus);
 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_hosts, $shmkh);
+my ($xml, $bus_cipher, $known_daemons, $shmkh);
 
 $foreground = 0 ;
-$known_hosts = {};
-$shmkh = tie($known_hosts, 'IPC::Shareable', undef, {create => 1, 
+$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"],
@@ -134,8 +134,12 @@ sub check_cmdline_param () {
     my $err_config;
     my $err_counter = 0;
     if( not defined( $cfg_file)) {
-        $err_config = "please specify a config file";
-        $err_counter += 1;
+        #$err_config = "please specify a config file";
+        #$err_counter += 1;
+        my $cwd = getcwd;
+        my $name = "gosa-sd-bus.cfg";
+        $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 );
@@ -412,24 +416,24 @@ sub process_incoming_msg {
     daemon_log("crypted_msg:\n\t$crypted_msg", 7);
 
     my @valid_keys;
-    my @host_keys = keys %$known_hosts;
-    my $l = @host_keys;
-    daemon_log("number of host_keys: $l\n", 7);
-
-    foreach my $host_key (@host_keys) {    
-        if($host_key =~ "^$host") {
-            push(@valid_keys, $host_key);
+    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 daemon_keys: $l\n", 7);
+
     my ($msg, $msg_hash);
     my $msg_flag = 0;    
 
-    # ermittle alle in frage kommenden known_hosts einträge
+    # ermittle alle in frage kommenden known_daemons einträge
     foreach my $host_key (@valid_keys) {
         eval{
             daemon_log( "key: $host_key\n", 7);
-            my $key_passwd = $known_hosts->{$host_key}->{passwd};
+            my $key_passwd = $known_daemons->{$host_key}->{passwd};
             daemon_log("key_passwd: $key_passwd\n", 7);
             my $key_cipher = &create_ciphering($key_passwd);
             $msg = &decrypt_msg($crypted_msg, $key_cipher);
@@ -453,31 +457,83 @@ sub process_incoming_msg {
 
     daemon_log("header from msg:\n\t$header", 1);
     daemon_log("msg to process:\n\t$msg", 7);
+    daemon_log("msg is for: \n\t$target", 7);
 
-    if($target eq "$bus_ip:$bus_port") {
+    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)}
     } else {
-        print "bus leitet $header an $target weiter\n";
-        # bus ist nicht der ziel rechner
-        # leite msg an ziel rechner weiter
+        # msg is for any other server
+        my @targets = @{$msg_hash->{target}};
+        my $len_targets = @targets;
+        print "debug: process_incoming_msg: number of targets for msg: $len_targets\n";
+    
+        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
+            print "debug: process_incoming_msg: all deamons in known_daemons are targets\n";
+
+            my $target = $targets[0];
+            my $source = @{$msg_hash->{source}}[0];
+            print "debug: process_incoming_msg: source: $source\n";
+            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);
+            }
+
+        } else {
+            # a list of targets is specified            
+            print "debug: process_incoming_msg: a list of targets is specified\n";
+            
+            my $target_address;
+            foreach $target_address (@targets) {
+                print "debug: process_incoming_msg: target in targets: $target_address\n";
+                if (exists $known_daemons->{$target_address}) {
+                    print "debug: process_incoming_msg: target is a daemon\n";
+                    &send_msg_hash2address($msg_hash, $target_address);
+                } else { 
+                    print "debug: process_incoming_msg: target is not a daemon\n";
+                    my @daemon_addresses = keys %$known_daemons;
+                    my $daemon_address;
+                    foreach $daemon_address (@daemon_addresses) {
+                        print "debug: process_incoming_msg: client is registered under daemon $daemon_address???\n";
+                        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;
+                        }
+                    }
 
+                }
+            }
+        }
     }
 
-    &print_known_hosts_hash();
+    &print_known_daemons_hash();
     return;
 }
 
 
 #===  FUNCTION  ================================================================
-#         NAME:  get_content_of_known_hosts
+#         NAME:  get_content_of_known_daemons
 #   PARAMETERS:
 #      RETURNS:
 #  DESCRIPTION:
 #===============================================================================
-sub get_content_of_known_hosts {
+sub get_content_of_known_daemons {
     my ($host, $content) = @_;
     return;
 }
@@ -491,7 +547,7 @@ sub get_content_of_known_hosts {
 #===============================================================================
 sub encrypt_msg {
     my ($msg, $my_cipher) = @_;
-    $msg =~ s/[\s]+//g;
+    $msg =~ s/[\n]+//g;
     my $msg_length = length($msg);
     my $multiplier = int($msg_length / 16) + 1;
     my $extension = 16*$multiplier - $msg_length;
@@ -542,7 +598,7 @@ sub create_xml_hash {
 sub create_xml_string {
     my ($xml_hash) = @_ ;
     my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml');
-    $xml_string =~ s/[\s]+//g;
+    $xml_string =~ s/[\n]+//g;
     return $xml_string;
 }
 
@@ -568,9 +624,9 @@ 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") {
-        $result = @$result[0];
+        return @$result[0];
     }
-    return $result;
+    return @$result;
 }
 
 
@@ -639,7 +695,7 @@ sub send_msg_hash2address {
     # generiere xml string
     my $msg_xml = &create_xml_string($msg_hash);
     # hole das entsprechende passwd aus dem hash
-    my $passwd = $known_hosts->{$address}->{passwd};
+    my $passwd = $known_daemons->{$address}->{passwd};
     # erzeuge ein ciphering object
     my $act_cipher = &create_ciphering($passwd);
     # encrypt xml msg
@@ -668,35 +724,47 @@ sub send_msg_hash2address {
 #===============================================================================
 sub send_msg_hash2all {
     my ($msg_hash) = @_;
+
     # fetch header for logging
     my $header = &get_content_from_xml_hash($msg_hash, "header");
+
     # generiere xml string
     my $msg_xml = &create_xml_string($msg_hash);
+
     # hole die liste von target adressen
-    my @targets = keys(%$known_hosts);
+    my @targets = keys(%$known_daemons);
+
     # itteriere durch liste und schicke an jeden msg_xml
     foreach my $target (@targets) {
         if($target eq $bus_address) {next};   # schicke die nachricht nicht an den bus
+
         # hole das entsprechende passwd aus dem hash
-        my $passwd = $known_hosts->{$target}->{passwd};
+        my $passwd = $known_daemons->{$target}->{passwd};
+
         # erzeuge ein ciphering object
         my $act_cipher = &create_ciphering($passwd);
+
         # encrypt xml msg
         my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher);
+
         # öffne socket
         my $socket = &open_socket($target);
         if(not defined $socket){
+
             # hole status für den server aus hash
-            my $status = $known_hosts->{$target}->{status};
+            my $status = $known_daemons->{$target}->{status};
             if(not $status eq "down") {
                 daemon_log("cannot open socket to $target , server not reachable", 1);
+
                 # update status
-                &update_known_hosts_entry($target, "down");
+                &update_known_daemons_entry(hostname=>$target, status=>"down");
             }
             next;
         }
+
         # versende xml msg
         print $socket $crypted_msg."\n";
+
         # schließe socket
         close $socket;
         daemon_log("send '$header'-msg to $target", 5);
@@ -747,15 +815,14 @@ sub create_passwd {
 #  DESCRIPTION:
 #===============================================================================
 sub here_i_am {
-    my ($msg_hash) = @_;
+    my ($msg_hash) = @_ ;
     my $source = &get_content_from_xml_hash($msg_hash, "source");
-    #my $timestamp = time;
 
     my $new_passwd = &create_passwd();
 
-    # create known_hosts entry
-    &create_known_hosts_entry($source);
-    &update_known_hosts_entry($source, "registered", $bus_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);
@@ -763,8 +830,8 @@ sub here_i_am {
     &send_msg_hash2address($out_hash, $source);
 
     # change passwd, reason
-    # &send_msg_hash2address takes $known_hosts->{"$source"}->{passwd} to cipher msg
-    &update_known_hosts_entry($source, "new_passwd", $new_passwd);
+    # &send_msg_hash2address takes $known_daemons->{"$source"}->{passwd} to cipher msg
+    &update_known_daemons_entry(hostname=>$source, status=>"new_passwd", passwd=>$new_passwd);
 
     return;
 }
@@ -777,9 +844,9 @@ sub here_i_am {
 #  DESCRIPTION: 
 #===============================================================================
 sub confirm_new_passwd {
-    my ($msg_hash) = @_;
+    my ($msg_hash) = @_ ;
     my $source = &get_content_from_xml_hash($msg_hash, "source");
-    &update_known_hosts_entry($source, "confirmed_new_passwd");
+    &update_known_daemons_entry(hostname=>$source, status=>"confirmed_new_passwd");
     return;
 }
 
@@ -791,7 +858,7 @@ sub confirm_new_passwd {
 #  DESCRIPTION: 
 #===============================================================================
 sub ping {
-    my ($msg_hash) = @_;
+    my ($msg_hash) = @_ ;
     my $source = &get_content_from_xml_hash($msg_hash, "source");   
     my $out_hash = &create_xml_hash("got_ping", $bus_address, $source);
     &send_msg_hash2address($out_hash, $source);
@@ -823,77 +890,126 @@ sub make_ping {
 sub got_ping {
     my ($msg_hash) = @_;
     my $source = &get_content_from_xml_hash($msg_hash, "source");
-    &update_known_hosts_entry($source, "got_ping");
+    &update_known_daemons_entry(hostname=>$source, status=>"got_ping");
+    return;
+}
+
+
+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;
 }
 
+
+
 #===  FUNCTION  ================================================================
-#         NAME:  print_known_hosts_hash
+#         NAME:  print_known_daemons_hash
 #   PARAMETERS:
 #      RETURNS: 
 #  DESCRIPTION: 
 #===============================================================================
-sub print_known_hosts_hash {
+sub print_known_daemons_hash {
     my ($tmp) = @_;
     print "####################################\n";
-    print "# status of $known_hosts\n";
+    print "# status of known_daemons\n";
     my $hosts;
     my $host_hash;
     $shmkh->shlock(LOCK_EX);
-    my @hosts = keys %$known_hosts;
+    my @hosts = keys %$known_daemons;
     foreach my $host (@hosts) {
-        #my @elements = keys %$known_hosts->{$host};
-        my $status = $known_hosts->{$host}->{status} ;
-        my $passwd = $known_hosts->{$host}->{passwd};
-        my $timestamp = $known_hosts->{$host}->{timestamp};
+        #my @elements = keys %$known_daemons->{$host};
+        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 "\t$status\n";
-        print "\t$passwd\n";
-        print "\t$timestamp\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 create_known_hosts_entry {
+sub create_known_daemons_entry {
     my ($hostname) = @_;
     $shmkh->shlock(LOCK_EX);
-    $known_hosts->{$hostname} = {};
-    $known_hosts->{$hostname}->{status} = "none";
-    $known_hosts->{$hostname}->{passwd} = "none";
-    $known_hosts->{$hostname}->{timestamp} = "none";
+    $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 update_known_hosts_entry {
-    my ($hostname, $status, $passwd, $timestamp) = @_;
-    my ($Sekunden, $Minuten, $Stunden, $Monatstag, $Monat,
-    $Jahr, $Wochentag, $Jahrestag, $Sommerzeit) = localtime(time);
-    $Stunden = $Stunden < 10 ? $Stunden = "0".$Stunden : $Stunden;
-    $Minuten = $Minuten < 10 ? $Minuten = "0".$Minuten : $Minuten;
-    $Sekunden = $Sekunden < 10 ? $Sekunden = "0".$Sekunden : $Sekunden;
-    $Monat+=1;
-    $Monat = $Monat < 10 ? $Monat = "0".$Monat : $Monat;
-    $Monatstag = $Monatstag < 10 ? $Monatstag = "0".$Monatstag : $Monatstag;
-    $Jahr+=1900;
-    my $t = "$Jahr$Monat$Monatstag$Stunden$Minuten$Sekunden";
+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;
+    }
+
+    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($status) {
-        $known_hosts->{$hostname}->{status} = $status;
+    if (defined $status) {
+        $known_daemons->{$hostname}->{status} = $status;
     }
-    if($passwd) {
-        $known_hosts->{$hostname}->{passwd} = $passwd;
+    if (defined $passwd) {
+        $known_daemons->{$hostname}->{passwd} = $passwd;
     }
-    $known_hosts->{$hostname}->{timestamp} = $t;
-    $shmkh->shunlock(LOCK_EX); 
-    return;  
+    if (defined $client) {
+        $known_daemons->{$hostname}->{clients}->{$client} = "";
+    }
+    $known_daemons->{$hostname}->{timestamp} = $t;
+    $shmkh->shunlock(LOCK_EX);
+    return;
 }
 
 
 
+#    $shmkh->shlock(LOCK_EX);
+#    if($status) {
+#        $known_daemons->{$hostname}->{status} = $status;
+#    }
+#    if($passwd) {
+#        $known_daemons->{$hostname}->{passwd} = $passwd;
+#    }
+#    if($lcient
+#    $known_daemons->{$hostname}->{timestamp} = $t;
+#    $shmkh->shunlock(LOCK_EX); 
+#    return;  
+#}
+
+
+
 #==== MAIN = main ==============================================================
 
 #  parse commandline options
@@ -905,8 +1021,9 @@ GetOptions("h|help" => \&usage,
            );
 
 #  read and set config parameters
-&read_configfile;
+
 &check_cmdline_param ;
+&read_configfile;
 &check_pid;
 
 $SIG{CHLD} = 'IGNORE';
@@ -953,9 +1070,9 @@ if($bus_activ eq "on") {
     print "start bus at $bus_ip:$bus_port\n";        
 }
 
-# füge den bus zu known_hosts hinzu
-&create_known_hosts_entry($bus_address);
-&update_known_hosts_entry($bus_address, "bus", $bus_passwd);
+# füge den bus zu known_daemons hinzu
+&create_known_daemons_entry($bus_address);
+&update_known_daemons_entry(hostname=>$bus_address, status=>"bus", passwd=>$bus_passwd);
 
 
 while(1) {
index 7aa61aeb126c9f31f0aec81819792969ff58dad0..cfa4ec37e69127f02c798888909062b77a2c0951 100644 (file)
@@ -16,7 +16,7 @@ server_activ = on
 server_ip = 10.89.1.155
 server_port = 10001
 server_passwd = tester
-
+max_clients = 5
 
 [arp]
 arp_activ = on