Code

Fixed a couple of additional _/-
[gosa.git] / gosa-si / modules / SIPackages.pm
index 8fd71440642b7d501b471dc60d711e7f564426c4..b36fa497e92bf85d14dfce6b0f6f8ec3a38a38b5 100644 (file)
@@ -12,40 +12,42 @@ use GOSA::GosaSupportDaemon;
 use IO::Socket::INET;
 use XML::Simple;
 use Data::Dumper;
+use NetAddr::IP;
 use Net::LDAP;
-use Socket qw/PF_INET SOCK_DGRAM inet_ntoa sockaddr_in/;
+use Socket;
+use Net::hostent;
+use Net::DNS;
 
 BEGIN{}
 END {}
 
-my ($known_clients_file_name);
-my ($server_activ, $server_ip, $server_mac_address, $server_port, $server_passwd, $max_clients, $ldap_uri, $ldap_base, $ldap_admin_dn, $ldap_admin_password);
-my ($bus_activ, $bus_passwd, $bus_ip, $bus_port);
+my ($server_ip, $server_mac_address, $server_port, $SIPackages_key, $max_clients, $ldap_uri, $ldap_base, $ldap_admin_dn, $ldap_admin_password, $server_interface);
+my ($bus_activ, $bus_key, $bus_ip, $bus_port);
 my $server;
 my $network_interface;
 my $no_bus;
 my (@ldap_cfg, @pam_cfg, @nss_cfg, $goto_admin, $goto_secret);
 
 
-my %cfg_defaults =
-(
-"server" =>
-    {"server_activ" => [\$server_activ, "on"],
-    "server_ip" => [\$server_ip, "0.0.0.0"],
-    "server_mac_address" => [\$server_mac_address, ""],
-    "server_port" => [\$server_port, "20081"],
-    "server_passwd" => [\$server_passwd, ""],
-    "max_clients" => [\$max_clients, 100],
-    "ldap_uri" => [\$ldap_uri, ""],
-    "ldap_base" => [\$ldap_base, ""],
-    "ldap_admin_dn" => [\$ldap_admin_dn, ""],
-    "ldap_admin_password" => [\$ldap_admin_password, ""],
+my %cfg_defaults = (
+"bus" => {
+    "activ" => [\$bus_activ, "on"],
+    "key" => [\$bus_key, ""],
+    "ip" => [\$bus_ip, ""],
+    "port" => [\$bus_port, "20080"],
     },
-"bus" =>
-    {"bus_activ" => [\$bus_activ, "on"],
-    "bus_passwd" => [\$bus_passwd, ""],
-    "bus_ip" => [\$bus_ip, ""],
-    "bus_port" => [\$bus_port, "20080"],
+"server" => {
+    "ip" => [\$server_ip, "0.0.0.0"],
+    "mac_address" => [\$server_mac_address, "00:00:00:00:00"],
+    "port" => [\$server_port, "20081"],
+    "ldap-uri" => [\$ldap_uri, ""],
+    "ldap-base" => [\$ldap_base, ""],
+    "ldap-admin_dn" => [\$ldap_admin_dn, ""],
+    "ldap-admin_password" => [\$ldap_admin_password, ""],
+    "max-clients" => [\$max_clients, 100],
+    },
+"SIPackages" => {
+    "key" => [\$SIPackages_key, ""],
     },
 );
 
@@ -54,16 +56,17 @@ my %cfg_defaults =
 # read configfile and import variables
 &read_configfile();
 
-# detect interfaces and mac address
 $network_interface= &get_interface_for_ip($server_ip);
-$server_mac_address= &get_mac($network_interface); 
+$server_mac_address= &get_mac($network_interface);
 
 # complete addresses
-if( $server_ip eq "0.0.0.0" ) {
-    $server_ip = "127.0.0.1";
-}
+#if( $server_ip eq "0.0.0.0" ) {
+#    $server_ip = "127.0.0.1";
+#}
 my $server_address = "$server_ip:$server_port";
+$main::server_address = $server_address;
 my $bus_address = "$bus_ip:$bus_port";
+$main::bus_address = $bus_address;
 
 # create general settings for this module
 my $xml = new XML::Simple();
@@ -76,20 +79,76 @@ if($bus_activ eq "on") {
     &register_at_bus();
 }
 
+# add myself to known_server_db
+my $res = $main::known_server_db->add_dbentry( {table=>'known_server',
+        primkey=>'hostname',
+        hostname=>$server_address,
+        status=>'myself',
+        hostkey=>$SIPackages_key,
+        timestamp=>&get_time,
+        } );
+
+
+
 ### functions #################################################################
 
 
 sub get_module_info {
     my @info = ($server_address,
-                $server_passwd,
-                $server,
-                $server_activ,
-                "socket",
+                $SIPackages_key,
                 );
     return \@info;
 }
 
 
+sub do_wake {
+        my $host    = shift;
+        my $ipaddr  = shift || '255.255.255.255';
+        my $port    = getservbyname('discard', 'udp');
+
+        my ($raddr, $them, $proto);
+        my ($hwaddr, $hwaddr_re, $pkt);
+
+        # get the hardware address (ethernet address)
+
+        $hwaddr_re = join(':', ('[0-9A-Fa-f]{1,2}') x 6);
+        if ($host =~ m/^$hwaddr_re$/) {
+                $hwaddr = $host;
+        } else {
+                # $host is not a hardware address, try to resolve it
+                my $ip_re = join('\.', ('([0-9]|[1-9][0-9]|1[0-9]{2}|2([0-4][0-9]|5[0-5]))') x 4);
+                my $ip_addr;
+                if ($host =~ m/^$ip_re$/) {
+                        $ip_addr = $host;
+                } else {
+                        my $h;
+                        unless ($h = gethost($host)) {
+                                return undef;
+                        }
+                        $ip_addr = inet_ntoa($h->addr);
+                }
+        }
+
+        # Generate magic sequence
+        foreach (split /:/, $hwaddr) {
+                $pkt .= chr(hex($_));
+        }
+        $pkt = chr(0xFF) x 6 . $pkt x 16;
+
+        # Allocate socket and send packet
+
+        $raddr = gethostbyname($ipaddr)->addr;
+        $them = pack_sockaddr_in($port, $raddr);
+        $proto = getprotobyname('udp');
+
+        socket(S, AF_INET, SOCK_DGRAM, $proto) or die "socket : $!";
+        setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt : $!";
+
+        send(S, $pkt, 0, $them) or die "send : $!";
+        close S;
+}
+
+
 #===  FUNCTION  ================================================================
 #         NAME:  read_configfile
 #   PARAMETERS:  cfg_file - string -
@@ -234,34 +293,6 @@ sub get_mac {
        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 $result;
-}
-
 
 #===  FUNCTION  ================================================================
 #         NAME:  register_at_bus
@@ -276,18 +307,14 @@ sub register_at_bus {
                                                     primkey=>'hostname',
                                                     hostname=>$bus_address,
                                                     status=>'bus',
-                                                    hostkey=>$bus_passwd,
+                                                    hostkey=>$bus_key,
                                                     timestamp=>&get_time,
                                                 } );
     my $msg_hash = &create_xml_hash("here_i_am", $server_address, $bus_address);
-    my $answer = "";
-    $answer = &send_msg_hash2address($msg_hash, $bus_address, $bus_passwd);
-    if ($answer == 0) {
-        &main::daemon_log("register at bus: $bus_address", 1);
-    } else {
-        &main::daemon_log("unable to send 'register'-msg to bus '$bus_address': $answer", 1);
-    }
-    return;
+    my $msg = &create_xml_string($msg_hash);
+
+    &main::send_msg_to_target($msg, $bus_address, $bus_key, "here_i_am");
+    return $msg;
 }
 
 
@@ -298,7 +325,7 @@ sub register_at_bus {
 #  DESCRIPTION:  handels the proceeded distribution to the appropriated functions
 #===============================================================================
 sub process_incoming_msg {
-    my ($msg, $msg_hash) = @_ ;
+    my ($msg, $msg_hash, $remote_ip) = @_ ;
     my $error = 0;
     my $host_name;
     my $host_key;
@@ -306,7 +333,6 @@ sub process_incoming_msg {
 
     # process incoming msg
     my $header = @{$msg_hash->{header}}[0]; 
-    my $source = @{$msg_hash->{source}}[0];
     my @target_l = @{$msg_hash->{target}};
 
     &main::daemon_log("SIPackages: msg to process: $header", 3);
@@ -319,15 +345,29 @@ sub process_incoming_msg {
 
     if( 1 == length @target_l) {
         my $target = $target_l[0];
-        if( $target eq $server_address ) {  
-            if ($header eq 'new_passwd') { @out_msg_l = &new_passwd($msg_hash) }
-            elsif ($header eq 'here_i_am') { @out_msg_l = &here_i_am($msg_hash) }
-            elsif ($header eq 'who_has') { @out_msg_l = &who_has($msg_hash) }
-            elsif ($header eq 'who_has_i_do') { @out_msg_l = &who_has_i_do($msg_hash) }
-            elsif ($header eq 'got_ping') { @out_msg_l = &got_ping($msg_hash)}
-            elsif ($header eq 'get_load') { @out_msg_l = &execute_actions($msg_hash)}
-            else {
-                &main::daemon_log("ERROR: $header is an unknown core funktion", 1);
+               if(&server_matches($target)) {
+            if ($header eq 'new_key') {
+                @out_msg_l = &new_key($msg_hash)
+            } elsif ($header eq 'here_i_am') {
+                @out_msg_l = &here_i_am($msg_hash)
+            } elsif ($header eq 'who_has') {
+                @out_msg_l = &who_has($msg_hash)
+            } elsif ($header eq 'who_has_i_do') {
+                @out_msg_l = &who_has_i_do($msg_hash)
+            } elsif ($header eq 'got_ping') {
+                @out_msg_l = &got_ping($msg_hash)
+            } elsif ($header eq 'get_load') {
+                @out_msg_l = &execute_actions($msg_hash)
+            } elsif ($header eq 'detected_hardware') {
+                @out_msg_l = &process_detected_hardware($msg_hash)
+            } elsif ($header eq 'trigger_wake') {
+                foreach (@{$msg_hash->{macAddress}}){
+                    &main::daemon_log("SIPackages: trigger wake for $_", 1);
+                    do_wake($_);
+                }
+
+            } else {
+                &main::daemon_log("ERROR: $header is an unknown core function", 1);
                 $error++;
             }
         }
@@ -337,11 +377,11 @@ sub process_incoming_msg {
                }
     }
 
-    if( $error == 0) {
-        if( 0 == @out_msg_l ) {
-                       push(@out_msg_l, $msg);
-        }
-    }
+#    if( $error == 0) {
+#        if( 0 == @out_msg_l ) {
+#                      push(@out_msg_l, $msg);
+#        }
+#    }
     
     return \@out_msg_l;
 }
@@ -376,13 +416,13 @@ sub got_ping {
 #      RETURNS:  nothing
 #  DESCRIPTION:  process this incoming message
 #===============================================================================
-sub new_passwd {
+sub new_key {
     my ($msg_hash) = @_;
     my @out_msg_l;
     
     my $header = @{$msg_hash->{header}}[0];
     my $source_name = @{$msg_hash->{source}}[0];
-    my $source_key = @{$msg_hash->{new_passwd}}[0];
+    my $source_key = @{$msg_hash->{new_key}}[0];
     my $query_res;
 
     # check known_clients_db
@@ -394,8 +434,7 @@ sub new_passwd {
             "SET hostkey='$source_key', timestamp='$act_time' ".
             "WHERE hostname='$source_name'";
         my $res = $main::known_clients_db->update_dbentry( $sql_statement );
-
-        my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name);
+        my $hash = &create_xml_hash("confirm_new_key", $server_address, $source_name);
         my $out_msg = &create_xml_string($hash);
         push(@out_msg_l, $out_msg);
     }
@@ -412,7 +451,7 @@ sub new_passwd {
                 "WHERE hostname='$source_name'";
             my $res = $main::known_server_db->update_dbentry( $sql_statement );
 
-            my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name);
+            my $hash = &create_xml_hash("confirm_new_key", $server_address, $source_name);
             my $out_msg = &create_xml_string($hash);
             push(@out_msg_l, $out_msg);
         }
@@ -435,6 +474,7 @@ sub here_i_am {
 
     my $source = @{$msg_hash->{source}}[0];
     my $mac_address = @{$msg_hash->{mac_address}}[0];
+       my $gotoHardwareChecksum = @{$msg_hash->{gotoHardwareChecksum}}[0];
 
     # number of known clients
     my $nu_clients= $main::known_clients_db->count_dbentries('known_clients');
@@ -471,6 +511,7 @@ sub here_i_am {
     
 
     # add entry to known_clients_db
+    my $act_timestamp = &get_time;
     my $res = $main::known_clients_db->add_dbentry( {table=>'known_clients', 
                                                 primkey=>'hostname',
                                                 hostname=>$source,
@@ -478,7 +519,7 @@ sub here_i_am {
                                                 macaddress=>$mac_address,
                                                 status=>'registered',
                                                 hostkey=>$new_passwd,
-                                                timestamp=>&get_time,
+                                                timestamp=>$act_timestamp,
                                                 } );
 
     if ($res != 0)  {
@@ -500,6 +541,8 @@ sub here_i_am {
 
         # send update msg to bus
         $out_hash = &create_xml_hash("new_client", $server_address, $bus_address, $source);
+        &add_content2xml_hash($out_hash, "macaddress", $mac_address);
+        &add_content2xml_hash($out_hash, "timestamp", $act_timestamp);
         my $new_client_out = &create_xml_string($out_hash);
         push(@out_msg_l, $new_client_out);
         &main::daemon_log("send bus msg that client '$source' has registerd at server '$server_address'", 3);
@@ -511,6 +554,10 @@ sub here_i_am {
         push(@out_msg_l, $new_ldap_config_out);
     }
 
+       my $hardware_config_out = &hardware_config($source, $gotoHardwareChecksum);
+       if( $hardware_config_out ) {
+               push(@out_msg_l, $hardware_config_out);
+       }
 
     return @out_msg_l;
 }
@@ -524,6 +571,7 @@ sub here_i_am {
 #===============================================================================
 sub who_has {
     my ($msg_hash) = @_ ;
+    my @out_msg_l;
     
     # what is your search pattern
     my $search_pattern = @{$msg_hash->{who_has}}[0];
@@ -545,11 +593,12 @@ sub who_has {
     # search was successful
     if (defined $host_address) {
         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);
+        my $out_hash = &create_xml_hash("who_has_i_do", $server_address, $source, "mac_address");
+        &add_content2xml_hash($out_hash, "mac_address", $search_element);
+        my $out_msg = &create_xml_string($out_hash);
+        push(@out_msg_l, $out_msg);
     }
-    return;
+    return @out_msg_l;
 }
 
 
@@ -562,7 +611,6 @@ sub who_has_i_do {
     print "\ngot msg $header:\nserver $source has client with $search_param $search_value\n";
 }
 
-
 #===  FUNCTION  ================================================================
 #         NAME:  new_ldap_config
 #   PARAMETERS:  address - string - ip address and port of a host
@@ -570,8 +618,154 @@ sub who_has_i_do {
 #  DESCRIPTION:  send to address the ldap configuration found for dn gotoLdapServer
 #===============================================================================
 sub new_ldap_config {
-    my ($address) = @_ ;
-    
+       my ($address) = @_ ;
+
+       my $sql_statement= "SELECT * FROM known_clients WHERE hostname='$address'";
+       my $res = $main::known_clients_db->select_dbentry( $sql_statement );
+
+       # check hit
+       my $hit_counter = keys %{$res};
+       if( not $hit_counter == 1 ) {
+               &main::daemon_log("ERROR: more or no hit found in known_clients_db by query by '$address'", 1);
+       }
+
+       my $macaddress = $res->{1}->{macaddress};
+       my $hostkey = $res->{1}->{hostkey};
+
+       if (not defined $macaddress) {
+               &main::daemon_log("ERROR: no mac address found for client $address", 1);
+               return;
+       }
+
+       # Build LDAP connection
+       my $ldap = Net::LDAP->new($ldap_uri);
+       if( not defined $ldap ) {
+               &main::daemon_log("ERROR: cannot connect to ldap: $ldap_uri", 1);
+               return;
+       } 
+
+
+       # Bind to a directory with dn and password
+       my $mesg= $ldap->bind($ldap_admin_dn, password => $ldap_admin_password);
+
+       # Perform search
+       $mesg = $ldap->search( base   => $ldap_base,
+               scope  => 'sub',
+               attrs => ['dn', 'gotoLdapServer', 'gosaUnitTag'],
+               filter => "(&(objectClass=GOhard)(macaddress=$macaddress))");
+       #$mesg->code && die $mesg->error;
+       if($mesg->code) {
+               &main::daemon_log($mesg->error, 1);
+               return;
+       }
+
+       # Sanity check
+       if ($mesg->count != 1) {
+               &main::daemon_log("WARNING: client mac address $macaddress not found/not unique in ldap search", 1);
+               &main::daemon_log("\tbase: $ldap_base", 1);
+               &main::daemon_log("\tscope: sub", 1);
+               &main::daemon_log("\tattrs: dn, gotoLdapServer", 1);
+               &main::daemon_log("\tfilter: (&(objectClass=GOhard)(macaddress=$macaddress))", 1);
+               return;
+       }
+
+       my $entry= $mesg->entry(0);
+       my $dn= $entry->dn;
+       my @servers= $entry->get_value("gotoLdapServer");
+       my $unit_tag= $entry->get_value("gosaUnitTag");
+       my @ldap_uris;
+       my $server;
+       my $base;
+
+       # Do we need to look at an object class?
+       if (length(@servers) < 1){
+               $mesg = $ldap->search( base   => $ldap_base,
+                       scope  => 'sub',
+                       attrs => ['dn', 'gotoLdapServer'],
+                       filter => "(&(objectClass=gosaGroupOfNames)(member=$dn))");
+               #$mesg->code && die $mesg->error;
+               if($mesg->code) {
+                       &main::daemon_log($mesg->error, 1);
+                       return;
+               }
+
+               # Sanity check
+               if ($mesg->count != 1) {
+                       &main::daemon_log("WARNING: no LDAP information found for client mac $macaddress", 1);
+                       return;
+               }
+
+               $entry= $mesg->entry(0);
+               $dn= $entry->dn;
+               @servers= $entry->get_value("gotoLdapServer");
+       }
+
+       @servers= sort (@servers);
+
+       foreach $server (@servers){
+               $base= $server;
+               $server =~ s%^[^:]+:[^:]+:(ldap.*://[^/]+)/.*$%$1%;
+               $base =~ s%^[^:]+:[^:]+:ldap.*://[^/]+/(.*)$%$1%;
+               push (@ldap_uris, $server);
+       }
+
+       # Assemble data package
+       my %data = ( 'ldap_uri'  => \@ldap_uris, 'ldap_base' => $base,
+               'ldap_cfg' => \@ldap_cfg, 'pam_cfg' => \@pam_cfg,'nss_cfg' => \@nss_cfg );
+
+       # Need to append GOto settings?
+       if (defined $goto_admin and defined $goto_secret){
+               $data{'goto_admin'}= $goto_admin;
+               $data{'goto_secret'}= $goto_secret;
+       }
+
+       # Append unit tag if needed
+       if (defined $unit_tag){
+
+               # Find admin base and department name
+               $mesg = $ldap->search( base   => $ldap_base,
+                       scope  => 'sub',
+                       attrs => ['dn', 'ou', 'FAIclass'],
+                       filter => "(&(objectClass=gosaAdministrativeUnit)(gosaUnitTag=$unit_tag))");
+               #$mesg->code && die $mesg->error;
+               if($mesg->code) {
+                       &main::daemon_log($mesg->error, 1);
+                       return;
+               }
+
+               # Sanity check
+               if ($mesg->count != 1) {
+                       &main::daemon_log("WARNING: cannot find administrative unit for client with tag $unit_tag", 1);
+                       return;
+               }
+
+               $entry= $mesg->entry(0);
+               $data{'admin_base'}= $entry->dn;
+               $data{'department'}= $entry->get_value("ou");
+
+               # Append unit Tag
+               $data{'unit_tag'}= $unit_tag;
+       }
+
+       # Fill release if available
+       my $FAIclass= $entry->get_value("FAIclass");
+       if (defined $FAIclass && $FAIclass =~ /^.* :([A-Za-z0-9\/.]+).*$/) {
+               $data{'release'}= $1;
+       }
+
+
+       # Unbind
+       $mesg = $ldap->unbind;
+
+       # Send information
+       return send_msg("new_ldap_config", $server_address, $address, \%data);
+}
+
+sub process_detected_hardware {
+       my $msg_hash = shift;
+       my $address = $msg_hash->{source}[0];
+       my $gotoHardwareChecksum= $msg_hash->{detected_hardware}[0]->{gotoHardwareChecksum};
+
     my $sql_statement= "SELECT * FROM known_clients WHERE hostname='$address'";
     my $res = $main::known_clients_db->select_dbentry( $sql_statement );
 
@@ -579,6 +773,7 @@ sub new_ldap_config {
     my $hit_counter = keys %{$res};
     if( not $hit_counter == 1 ) {
         &main::daemon_log("ERROR: more or no hit found in known_clients_db by query by '$address'", 1);
+               return;
     }
 
     my $macaddress = $res->{1}->{macaddress};
@@ -588,7 +783,6 @@ sub new_ldap_config {
         &main::daemon_log("ERROR: no mac address found for client $address", 1);
         return;
     }
-
     # Build LDAP connection
     my $ldap = Net::LDAP->new($ldap_uri);
     if( not defined $ldap ) {
@@ -596,79 +790,252 @@ sub new_ldap_config {
         return;
     } 
 
-
     # Bind to a directory with dn and password
-    my $mesg= $ldap->bind($ldap_admin_dn, $ldap_admin_password);
+    my $mesg= $ldap->bind($ldap_admin_dn, password => $ldap_admin_password);
 
     # Perform search
-    $mesg = $ldap->search( base   => $ldap_base,
-                   scope  => 'sub',
-                   attrs => ['dn', 'gotoLdapServer'],
-                   filter => "(&(objectClass=GOhard)(macaddress=$macaddress))");
-    $mesg->code && die $mesg->error;
-
-    # Sanity check
-    if ($mesg->count != 1) {
-           &main::daemon_log("WARNING: client mac address $macaddress not found/not unique in ldap search", 1);
-        &main::daemon_log("\tbase: $ldap_base", 1);
-        &main::daemon_log("\tscope: sub", 1);
-        &main::daemon_log("\tattrs: dn, gotoLdapServer", 1);
-        &main::daemon_log("\tfilter: (&(objectClass=GOhard)(macaddress=$macaddress))", 1);
-           return;
-    }
+       $mesg = $ldap->search(
+               base   => $ldap_base,
+               scope  => 'sub',
+               filter => "(&(objectClass=GOhard)(|(macAddress=$macaddress)(dhcpHWaddress=ethernet $macaddress)))"
+       );
+
+       # We need to create a base entry first (if not done from ArpHandler)
+       if($mesg->count == 0) {
+               &main::daemon_log("Need to create a new LDAP Entry for client $address", 1);
+               my $resolver=Net::DNS::Resolver->new;
+               my $ipaddress= $1 if $address =~ /^([0-9\.]*?):.*$/;
+               my $dnsresult= $resolver->search($ipaddress);
+               my $dnsname= (defined($dnsresult))?$dnsresult->{answer}[0]->{ptrdname}:$ipaddress;
+               my $cn = (($dnsname =~ /^(\d){1,3}\.(\d){1,3}\.(\d){1,3}\.(\d){1,3}/) ? $dnsname : sprintf "%s", $dnsname =~ /([^\.]+)\.?/);
+               my $dn = "cn=$cn,ou=incoming,$ldap_base";
+               &main::daemon_log("Creating entry for $dn",6);
+               my $entry= Net::LDAP::Entry->new( $dn );
+               $entry->dn($dn);
+               $entry->add("objectClass" => "goHard");
+               $entry->add("cn" => $cn);
+               $entry->add("macAddress" => $macaddress);
+               $entry->add("gotomode" => "locked");
+               $entry->add("gotoSysStatus" => "new-system");
+               $entry->add("ipHostNumber" => $ipaddress);
+               if(my $res=$entry->update($ldap)) {
+                       # Fill $mesg again
+                       $mesg = $ldap->search(
+                               base   => $ldap_base,
+                               scope  => 'sub',
+                               filter => "(&(objectClass=GOhard)(|(macAddress=$macaddress)(dhcpHWaddress=ethernet $macaddress)))"
+                       );
+               } else {
+                       &main::daemon_log("ERROR: There was a problem adding the entry", 1);
+               }
 
-    my $entry= $mesg->entry(0);
-    my $dn= $entry->dn;
-    my @servers= $entry->get_value("gotoLdapServer");
-    my @ldap_uris;
-    my $server;
-    my $base;
-
-    # Do we need to look at an object class?
-    if ($#servers < 1){
-           $mesg = $ldap->search( base   => $ldap_base,
-                           scope  => 'sub',
-                           attrs => ['dn', 'gotoLdapServer'],
-                           filter => "(&(objectClass=gosaGroupOfNames)(member=$dn))");
-           $mesg->code && die $mesg->error;
-
-            # Sanity check
-           if ($mesg->count != 1) {
-                   &main::daemon_log("WARNING: no LDAP information found for client mac $macaddress", 1);
-                   return;
-           }
-
-           $entry= $mesg->entry(0);
-           $dn= $entry->dn;
-           @servers= $entry->get_value("gotoLdapServer");
-    }
+       }
+       
+       if($mesg->count == 1) {
+               my $entry= $mesg->entry(0);
+               $entry->changetype("modify");
+               foreach my $attribute (
+                       "gotoSndModule", "ghNetNic", "gotoXResolution", "ghSoundAdapter", "ghCpuType", "gotoXkbModel", 
+                       "ghGfxAdapter", "gotoXMousePort", "ghMemSize", "gotoXMouseType", "ghUsbSupport", "gotoXHsync", 
+                       "gotoXDriver", "gotoXVsync", "gotoXMonitor", "gotoHardwareChecksum") {
+                       if(defined($msg_hash->{detected_hardware}[0]->{$attribute})) {
+                               if(defined($entry->get_value($attribute))) {
+                                       $entry->delete($attribute);
+                               }
+                               &main::daemon_log("Adding attribute $attribute with value ".$msg_hash->{detected_hardware}[0]->{$attribute},1);
+                               $entry->add($attribute => $msg_hash->{detected_hardware}[0]->{$attribute});     
+                       }
+               }
+               foreach my $attribute (
+                       "gotoModules", "ghScsiDev", "ghIdeDev") {
+                       if(defined($msg_hash->{detected_hardware}[0]->{$attribute})) {
+                               if(defined($entry->get_value($attribute))) {
+                                       $entry->delete($attribute);
+                               }
+                               foreach my $array_entry (@{$msg_hash->{detected_hardware}[0]->{$attribute}}) {
+                                       $entry->add($attribute => $array_entry);
+                               }
+                       }
 
-    @servers= sort (@servers);
+               }
 
-    foreach $server (@servers){
-           $base= $server;
-           $server =~ s%^[^:]+:[^:]+:(ldap.*://[^/]+)/.*$%$1%;
-           $base =~ s%^[^:]+:[^:]+:ldap.*://[^/]+/(.*)$%$1%;
-           push (@ldap_uris, $server);
-    }
+               if($entry->update($ldap)) {
+                       &main::daemon_log("Added Hardware configuration to LDAP", 4);
+               }
+
+       }
+       return;
+}
+#===  FUNCTION  ================================================================
+#         NAME:  hardware_config
+#   PARAMETERS:  address - string - ip address and port of a host
+#      RETURNS:  
+#  DESCRIPTION:  
+#===============================================================================
+sub hardware_config {
+       my ($address, $gotoHardwareChecksum) = @_ ;
 
-    # Unbind
-    $mesg = $ldap->unbind;
+       my $sql_statement= "SELECT * FROM known_clients WHERE hostname='$address'";
+       my $res = $main::known_clients_db->select_dbentry( $sql_statement );
 
-    # Assemble data package
-    my %data = ( 'ldap_uri'  => \@ldap_uris, 'ldap_base' => $base,
-                    'ldap_cfg' => \@ldap_cfg, 'pam_cfg' => \@pam_cfg,'nss_cfg' => \@nss_cfg );
+       # check hit
+       my $hit_counter = keys %{$res};
+       if( not $hit_counter == 1 ) {
+               &main::daemon_log("ERROR: more or no hit found in known_clients_db by query by '$address'", 1);
+       }
 
-    # Need to append GOto settings?
-    if (defined $goto_admin and defined $goto_secret){
-           $data{'goto_admin'}= $goto_admin;
-           $data{'goto_secret'}= $goto_secret;
-    }
+       my $macaddress = $res->{1}->{macaddress};
+       my $hostkey = $res->{1}->{hostkey};
 
-    # Send information
-    send_msg("new_ldap_config", $server_address, $address, \%data, $hostkey);
+       if (not defined $macaddress) {
+               &main::daemon_log("ERROR: no mac address found for client $address", 1);
+               return;
+       }
 
-    return;
+       # Build LDAP connection
+       my $ldap = Net::LDAP->new($ldap_uri);
+       if( not defined $ldap ) {
+               &main::daemon_log("ERROR: cannot connect to ldap: $ldap_uri", 1);
+               return;
+       } 
+
+       # Bind to a directory with dn and password
+       my $mesg= $ldap->bind($ldap_admin_dn, password => $ldap_admin_password);
+
+       # Perform search
+       $mesg = $ldap->search(
+               base   => $ldap_base,
+               scope  => 'sub',
+               filter => "(&(objectClass=GOhard)(|(macAddress=$macaddress)(dhcpHWaddress=ethernet $macaddress)))"
+       );
+
+       if($mesg->count() == 0) {
+               &main::daemon_log("Host was not found in LDAP!", 1);
+       } else {
+               my $entry= $mesg->entry(0);
+               my $dn= $entry->dn;
+               if(defined($entry->get_value("gotoHardwareChecksum"))) {
+                       if(! $entry->get_value("gotoHardwareChecksum") eq $gotoHardwareChecksum) {
+                               $entry->replace(gotoHardwareChecksum => $gotoHardwareChecksum);
+                               if($entry->update($ldap)) {
+                                       &main::daemon_log("Hardware changed! Detection triggered.", 4);
+                               }
+                       } else {
+                               # Nothing to do
+                               return;
+                       }
+               }
+       } 
+       # need to fill it to LDAP
+       #$entry->add(gotoHardwareChecksum => $gotoHardwareChecksum);
+       #if($entry->update($ldap)) {
+       #               &main::daemon_log("gotoHardwareChecksum $gotoHardwareChecksum was added to LDAP", 4);
+       #}
+
+       ## Look if there another host with this checksum to use the hardware config
+       #$mesg = $ldap->search(
+       #       base   => $ldap_base,
+       #       scope  => 'sub',
+       #       filter => "(&(objectClass=GOhard)(gotoHardwareChecksum=$gotoHardwareChecksum))"
+       #);
+
+       #if($mesg->count>1) {
+       #       my $clone_entry= $mesg->entry(0);
+       #       $entry->changetype("modify");
+       #       foreach my $attribute (
+       #               "gotoSndModule", "ghNetNic", "gotoXResolution", "ghSoundAdapter", "ghCpuType", "gotoXkbModel", 
+       #               "ghGfxAdapter", "gotoXMousePort", "ghMemSize", "gotoXMouseType", "ghUsbSupport", "gotoXHsync", 
+       #               "gotoXDriver", "gotoXVsync", "gotoXMonitor") {
+       #               my $value= $clone_entry->get_value($attribute);
+       #               if(defined($value)) {
+       #                       if(defined($entry->get_value($attribute))) {
+       #                               $entry->delete($attribute);
+       #                       }
+       #                       &main::daemon_log("Adding attribute $attribute with value $value",1);
+       #                       $entry->add($attribute => $value);
+       #               }
+       #       }
+       #       foreach my $attribute (
+       #               "gotoModules", "ghScsiDev", "ghIdeDev") {
+       #               my $array= $clone_entry->get_value($attribute, 'as_ref' => 1);
+       #               if(defined($array))     {
+       #                       if(defined($entry->get_value($attribute))) {
+       #                               $entry->delete($attribute);
+       #                       }
+       #                       foreach my $array_entry (@{$array}) {
+       #                               $entry->add($attribute => $array_entry);
+       #                       }
+       #               }
+
+       #       }
+       #       if($entry->update($ldap)) {
+       #               &main::daemon_log("Added Hardware configuration to LDAP", 4);
+       #       }
+
+       #}
+
+
+       # Assemble data package
+       my %data = ();
+
+       # Need to append GOto settings?
+       if (defined $goto_admin and defined $goto_secret){
+               $data{'goto_admin'}= $goto_admin;
+               $data{'goto_secret'}= $goto_secret;
+       }
+
+       # Unbind
+       $mesg = $ldap->unbind;
+
+       &main::daemon_log("Send detect_hardware message to $address", 4);
+
+       # Send information
+       return send_msg("detect_hardware", $server_address, $address, \%data);
+}
+
+sub server_matches {
+       my $target = shift;
+       my $target_ip = sprintf("%s", $target =~ /^([0-9\.]*?):.*$/);
+       my $result = 0;
+
+       if($server_ip eq $target_ip) {
+               $result= 1;
+       } elsif ($server_ip eq "0.0.0.0") {     
+               if ($target_ip eq "127.0.0.1") {
+                       $result= 1;
+               } else {
+                       my $PROC_NET_ROUTE= ('/proc/net/route');
+
+                       open(PROC_NET_ROUTE, "<$PROC_NET_ROUTE")
+                               or die "Could not open $PROC_NET_ROUTE";
+
+                       my @ifs = <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($target_ip)->within(new NetAddr::IP($destination, $mask))) {
+                                       # destination matches route, save mac and exit
+                                       $result= 1;
+                                       last;
+                               }
+                       }
+               }
+       } else {
+               &main::daemon_log("Target ip $target_ip does not match Server ip $server_ip",1);
+       }
+
+       return $result;
 }