Code

Added functionality for waking clients - basically
[gosa.git] / gosa-si / gosa-si-client
index 3825940a7c6235ae4a5fb9b163f62f1ecccebf45..2076b09798e96d0da7df0ea1c3dca0cfa781b557 100755 (executable)
@@ -3,12 +3,12 @@
 #
 #         FILE:  gosa-server
 #
-#        USAGE:  ./gosasc
+#        USAGE:  gosa-si-client
 #
 #  DESCRIPTION:
 #
 #      OPTIONS:  ---
-# REQUIREMENTS:  ---
+# REQUIREMENTS:  libnetaddr-ip-perl
 #         BUGS:  ---
 #        NOTES:
 #       AUTHOR:   (Andreas Rettenberger), <rettenberger@gonicus.de>
@@ -24,6 +24,7 @@ use Getopt::Long;
 use Config::IniFiles;
 use POSIX;
 use Time::HiRes qw( gettimeofday );
+use File::Basename;
 
 use Fcntl;
 use IO::Socket::INET;
@@ -35,17 +36,18 @@ use Data::Dumper;
 use Sys::Syslog qw( :DEFAULT setlogsock);
 use File::Spec;
 use Cwd;
-use GosaSupportDaemon;
+use NetAddr::IP;
+use GOSA::GosaSupportDaemon;
 
 
 my ($cfg_file, %cfg_defaults, $foreground, $verbose, $pid_file, $procid, $pid, $log_file);
 my ($server_address, $server_ip, $server_port, $server_domain, $server_passwd, $server_cipher, $server_timeout);
-my ($client_address, $client_ip, $client_port, $client_mac_address);
-my ($input_socket, $rbits, $wbits, $ebits, $xml, $known_hosts);
+my ($client_address, $client_ip, $client_port, $client_mac_address, $network_interface, $ldap_config, $pam_config, $nss_config, $gotoHardwareChecksum);
+my ($input_socket, $rbits, $wbits, $ebits, $xml, $known_hosts, $ldap_enabled);
 my (@events);
 
 # default variables
-my $event_dir = "/etc/gosac/events";
+my $event_dir = "/usr/lib/gosa-si/client/events";
 $known_hosts = {};
 $foreground = 0 ;
 %cfg_defaults =
@@ -55,6 +57,11 @@ $foreground = 0 ;
     },
 "client" => 
     {"client_port" => [\$client_port, "20083"],
+     "client_ip" => [\$client_ip, "0.0.0.0"],
+     "ldap" => [\$ldap_enabled, 1],
+     "ldap_config" => [\$ldap_config, "/etc/ldap/ldap.conf"],
+     "pam_config" => [\$pam_config, "/etc/pam_ldap.conf"],
+     "nss_config" => [\$nss_config, "/etc/libnss_ldap.conf"],
     },
 "server" =>
     {"server_ip" => [\$server_ip, ""],
@@ -136,13 +143,12 @@ sub daemon_log {
 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;
-        my $cwd = getcwd;
-        my $name = "/etc/gosa/gosa-si-client.conf";
-        $cfg_file = File::Spec->catfile( $cwd, $name );
-        print STDERR "no conf file specified\n   try to use default: $cfg_file\n";        
+       if(not defined($cfg_file)) {
+               $cfg_file = "/etc/gosa-si/client.conf";
+               if(! -r $cfg_file) {
+                       $err_config = "please specify a config file";
+                       $err_counter += 1;
+               }
     }
     if( $err_counter > 0 ) {
         &usage( "", 1 );
@@ -201,32 +207,172 @@ sub check_pid {
     }
 }
 
+#===  FUNCTION  ================================================================
+#         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 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_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_interfaces 
+#   PARAMETERS:  none
+#      RETURNS:  (list of interfaces) 
+#  DESCRIPTION:  Uses proc fs (/proc/net/dev) to get list of interfaces.
 #===============================================================================
-sub get_ip_and_mac {
-    my $ip = "0.0.0.0.0"; # Defualt-IP
-    my $mac = "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 = "$1:$2:$3:$4:$5:$6";
-            next;
+sub get_interfaces {
+        my @result;
+        my $PROC_NET_DEV= ('/proc/net/dev');
+
+        open(PROC_NET_DEV, "<$PROC_NET_DEV")
+                or die "Could not open $PROC_NET_DEV";
+
+        my @ifs = <PROC_NET_DEV>;
+
+        close(PROC_NET_DEV);
+
+        # Eat first two line
+        shift @ifs;
+        shift @ifs;
+
+        chomp @ifs;
+        foreach my $line(@ifs) {
+                my $if= (split /:/, $line)[0];
+                $if =~ s/^\s+//;
+                push @result, $if;
+        }
+
+        return @result;
+}
+
+#===  FUNCTION  ================================================================
+#         NAME:  get_mac 
+#   PARAMETERS:  interface name (i.e. eth0)
+#      RETURNS:  (mac address) 
+#  DESCRIPTION:  Uses ioctl to get mac address directly from system.
+#===============================================================================
+sub get_mac {
+        my $ifreq= shift;
+        my $result;
+        if ($ifreq && length($ifreq) > 0) { 
+                if($ifreq eq "all") {
+                       if(defined($server_ip)) {
+                               $result = &get_local_mac_for_remote_ip($server_ip);
+                       } else {
+                               $result = "00:00:00:00:00:00";
+                       }
+                } else {
+                        my $SIOCGIFHWADDR= 0x8927;     # man 2 ioctl_list
+
+                        # A configured MAC Address should always override a guessed value
+                        if ($client_mac_address and length($client_mac_address) > 0) {
+                                $result= $client_mac_address;
+                        }
+
+                        socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip')
+                                or die "socket: $!";
+
+                        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;
+                                }
+                        }
+                }
         }
-        if (/inet Adresse:(\d+).(\d+).(\d+).(\d+)/) {
-            $ip = "$1.$2.$3.$4";
-            last;
+        return $result;
+}
+
+#===  FUNCTION  ================================================================
+#         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 {
+        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);
+
+        return $result;
 }
 
+#===  FUNCTION  ================================================================
+#         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 $ifreq= shift;
+        my $result= "00:00:00:00:00:00";
+        my $PROC_NET_ROUTE= ('/proc/net/route');
+
+        open(PROC_NET_ROUTE, "<$PROC_NET_ROUTE")
+                or die "Could not open $PROC_NET_ROUTE";
+
+        my @ifs = <PROC_NET_ROUTE>;
+
+        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;
+               }
+       }
+
+
+        return $result;
+}
 
 #===  FUNCTION  ================================================================
 #         NAME:  usage
@@ -306,16 +452,16 @@ sub register_at_server {
 
     # detect all client accepted events
     opendir(DIR, $event_dir) 
-        or daemon_log("cannot find directory $event_dir!\ngosac starts without any accepting events!", 1);
+        or daemon_log("cannot find directory $event_dir!\ngosa-si-client starts without any accepting events!", 1);
     my $file_name;
-    @events = ();
+    my @events_list = ();
     while(defined($file_name = readdir(DIR))){
         if ($file_name eq "." || $file_name eq "..") {
             next;
         }
-        push(@events, $file_name);
+        push(@events_list, $file_name);
     }
-    my $events = join(",", @events);
+    my $events = join(",", @events_list);
     daemon_log("found events: $events", 1);
 
     # fill in all possible servers
@@ -335,18 +481,19 @@ sub register_at_server {
 
     my ($rout, $wout, $reg_server);
     foreach my $server (@servers) {
+
         # 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, "client_mac_address", $client_mac_address);
+        &add_content2xml_hash($register_hash, "mac_address", $client_mac_address);
         &add_content2xml_hash($register_hash, "events", $events);
+        &add_content2xml_hash($register_hash, "gotoHardwareChecksum", $gotoHardwareChecksum);
 
         # 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; }
-    
+        if ($answer != 0) { next; }
+       
         # waiting for response
         daemon_log("waiting for response...\n", 5);
         my $nf = select($rout=$rbits, $wout=$wbits, undef, $server_timeout);
@@ -384,7 +531,7 @@ sub register_at_server {
                 daemon_log("ERROR: do not understand the incoming message:" , 5);  
                 daemon_log("$@", 7); 
             } else {
-                my $header = &get_content_from_xml_hash($msg_hash, "header");
+                my $header = @{$msg_hash->{header}}[0];
                 if($header eq "registered") {
                     $reg_server = $server;
                     last;
@@ -396,7 +543,7 @@ sub register_at_server {
                 }
             }
         }
-        # kommt antwort nicht, dann probiere es mit dem nächsten in der liste
+        # if no answer arrive, try next server in list
 
     }
     
@@ -422,19 +569,19 @@ sub register_at_server {
 #      RETURNS:
 #  DESCRIPTION:
 #===============================================================================
-sub create_xml_hash {
-    my ($header, $source, $target, $header_value) = @_;
-    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
-}
+#sub create_xml_hash {
+#    my ($header, $source, $target, $header_value) = @_;
+#    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
+#}
 
 
 #===  FUNCTION  ================================================================
@@ -443,13 +590,13 @@ sub create_xml_hash {
 #      RETURNS:
 #  DESCRIPTION:
 #===============================================================================
-sub create_xml_string {
-    my ($xml_hash) = @_ ;
-    my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml');
-    $xml_string =~ s/[\n]+//g;
-    daemon_log("create_xml_string:\n\t$xml_string\n", 7);
-    return $xml_string;
-}
+#sub create_xml_string {
+#    my ($xml_hash) = @_ ;
+#    my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml');
+#    $xml_string =~ s/[\n]+//g;
+#    daemon_log("create_xml_string:\n\t$xml_string\n", 7);
+#    return $xml_string;
+#}
 
 
 #===  FUNCTION  ================================================================
@@ -458,15 +605,15 @@ sub create_xml_string {
 #      RETURNS:
 #  DESCRIPTION:
 #===============================================================================
-sub add_content2xml_hash {
-    my ($xml_ref, $element, $content) = @_;
-    if(not exists $$xml_ref{$element} ) {
-        $$xml_ref{$element} = [];
-    }
-    my $tmp = $$xml_ref{$element};
-    push(@$tmp, $content);
-    return;
-}
+#sub add_content2xml_hash {
+#    my ($xml_ref, $element, $content) = @_;
+#    if(not exists $$xml_ref{$element} ) {
+#        $$xml_ref{$element} = [];
+#    }
+#    my $tmp = $$xml_ref{$element};
+#    push(@$tmp, $content);
+#    return;
+#}
 
 
 #===  FUNCTION  ================================================================
@@ -478,14 +625,14 @@ sub add_content2xml_hash {
 #                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( $element eq "header" || $element eq "target" || $element eq "source") {
-        return @$result[0];
-    }
-    return @$result;
-}
+#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];
+#    }
+#    return @$result;
+#}
 
 #    my ($xml_ref, $element) = @_;
 #    if (exists $xml_ref->{$element}) {
@@ -509,14 +656,14 @@ sub get_content_from_xml_hash {
 #      RETURNS:
 #  DESCRIPTION:
 #===============================================================================
-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;
-}
+#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;
+#}
 
 
 #===  FUNCTION  ================================================================
@@ -525,13 +672,13 @@ sub encrypt_msg {
 #      RETURNS:
 #  DESCRIPTION:
 #===============================================================================
-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;
-    return $msg;
-}
+#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;
+#    return $msg;
+#}
 
 
 #===  FUNCTION  ================================================================
@@ -540,17 +687,17 @@ sub decrypt_msg {
 #      RETURNS:  cipher object
 #  DESCRIPTION:  
 #===============================================================================
-sub create_ciphering {
-    my ($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;
-}
+#sub create_ciphering {
+#    my ($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  ================================================================
@@ -577,52 +724,52 @@ sub create_passwd {
 #      RETURNS:  nothing
 #  DESCRIPTION:  ????
 #===============================================================================
-sub send_msg_hash2address {
-    my ($msg_hash, $address, $passwd) = @_ ;
-
-    # fetch header for logging
-    my $header = @{$msg_hash->{header}}[0];
-
-    # generiere xml string
-    my $msg_xml = &create_xml_string($msg_hash);
-
-    # hole das entsprechende passwd aus dem hash
-    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){
-        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 "done";
-}
+#sub send_msg_hash2address {
+#    my ($msg_hash, $address, $passwd) = @_ ;
+#
+#    # fetch header for logging
+#    my $header = @{$msg_hash->{header}}[0];
+#
+#    # generiere xml string
+#    my $msg_xml = &create_xml_string($msg_hash);
+#
+#    # hole das entsprechende passwd aus dem hash
+#    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){
+#        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 "done";
+#}
 
 
 #===  FUNCTION  ================================================================
@@ -821,12 +968,9 @@ sub process_incoming_msg {
         return;
     } 
 
-    my $header = &get_content_from_xml_hash($msg_hash, "header");
+    my $header = @{$msg_hash->{header}}[0];
     
-    daemon_log("header from msg:", 1);
-    daemon_log("\t$header", 1);
-    daemon_log("msg to process:", 7);
-    daemon_log("\t$msg", 7);
+    daemon_log("receive '$header' from $host", 1);
 
     #check whether msg to process is a event 
     opendir(DIR, $event_dir) 
@@ -855,12 +999,11 @@ sub process_incoming_msg {
     close(DIR);
     daemon_log("could not assign the msg $header to an event", 5);
     
-
-
-    if ($header eq 'new_ldap_config') { &new_ldap_config($msg_hash)}
+    if ($header eq 'new_ldap_config') { if ($ldap_enabled == 1) {&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()}
+       elsif ($header eq 'detect_hardware') { &detect_hardware()}
     else { daemon_log("ERROR: no function assigned to msg $header", 5) }
 
     return;
@@ -926,10 +1069,139 @@ sub got_ping {
 
 sub new_ldap_config {
     my ($msg_hash) = @_ ;
+    my $element;
+    my @ldap_uris;
+    my $ldap_base;
+    my @ldap_options;
+    my @pam_options;
+    my @nss_options;
+    my $goto_admin;
+    my $goto_secret;
+    my $admin_base= "";
+    my $department= "";
+    my $unit_tag;
+
+    # Transform input into array
+    while ( my ($key, $value) = each(%$msg_hash) ) {
+       if ($key =~ /^(source|target|header)$/) {
+               next;
+       }
+
+       foreach $element (@$value) {
+               if ($key =~ /^ldap_uri$/) {
+                       push (@ldap_uris, $element);
+                       next;
+               }
+               if ($key =~ /^ldap_base$/) {
+                       $ldap_base= $element;
+                       next;
+               }
+               if ($key =~ /^goto_admin$/) {
+                       $goto_admin= $element;
+                       next;
+               }
+               if ($key =~ /^goto_secret$/) {
+                       $goto_secret= $element;
+                       next;
+               }
+               if ($key =~ /^ldap_cfg$/) {
+                       push (@ldap_options, "$element");
+                       next;
+               }
+               if ($key =~ /^pam_cfg$/) {
+                       push (@pam_options, "$element");
+                       next;
+               }
+               if ($key =~ /^nss_cfg$/) {
+                       push (@nss_options, "$element");
+                       next;
+               }
+               if ($key =~ /^admin_base$/) {
+                       $admin_base= $element;
+                       next;
+               }
+               if ($key =~ /^department$/) {
+                       $department= $element;
+                       next;
+               }
+               if ($key =~ /^unit_tag$/) {
+                       $unit_tag= $element;
+                       next;
+               }
+       }
+    }
+
+    # Unit tagging enabled?
+    if (defined $unit_tag){
+           push (@pam_options, "pam_filter gosaUnitTag=$unit_tag");
+           push (@nss_options, "nss_base_passwd  $admin_base?sub?gosaUnitTag=$unit_tag");
+           push (@nss_options, "nss_base_group   $admin_base?sub?gosaUnitTag=$unit_tag");
+    }
+
+    # Setup ldap.conf
+    my $file1;
+    my $file2;
+    open(file1, "> $ldap_config");
+    print file1 "# This file was automatically generated by gosa-si-client. Do not change.\n";
+    print file1 "URI";
+    foreach $element (@ldap_uris) {
+       print file1 " $element";
+    }
+    print file1 "\nBASE $ldap_base\n";
+    foreach $element (@ldap_options) {
+       print file1 "$element\n";
+    }
+    close (file1);
+    daemon_log("wrote $ldap_config", 5);
+
+    # Setup pam_ldap.conf / libnss_ldap.conf
+    open(file1, "> $pam_config");
+    open(file2, "> $nss_config");
+    print file1 "# This file was automatically generated by gosa-si-client. Do not change.\n";
+    print file2 "# This file was automatically generated by gosa-si-client. Do not change.\n";
+    print file1 "uri";
+    print file2 "uri";
+    foreach $element (@ldap_uris) {
+       print file1 " $element";
+       print file2 " $element";
+    }
+    print file1 "\nbase $ldap_base\n";
+    print file2 "\nbase $ldap_base\n";
+    foreach $element (@pam_options) {
+       print file1 "$element\n";
+    }
+    foreach $element (@nss_options) {
+       print file2 "$element\n";
+    }
+    close (file2);
+    daemon_log("wrote $nss_config", 5);
+    close (file1);
+    daemon_log("wrote $pam_config", 5);
+
+    # Create goto.secrets if told so - for compatibility reasons
+    if (defined $goto_admin){
+           open(file1, "> /etc/goto/secret");
+           close(file1);
+           chown(0,0, "/etc/goto/secret");
+           chmod(0600, "/etc/goto/secret");
+           open(file1, "> /etc/goto/secret");
+           print file1 "GOTOADMIN=\"$goto_admin\"\nGOTOSECRET=\"$goto_secret\"\n";
+           close(file1);
+           daemon_log("wrote /etc/goto/secret", 5);
+    }
 
-    my @gotoLdapServer = &get_content_from_xml_hash($msg_hash, "new_ldap_config");
-    print Dumper @gotoLdapServer;
+    
 
+    # Write shell based config
+    my $cfg_name= dirname($ldap_config)."/ldap-shell.conf";
+    open(file1, "> $cfg_name");
+    print file1 "LDAP_BASE=\"$ldap_base\"\n";
+    print file1 "ADMIN_BASE=\"$admin_base\"\n";
+    print file1 "DEPARTMENT=\"$department\"\n";
+    print file1 "UNIT_TAG=\"".(defined $unit_tag ? "$unit_tag" : "")."\"\n";
+    print file1 "UNIT_TAG_FILTER=\"".(defined $unit_tag ? "(gosaUnitTag=$unit_tag)" : "")."\"\n";
+    close(file1);
+    daemon_log("wrote $cfg_name", 5);
 
     return;
 
@@ -938,7 +1210,7 @@ sub new_ldap_config {
 
 sub execute_event {
     my ($msg_hash)= @_;
-    my $configdir= '/etc/gosac/events/';
+    my $configdir= '/etc/gosa-si/client/events/';
     my $result;
 
     my $header = &get_content_from_xml_hash($msg_hash, 'header');
@@ -949,7 +1221,7 @@ sub execute_event {
     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");
+        daemon_log("ERROR: Entries missing in XML msg for gosa events under $configdir");
     } else {
         my $parameters="";
         my @params = &get_content_from_xml_hash($msg_hash, $header);
@@ -995,8 +1267,128 @@ sub new_passwd {
     return; 
 }
 
+sub generate_hw_digest {
+       my $hw_data;
+       foreach my $line (split /\n/, `cat /proc/bus/pci/devices`) {
+               $hw_data.= sprintf "%s", $line =~ /[^\s]+\s([^\s]+)\s.*/;
+       }
+       return(md5_base64($hw_data));
+}
+
+sub detect_hardware {
+       my $hwinfo= `which hwinfo`;
+       chomp $hwinfo;
+
+       if (!(defined($hwinfo) && length($hwinfo) > 0)) {
+               &main::daemon_log("ERROR: hwinfo was not found in \$PATH! Hardware detection will not work!", 1);
+               return;
+       }
+
+       my $result= {
+               gotoXDriver     => "",
+               gotoXMouseType  => "",
+               gotoXMouseport  => "",
+               gotoXkbModel    => "",
+               gotoXHsync      => "",
+               gotoXVsync      => "",
+               gotoXResolution => "",
+               ghUsbSupport    => "",
+               gotoSndModule   => "",
+               ghGfxAdapter    => "",
+               ghNetNic        => "",
+               ghSoundAdapter  => "",
+               ghMemSize       => "",
+               ghCpuType       => "",
+               gotoModules     => [],
+               ghIdeDev        => [],
+               ghScsiDev       => [],
+       };
+
+       &main::daemon_log("Starting hardware detection", 4);
+       my $gfxcard= `$hwinfo --gfxcard`;
+       my $primary_adapter= $1 if $gfxcard =~ /^Primary display adapter:\s#(\d+)\n/m;
+       if(defined($primary_adapter)) {
+               ($result->{ghGfxAdapter}, $result->{gotoXDriver}) = ($1,$2) if 
+                       $gfxcard =~ /$primary_adapter:.*?Model:\s\"([^\"]*)\".*?Server Module:\s(\w*).*?\n\n/s;
+       }
+       my $monitor= `$hwinfo --monitor`;
+       my $primary_monitor= $1 if $monitor =~ /^(\d*):.*/m;
+       if(defined($primary_monitor)) {
+               ($result->{gotoXResolution}, $result->{gotoXVsync}, $result->{gotoXHsync})= ($1,$2,$3) if 
+               $monitor =~ /$primary_monitor:\s.*?Max\.\sResolution:\s([0-9x]*).*?Vert\.\sSync\sRange:\s([\d\-]*)\sHz.*?Hor\.\sSync\sRange:\s([\d\-]*)\skHz.*/s;
+       }
+
+       if(length($result->{gotoXHsync}) == 0) {
+               # set default values
+               $result->{gotoXHsync} = "30+50";
+               $result->{gotoXVsync} = "30+90";
+       }
+
+       my $mouse= `$hwinfo --mouse`;
+       my $primary_mouse= $1 if $mouse =~ /^(\d*):.*/m;
+       if(defined($primary_mouse)) {
+               ($result->{gotoXMouseport}, $result->{gotoXMouseType}) = ($1,$2) if
+               $mouse =~ /$primary_mouse:\s.*?Device\sFile:\s(.*?)\s.*?XFree86\sProtocol:\s(.*?)\n.*?/s;
+       }
+
+       my $sound= `$hwinfo --sound`;
+       my $primary_sound= $1 if $sound =~ /^(\d*):.*/m;
+       if(defined($primary_sound)) {
+               ($result->{ghSoundAdapter}, $result->{gotoSndModule})= ($1,$2) if 
+               $sound =~ /$primary_sound:\s.*?Model:\s\"(.*?)\".*?Driver\sModules:\s\"(.*?)\".*/s;
+       }
+
+       my $netcard= `hwinfo --netcard`;
+       my $primary_netcard= $1 if $netcard =~ /^(\d*):.*/m;
+       if(defined($primary_netcard)) {
+               $result->{ghNetNic}= $1 if $netcard =~ /$primary_netcard:\s.*?Model:\s\"(.*?)\".*/s;
+       }
+
+       my $keyboard= `hwinfo --keyboard`;
+       my $primary_keyboard= $1 if $keyboard =~ /^(\d*):.*/m;
+       if(defined($primary_keyboard)) {
+               $result->{gotoXkbModel}= $1 if $keyboard =~ /$primary_keyboard:\s.*?XkbModel:\s(.*?)\n.*/s;
+       }
+
+       $result->{ghCpuType}= sprintf "%s / %s - %s", 
+       `cat /proc/cpuinfo` =~ /.*?vendor_id\s+:\s(.*?)\n.*?model\sname\s+:\s(.*?)\n.*?cpu\sMHz\s+:\s(.*?)\n.*/s;
+       $result->{ghMemSize}= $1 if `cat /proc/meminfo` =~ /^MemTotal:\s+(.*?)\skB.*/s;
+
+       my @gotoModules=();
+       for my $line(`lsmod`) {
+               if (($line =~ /^Module.*$/) or ($line =~ /^snd.*$/)) {
+                       next;
+               } else {
+                       push @gotoModules, $1 if $line =~ /^(\w*).*$/
+               }
+       }
+       my %seen = ();
+       
+       # Remove duplicates and save
+       push @{$result->{gotoModules}}, grep { ! $seen{$_} ++ } @gotoModules;
+
+       $result->{ghUsbSupport} = (-d "/proc/bus/usb")?"true":"false";
+       
+       #TODO Ide detection
+#$result->{ghIdeDev} = $@ if ``
+#opendir(IDE, "/proc/ide");
+#for my $model(grep /ide\d\/hd\w\/model/, readdir(DIR)) {
+#      print "$model\n";
+#}
+#close(IDE);
+
+       while ( `cat /proc/scsi/scsi` =~ /^.*?Vendor:\s(.*?)\s+Model:\s(.*?)\s+.*$/mg ) {
+               push (@{$result->{ghScsiDev}}, "$1 $2");
+       }
 
+       &main::daemon_log("Hardware detection done!", 4);
 
+    return &send_msg_hash2address(
+               &create_xml_hash("detected_hardware", $client_address, $server_address, $result),
+               $server_address, 
+               $server_passwd
+       );
+}
 
 #==== MAIN = main ==============================================================
 
@@ -1013,9 +1405,17 @@ GetOptions("h|help" => \&usage,
 &read_configfile;
 &check_pid;
 
+if ( ! $foreground ) {
+       open STDIN, '/dev/null' or die "Can’t read /dev/null: $!";
+       open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!";
+       open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!";
+}
+
+
 # restart daemon log file
 if(-e $log_file ) { unlink $log_file }
-daemon_log("started!");
+daemon_log(" ", 1);
+daemon_log("$0 started!", 1);
 
 # Just fork, if we"re not in foreground mode
 if( ! $foreground ) { $pid = fork(); }
@@ -1030,10 +1430,13 @@ if( 0 != $pid ) {
 }
 
 # detect own ip and mac address
-($client_ip, $client_mac_address) = &get_ip_and_mac(); 
-if (not defined $client_ip) {
-    die "EXIT: ip address of $0 could not be detected";
-}
+$network_interface= &get_interface_for_ip($client_ip);
+$client_mac_address= &get_mac($network_interface);
+
+# ($client_ip, $client_mac_address) = &get_ip_and_mac(); 
+#if (not defined $client_ip) {
+#    die "EXIT: ip address of $0 could not be detected";
+#}
 daemon_log("client ip address detected: $client_ip", 1);
 daemon_log("client mac address detected: $client_mac_address", 1);
 
@@ -1041,12 +1444,21 @@ daemon_log("client mac address detected: $client_mac_address", 1);
 if (defined $server_ip && defined $server_port) {
     $server_address = $server_ip.":".$server_port;
 }
+
+# this is necessary that gosa-si-server knowns to which ip-address he can send msgs
+if( $client_ip eq "0.0.0.0" ) {
+    $client_ip = "127.0.0.1";
+}
 $client_address = $client_ip.":".$client_port;
 
 # setup xml parser
 $xml = new XML::Simple();
 
+# compute hardware checksum
+$gotoHardwareChecksum= &generate_hw_digest();
+
 # create input socket
+daemon_log(" ", 1);
 $rbits = $wbits = $ebits = "";
 $input_socket = IO::Socket::INET->new(LocalPort => $client_port,
         Type => SOCK_STREAM,
@@ -1056,12 +1468,13 @@ $input_socket = IO::Socket::INET->new(LocalPort => $client_port,
 if(not defined $input_socket){
     daemon_log("cannot be a tcp server at $client_port : $@\n");
 } else {
-    daemon_log("start server:\n\t$server_ip:$client_port",1) ;
+    daemon_log("start client at $client_address",1) ;
     vec($rbits, fileno $input_socket, 1) = 1;
     vec($wbits, fileno $input_socket, 1) = 1;
 }
 
 # register at server
+daemon_log(" ", 1);
 &register_at_server();