Code

Don't send ldap config if disabled
[gosa.git] / gosa-si / modules / SIPackages.pm
1 package SIPackages;
3 use Exporter;
4 @ISA = ("Exporter");
6 # Each module has to have a function 'process_incoming_msg'. This function works as a interface to gosa-sd and receives the msg hash from gosa-sd. 'process_incoming_function checks, wether it has a function to process the incoming msg and forward the msg to it. 
9 use strict;
10 use warnings;
11 use GOSA::GosaSupportDaemon;
12 use IO::Socket::INET;
13 use XML::Simple;
14 use Data::Dumper;
15 use NetAddr::IP;
16 use Net::LDAP;
17 use Socket;
18 use Net::hostent;
19 use Net::DNS;
20 use utf8;
22 my $event_dir = "/usr/lib/gosa-si/server/events";
23 use lib "/usr/lib/gosa-si/server/events";
25 BEGIN{}
26 END {}
28 my ($server_ip, $server_mac_address, $server_port, $SIPackages_key, $max_clients, $ldap_uri, $ldap_base, $ldap_admin_dn, $ldap_admin_password, $server_interface);
29 my ($bus_activ, $bus_key, $bus_ip, $bus_port);
30 my $server;
31 my $event_hash;
32 my $network_interface;
33 my $no_bus;
34 my (@ldap_cfg, @pam_cfg, @nss_cfg, $goto_admin, $goto_secret);
35 my $mesg;
37 my %cfg_defaults = (
38 "bus" => {
39     "activ" => [\$bus_activ, "on"],
40     "key" => [\$bus_key, ""],
41     "ip" => [\$bus_ip, ""],
42     "port" => [\$bus_port, "20080"],
43     },
44 "server" => {
45     "ip" => [\$server_ip, "0.0.0.0"],
46     "mac-address" => [\$server_mac_address, "00:00:00:00:00"],
47     "port" => [\$server_port, "20081"],
48     "ldap-uri" => [\$ldap_uri, ""],
49     "ldap-base" => [\$ldap_base, ""],
50     "ldap-admin-dn" => [\$ldap_admin_dn, ""],
51     "ldap-admin-password" => [\$ldap_admin_password, ""],
52     "max-clients" => [\$max_clients, 100],
53     },
54 "SIPackages" => {
55     "key" => [\$SIPackages_key, ""],
56     },
57 );
59 ### START #####################################################################
61 # read configfile and import variables
62 &read_configfile();
65 # if server_ip is not an ip address but a name
66 if( inet_aton($server_ip) ){ $server_ip = inet_ntoa(inet_aton($server_ip)); } 
67 $network_interface= &get_interface_for_ip($server_ip);
68 $server_mac_address= &get_mac($network_interface);
70 &import_events();
72 # Unit tag can be defined in config
73 if((not defined($main::gosa_unit_tag)) || length($main::gosa_unit_tag) == 0) {
74         # Read gosaUnitTag from LDAP
75   &main::refresh_ldap_handle();
76         if( defined($main::ldap_handle) ) {
77                 &main::daemon_log("INFO: Searching for servers gosaUnitTag with mac address $server_mac_address",5);
78                 # Perform search for Unit Tag
79                 $mesg = $main::ldap_handle->search(
80                         base   => $ldap_base,
81                         scope  => 'sub',
82                         attrs  => ['gosaUnitTag'],
83                         filter => "(macaddress=$server_mac_address)"
84                 );
86                 if ($mesg->count == 1) {
87                         my $entry= $mesg->entry(0);
88                         my $unit_tag= $entry->get_value("gosaUnitTag");
89                         if(defined($unit_tag) && length($unit_tag) > 0) {
90                                 &main::daemon_log("INFO: Detected gosaUnitTag $unit_tag for creating entries", 5);
91                                 $main::gosa_unit_tag= $unit_tag;
92                         }
93                 } else {
94                         # Perform another search for Unit Tag
95                         my $hostname= `hostname -f`;
96                         chomp($hostname);
97                         &main::daemon_log("INFO: Searching for servers gosaUnitTag with hostname $hostname",5);
98                         $mesg = $main::ldap_handle->search(
99                                 base   => $ldap_base,
100                                 scope  => 'sub',
101                                 attrs  => ['gosaUnitTag'],
102                                 filter => "(&(cn=$hostname)(objectClass=goServer))"
103                         );
104                         if ($mesg->count == 1) {
105                                 my $entry= $mesg->entry(0);
106                                 my $unit_tag= $entry->get_value("gosaUnitTag");
107                                 if(defined($unit_tag) && length($unit_tag) > 0) {
108                                         &main::daemon_log("INFO: Detected gosaUnitTag $unit_tag for creating entries", 5);
109                                         $main::gosa_unit_tag= $unit_tag;
110                                 }
111                         } else {
112                                 # Perform another search for Unit Tag
113                                 $hostname= `hostname -s`;
114                                 chomp($hostname);
115                                 &main::daemon_log("INFO: Searching for servers gosaUnitTag with hostname $hostname",5);
116                                 $mesg = $main::ldap_handle->search(
117                                         base   => $ldap_base,
118                                         scope  => 'sub',
119                                         attrs  => ['gosaUnitTag'],
120                                         filter => "(&(cn=$hostname)(objectClass=goServer))"
121                                 );
122                                 if ($mesg->count == 1) {
123                                         my $entry= $mesg->entry(0);
124                                         my $unit_tag= $entry->get_value("gosaUnitTag");
125                                         if(defined($unit_tag) && length($unit_tag) > 0) {
126                                                 &main::daemon_log("INFO: Detected gosaUnitTag $unit_tag for creating entries", 5);
127                                                 $main::gosa_unit_tag= $unit_tag;
128                                         }
129                                 } else {
130                                         &main::daemon_log("WARNING: No gosaUnitTag detected. Not using gosaUnitTag", 3);
131                                 }
132                         }
133                 }
134         } else {
135                 &main::daemon_log("INFO: Using gosaUnitTag from config-file: $main::gosa_unit_tag",5);
136         }
140 my $server_address = "$server_ip:$server_port";
141 $main::server_address = $server_address;
144 if( inet_aton($bus_ip) ){ $bus_ip = inet_ntoa(inet_aton($bus_ip)); } 
145 ######################################################
146 # to change
147 if( $bus_ip eq "127.0.1.1" ) { $bus_ip = "127.0.0.1" }
148 ######################################################
149 my $bus_address = "$bus_ip:$bus_port";
150 $main::bus_address = $bus_address;
152 # create general settings for this module
153 my $xml = new XML::Simple();
155 # register at bus
156 if ($main::no_bus > 0) {
157     $bus_activ = "off"
159 if($bus_activ eq "on") {
160     &register_at_bus();
163 # add myself to known_server_db
164 my $res = $main::known_server_db->add_dbentry( {table=>'known_server',
165         primkey=>['hostname'],
166         hostname=>$server_address,
167         status=>'myself',
168         hostkey=>$SIPackages_key,
169         timestamp=>&get_time,
170         } );
174 ### functions #################################################################
177 sub get_module_info {
178     my @info = ($server_address,
179                 $SIPackages_key,
180                 );
181     return \@info;
185 #===  FUNCTION  ================================================================
186 #         NAME:  read_configfile
187 #   PARAMETERS:  cfg_file - string -
188 #      RETURNS:  nothing
189 #  DESCRIPTION:  read cfg_file and set variables
190 #===============================================================================
191 sub read_configfile {
192     my $cfg;
193     if( defined( $main::cfg_file) && ( length($main::cfg_file) > 0 )) {
194         if( -r $main::cfg_file ) {
195             $cfg = Config::IniFiles->new( -file => $main::cfg_file );
196         } else {
197             print STDERR "Couldn't read config file!";
198         }
199     } else {
200         $cfg = Config::IniFiles->new() ;
201     }
202     foreach my $section (keys %cfg_defaults) {
203         foreach my $param (keys %{$cfg_defaults{ $section }}) {
204             my $pinfo = $cfg_defaults{ $section }{ $param };
205             ${@$pinfo[0]} = $cfg->val( $section, $param, @$pinfo[1] );
206         }
207     }
209     # Read non predefined sections
210     my $param;
211     if ($cfg->SectionExists('ldap')){
212                 foreach $param ($cfg->Parameters('ldap')){
213                         push (@ldap_cfg, "$param ".$cfg->val('ldap', $param));
214                 }
215     }
216     if ($cfg->SectionExists('pam_ldap')){
217                 foreach $param ($cfg->Parameters('pam_ldap')){
218                         push (@pam_cfg, "$param ".$cfg->val('pam_ldap', $param));
219                 }
220     }
221     if ($cfg->SectionExists('nss_ldap')){
222                 foreach $param ($cfg->Parameters('nss_ldap')){
223                         push (@nss_cfg, "$param ".$cfg->val('nss_ldap', $param));
224                 }
225     }
226     if ($cfg->SectionExists('goto')){
227         $goto_admin= $cfg->val('goto', 'terminal_admin');
228         $goto_secret= $cfg->val('goto', 'terminal_secret');
229     } else {
230         $goto_admin= undef;
231         $goto_secret= undef;
232     }
236 #===  FUNCTION  ================================================================
237 #         NAME:  get_interface_for_ip
238 #   PARAMETERS:  ip address (i.e. 192.168.0.1)
239 #      RETURNS:  array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else
240 #  DESCRIPTION:  Uses proc fs (/proc/net/dev) to get list of interfaces.
241 #===============================================================================
242 sub get_interface_for_ip {
243         my $result;
244         my $ip= shift;
245         if ($ip && length($ip) > 0) {
246                 my @ifs= &get_interfaces();
247                 if($ip eq "0.0.0.0") {
248                         $result = "all";
249                 } else {
250                         foreach (@ifs) {
251                                 my $if=$_;
252                                 if(get_ip($if) eq $ip) {
253                                         $result = $if;
254                                 }
255                         }       
256                 }
257         }       
258         return $result;
261 #===  FUNCTION  ================================================================
262 #         NAME:  get_interfaces 
263 #   PARAMETERS:  none
264 #      RETURNS:  (list of interfaces) 
265 #  DESCRIPTION:  Uses proc fs (/proc/net/dev) to get list of interfaces.
266 #===============================================================================
267 sub get_interfaces {
268         my @result;
269         my $PROC_NET_DEV= ('/proc/net/dev');
271         open(PROC_NET_DEV, "<$PROC_NET_DEV")
272                 or die "Could not open $PROC_NET_DEV";
274         my @ifs = <PROC_NET_DEV>;
276         close(PROC_NET_DEV);
278         # Eat first two line
279         shift @ifs;
280         shift @ifs;
282         chomp @ifs;
283         foreach my $line(@ifs) {
284                 my $if= (split /:/, $line)[0];
285                 $if =~ s/^\s+//;
286                 push @result, $if;
287         }
289         return @result;
292 #===  FUNCTION  ================================================================
293 #         NAME:  get_mac 
294 #   PARAMETERS:  interface name (i.e. eth0)
295 #      RETURNS:  (mac address) 
296 #  DESCRIPTION:  Uses ioctl to get mac address directly from system.
297 #===============================================================================
298 sub get_mac {
299         my $ifreq= shift;
300         my $result;
301         if ($ifreq && length($ifreq) > 0) { 
302                 if($ifreq eq "all") {
303                         $result = "00:00:00:00:00:00";
304                 } else {
305                         my $SIOCGIFHWADDR= 0x8927;     # man 2 ioctl_list
307                         # A configured MAC Address should always override a guessed value
308                         if ($server_mac_address and length($server_mac_address) > 0) {
309                                 $result= $server_mac_address;
310                         }
312                         socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip')
313                                 or die "socket: $!";
315                         if(ioctl SOCKET, $SIOCGIFHWADDR, $ifreq) {
316                                 my ($if, $mac)= unpack 'h36 H12', $ifreq;
318                                 if (length($mac) > 0) {
319                                         $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])$/;
320                                         $mac= sprintf("%s:%s:%s:%s:%s:%s", $1, $2, $3, $4, $5, $6);
321                                         $result = $mac;
322                                 }
323                         }
324                 }
325         }
326         return $result;
330 #===  FUNCTION  ================================================================
331 #         NAME:  register_at_bus
332 #   PARAMETERS:  nothing
333 #      RETURNS:  nothing
334 #  DESCRIPTION:  creates an entry in known_daemons and send a 'here_i_am' msg to bus
335 #===============================================================================
336 sub register_at_bus {
338     # add bus to known_server_db
339     my $res = $main::known_server_db->add_dbentry( {table=>'known_server',
340                                                     primkey=>['hostname'],
341                                                     hostname=>$bus_address,
342                                                     status=>'bus',
343                                                     hostkey=>$bus_key,
344                                                     timestamp=>&get_time,
345                                                 } );
346     my $msg_hash = &create_xml_hash("here_i_am", $server_address, $bus_address);
347     my $msg = &create_xml_string($msg_hash);
349     &main::send_msg_to_target($msg, $bus_address, $bus_key, "here_i_am");
350     return $msg;
354 sub import_events {
355     if (not -e $event_dir) {
356         &main::daemon_log("ERROR: cannot find directory or directory is not readable: $event_dir", 1);   
357     }
358     opendir (DIR, $event_dir) or die "ERROR while loading gosa-si-events from directory $event_dir : $!\n";
360     while (defined (my $event = readdir (DIR))) {
361         if( $event eq "." || $event eq ".." ) { next; }  
362         if( $event eq "gosaTriggered.pm" ) { next; }    # only GOsa specific events
364         eval{ require $event; };
365         if( $@ ) {
366             &main::daemon_log("import of event module '$event' failed", 1);
367             &main::daemon_log("$@", 8);
368             next;
369         }
371         $event =~ /(\S*?).pm$/;
372         my $event_module = $1;
373         my $events_l = eval( $1."::get_events()") ;
374         foreach my $event_name (@{$events_l}) {
375             $event_hash->{$event_name} = $event_module;
376         }
377         my $events_string = join( ", ", @{$events_l});
378         &main::daemon_log("INFO: SIPackages imported events $events_string", 5);
379     }
383 #===  FUNCTION  ================================================================
384 #         NAME:  process_incoming_msg
385 #   PARAMETERS:  crypted_msg - string - incoming crypted message
386 #      RETURNS:  nothing
387 #  DESCRIPTION:  handels the proceeded distribution to the appropriated functions
388 #===============================================================================
389 sub process_incoming_msg {
390     my ($msg, $msg_hash, $session_id) = @_ ;
391     my $error = 0;
392     my $host_name;
393     my $host_key;
394     my @out_msg_l = ();
396     # process incoming msg
397     my $header = @{$msg_hash->{header}}[0]; 
398     my @target_l = @{$msg_hash->{target}};
400     # skip PREFIX
401     $header =~ s/^CLMSG_//;
403     &main::daemon_log("DEBUG: SIPackages: msg to process: $header", 7);
404     &main::daemon_log("$msg", 8);
406     if( 0 == length @target_l){     
407         &main::daemon_log("ERROR: no target specified for msg $header", 1);
408         $error++;
409     }
411     if( 1 == length @target_l) {
412         my $target = $target_l[0];
413                 if(&server_matches($target)) {
416             if ($header eq 'new_key') {
417                 @out_msg_l = &new_key($msg_hash)
418             } elsif ($header eq 'here_i_am') {
419                 @out_msg_l = &here_i_am($msg_hash)
420             } else {
421                 if( exists $event_hash->{$header} ) {
422                     # a event exists with the header as name
423                     &main::daemon_log("INFO: found event '$header' at event-module '".$event_hash->{$header}."'", 5);
424                     no strict 'refs';
425                     @out_msg_l = &{$event_hash->{$header}."::$header"}($msg, $msg_hash, $session_id);
426                 }
427             }
429             # if delivery not possible raise error and return 
430             if( not @out_msg_l ) {
431                 &main::daemon_log("WARNING: SIPackages got not answer from event handler '$header'", 3);
432             } elsif( 0 == @out_msg_l) {
433                 &main::daemon_log("ERROR: SIPackages: no event handler or core function defined for '$header'", 1);
434             } 
435         }
436                 else {
437                         &main::daemon_log("INFO: msg is not for gosa-si-server '$server_address', deliver it to target '$target'", 5);
438                         push(@out_msg_l, $msg);
439                 }
440     }
442     return \@out_msg_l;
446 #===  FUNCTION  ================================================================
447 #         NAME:  new_passwd
448 #   PARAMETERS:  msg_hash - ref - hash from function create_xml_hash
449 #      RETURNS:  nothing
450 #  DESCRIPTION:  process this incoming message
451 #===============================================================================
452 sub new_key {
453     my ($msg_hash) = @_;
454     my @out_msg_l;
455     
456     my $header = @{$msg_hash->{header}}[0];
457     my $source_name = @{$msg_hash->{source}}[0];
458     my $source_key = @{$msg_hash->{new_key}}[0];
459     my $query_res;
461     # check known_clients_db
462     my $sql_statement = "SELECT * FROM known_clients WHERE hostname='$source_name'";
463     $query_res = $main::known_clients_db->select_dbentry( $sql_statement );
464     if( 1 == keys %{$query_res} ) {
465         my $act_time = &get_time;
466         my $sql_statement= "UPDATE known_clients ".
467             "SET hostkey='$source_key', timestamp='$act_time' ".
468             "WHERE hostname='$source_name'";
469         my $res = $main::known_clients_db->update_dbentry( $sql_statement );
470         my $hash = &create_xml_hash("confirm_new_key", $server_address, $source_name);
471         my $out_msg = &create_xml_string($hash);
472         push(@out_msg_l, $out_msg);
473     }
475     # only do if host still not found
476     if( 0 == @out_msg_l ) {
477         # check known_server_db
478         $sql_statement = "SELECT * FROM known_server WHERE hostname='$source_name'";
479         $query_res = $main::known_server_db->select_dbentry( $sql_statement );
480         if( 1 == keys %{$query_res} ) {
481             my $act_time = &get_time;
482             my $sql_statement= "UPDATE known_server ".
483                 "SET hostkey='$source_key', timestamp='$act_time' ".
484                 "WHERE hostname='$source_name'";
485             my $res = $main::known_server_db->update_dbentry( $sql_statement );
487             my $hash = &create_xml_hash("confirm_new_key", $server_address, $source_name);
488             my $out_msg = &create_xml_string($hash);
489             push(@out_msg_l, $out_msg);
490         }
491     }
493     return @out_msg_l;
497 #===  FUNCTION  ================================================================
498 #         NAME:  here_i_am
499 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
500 #      RETURNS:  nothing
501 #  DESCRIPTION:  process this incoming message
502 #===============================================================================
503 sub here_i_am {
504     my ($msg_hash) = @_;
505     my @out_msg_l;
506     my $out_hash;
508     my $source = @{$msg_hash->{source}}[0];
509     my $mac_address = @{$msg_hash->{mac_address}}[0];
510         my $gotoHardwareChecksum = @{$msg_hash->{gotoHardwareChecksum}}[0];
512     # number of known clients
513     my $nu_clients= $main::known_clients_db->count_dbentries('known_clients');
515     # check wether client address or mac address is already known
516     my $sql_statement= "SELECT * FROM known_clients WHERE hostname='$source'";
517     my $db_res= $main::known_clients_db->select_dbentry( $sql_statement );
518     
519     if ( 1 == keys %{$db_res} ) {
520         &main::daemon_log("WARNING: $source is already known as a client", 1);
521         &main::daemon_log("WARNING: values for $source are being overwritten", 1);   
522         $nu_clients --;
523     }
525     # number of actual activ clients
526     my $act_nu_clients = $nu_clients;
528     &main::daemon_log("INFO: number of actual activ clients: $act_nu_clients", 5);
529     &main::daemon_log("INFO: number of maximal allowed clients: $max_clients", 5);
531     if($max_clients <= $act_nu_clients) {
532         my $out_hash = &create_xml_hash("denied", $server_address, $source);
533         &add_content2xml_hash($out_hash, "denied", "I_cannot_take_any_more_clients!");
534         my $passwd = @{$msg_hash->{new_passwd}}[0]; 
535         &send_msg_hash2address($out_hash, $source, $passwd);
536         return;
537     }
538     
539     # new client accepted
540     my $new_passwd = @{$msg_hash->{new_passwd}}[0];
542     # create entry in known_clients
543     my $events = @{$msg_hash->{events}}[0];
544     
546     # add entry to known_clients_db
547     my $act_timestamp = &get_time;
548     my $res = $main::known_clients_db->add_dbentry( {table=>'known_clients', 
549                                                 primkey=>['hostname'],
550                                                 hostname=>$source,
551                                                 events=>$events,
552                                                 macaddress=>$mac_address,
553                                                 status=>'registered',
554                                                 hostkey=>$new_passwd,
555                                                 timestamp=>$act_timestamp,
556                                                 } );
558     if ($res != 0)  {
559         &main::daemon_log("ERROR: cannot add entry to known_clients: $res");
560         return;
561     }
562     
563     # return acknowledgement to client
564     $out_hash = &create_xml_hash("registered", $server_address, $source);
565     my $register_out = &create_xml_string($out_hash);
566     push(@out_msg_l, $register_out);
568     # notify registered client to bus
569     if( $bus_activ eq "on") {
570         # fetch actual bus key
571         my $sql_statement= "SELECT * FROM known_server WHERE status='bus'";
572         my $query_res = $main::known_server_db->select_dbentry( $sql_statement );
573         my $hostkey = $query_res->{1}->{'hostkey'};
575         # send update msg to bus
576         $out_hash = &create_xml_hash("new_client", $server_address, $bus_address, $source);
577         &add_content2xml_hash($out_hash, "macaddress", $mac_address);
578         &add_content2xml_hash($out_hash, "timestamp", $act_timestamp);
579         my $new_client_out = &create_xml_string($out_hash);
580         push(@out_msg_l, $new_client_out);
581         &main::daemon_log("INFO: send bus msg that client '$source' has registerd at server '$server_address'", 5);
582     }
584     # give the new client his ldap config
585     my $new_ldap_config_out = &new_ldap_config($source);
586     if( $new_ldap_config_out ) {
587         push(@out_msg_l, $new_ldap_config_out);
588     }
590         my $hardware_config_out = &hardware_config($source, $gotoHardwareChecksum);
591         if( $hardware_config_out ) {
592                 push(@out_msg_l, $hardware_config_out);
593         }
595     return @out_msg_l;
599 #===  FUNCTION  ================================================================
600 #         NAME:  who_has
601 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
602 #      RETURNS:  nothing 
603 #  DESCRIPTION:  process this incoming message
604 #===============================================================================
605 sub who_has {
606     my ($msg_hash) = @_ ;
607     my @out_msg_l;
608     
609     # what is your search pattern
610     my $search_pattern = @{$msg_hash->{who_has}}[0];
611     my $search_element = @{$msg_hash->{$search_pattern}}[0];
612     &main::daemon_log("who_has-msg looking for $search_pattern $search_element", 7);
614     # scanning known_clients for search_pattern
615     my @host_addresses = keys %$main::known_clients;
616     my $known_clients_entries = length @host_addresses;
617     my $host_address;
618     foreach my $host (@host_addresses) {
619         my $client_element = $main::known_clients->{$host}->{$search_pattern};
620         if ($search_element eq $client_element) {
621             $host_address = $host;
622             last;
623         }
624     }
625         
626     # search was successful
627     if (defined $host_address) {
628         my $source = @{$msg_hash->{source}}[0];
629         my $out_hash = &create_xml_hash("who_has_i_do", $server_address, $source, "mac_address");
630         &add_content2xml_hash($out_hash, "mac_address", $search_element);
631         my $out_msg = &create_xml_string($out_hash);
632         push(@out_msg_l, $out_msg);
633     }
634     return @out_msg_l;
638 sub who_has_i_do {
639     my ($msg_hash) = @_ ;
640     my $header = @{$msg_hash->{header}}[0];
641     my $source = @{$msg_hash->{source}}[0];
642     my $search_param = @{$msg_hash->{$header}}[0];
643     my $search_value = @{$msg_hash->{$search_param}}[0];
644     print "\ngot msg $header:\nserver $source has client with $search_param $search_value\n";
648 #===  FUNCTION  ================================================================
649 #         NAME:  new_ldap_config
650 #   PARAMETERS:  address - string - ip address and port of a host
651 #      RETURNS:  gosa-si conform message
652 #  DESCRIPTION:  send to address the ldap configuration found for dn gotoLdapServer
653 #===============================================================================
654 sub new_ldap_config {
655         my ($address) = @_ ;
657         my $sql_statement= "SELECT * FROM known_clients WHERE hostname='$address' OR macaddress='$address'";
658         my $res = $main::known_clients_db->select_dbentry( $sql_statement );
660         # check hit
661         my $hit_counter = keys %{$res};
662         if( not $hit_counter == 1 ) {
663                 &main::daemon_log("ERROR: more or no hit found in known_clients_db by query by '$address'", 1);
664         }
666     $address = $res->{1}->{hostname};
667         my $macaddress = $res->{1}->{macaddress};
668         my $hostkey = $res->{1}->{hostkey};
670         if (not defined $macaddress) {
671                 &main::daemon_log("ERROR: no mac address found for client $address", 1);
672                 return;
673         }
675         # Build LDAP connection
676   &main::refresh_ldap_handle();
677         if( not defined $main::ldap_handle ) {
678                 &main::daemon_log("ERROR: cannot connect to ldap: $ldap_uri", 1);
679                 return;
680         } 
682         # Perform search
683         $mesg = $main::ldap_handle->search( base   => $ldap_base,
684                 scope  => 'sub',
685                 attrs => ['dn', 'gotoLdapServer', 'gosaUnitTag', 'FAIclass'],
686                 filter => "(&(objectClass=GOhard)(macaddress=$macaddress)(gotoMode=active))");
687         #$mesg->code && die $mesg->error;
688         if($mesg->code) {
689                 &main::daemon_log($mesg->error, 1);
690                 return;
691         }
693         # Sanity check
694         if ($mesg->count != 1) {
695                 &main::daemon_log("WARNING: client with mac address $macaddress not found/unique/active - not sending ldap config", 1);
696                 &main::daemon_log("\tbase: $ldap_base", 1);
697                 &main::daemon_log("\tscope: sub", 1);
698                 &main::daemon_log("\tattrs: dn, gotoLdapServer", 1);
699                 &main::daemon_log("\tfilter: (&(objectClass=GOhard)(macaddress=$macaddress))", 1);
700                 return;
701         }
703         my $entry= $mesg->entry(0);
704         my $dn= $entry->dn;
705         my @servers= $entry->get_value("gotoLdapServer");
706         my $unit_tag= $entry->get_value("gosaUnitTag");
707         my @ldap_uris;
708         my $server;
709         my $base;
710         my $release;
712         # Fill release if available
713         my $FAIclass= $entry->get_value("FAIclass");
714         if (defined $FAIclass && $FAIclass =~ /^.* :([A-Za-z0-9\/.]+).*$/) {
715                 $release= $1;
716         }
718         # Do we need to look at an object class?
719         if (length(@servers) < 1){
720                 $mesg = $main::ldap_handle->search( base   => $ldap_base,
721                         scope  => 'sub',
722                         attrs => ['dn', 'gotoLdapServer', 'FAIclass'],
723                         filter => "(&(objectClass=gosaGroupOfNames)(member=$dn))");
724                 #$mesg->code && die $mesg->error;
725                 if($mesg->code) {
726                         &main::daemon_log($mesg->error, 1);
727                         return;
728                 }
730                 # Sanity check
731                 if ($mesg->count != 1) {
732                         &main::daemon_log("WARNING: no LDAP information found for client mac $macaddress", 1);
733                         return;
734                 }
736                 $entry= $mesg->entry(0);
737                 $dn= $entry->dn;
738                 @servers= $entry->get_value("gotoLdapServer");
740                 if (not defined $release){
741                         $FAIclass= $entry->get_value("FAIclass");
742                         if (defined $FAIclass && $FAIclass =~ /^.* :([A-Za-z0-9\/.]+).*$/) {
743                                 $release= $1;
744                         }
745                 }
746         }
748         @servers= sort (@servers);
750         foreach $server (@servers){
751                 # Conversation for backward compatibility
752                 if (not $server =~ /^\d+:[^:]+:ldap[^:]*:\/\// ) {
753                     if ($server =~ /^([^:]+):(.*)$/ ) {
754                       $server= "1:dummy:ldap://$1/$2";
755                     }
756                 }
758                 $base= $server;
759                 $server =~ s%^[^:]+:[^:]+:(ldap.*://[^/]+)/.*$%$1%;
760                 $base =~ s%^[^:]+:[^:]+:ldap.*://[^/]+/(.*)$%$1%;
761                 push (@ldap_uris, $server);
762         }
764         # Assemble data package
765         my %data = ( 'ldap_uri'  => \@ldap_uris, 'ldap_base' => $base,
766                 'ldap_cfg' => \@ldap_cfg, 'pam_cfg' => \@pam_cfg,'nss_cfg' => \@nss_cfg );
767         if (defined $release){
768                 $data{'release'}= $release;
769         }
771         # Need to append GOto settings?
772         if (defined $goto_admin and defined $goto_secret){
773                 $data{'goto_admin'}= $goto_admin;
774                 $data{'goto_secret'}= $goto_secret;
775         }
777         # Append unit tag if needed
778         if (defined $unit_tag){
780                 # Find admin base and department name
781                 $mesg = $main::ldap_handle->search( base   => $ldap_base,
782                         scope  => 'sub',
783                         attrs => ['dn', 'ou'],
784                         filter => "(&(objectClass=gosaAdministrativeUnit)(gosaUnitTag=$unit_tag))");
785                 #$mesg->code && die $mesg->error;
786                 if($mesg->code) {
787                         &main::daemon_log($mesg->error, 1);
788                         return;
789                 }
791                 # Sanity check
792                 if ($mesg->count != 1) {
793                         &main::daemon_log("WARNING: cannot find administrative unit for client with tag $unit_tag", 1);
794                         return;
795                 }
797                 $entry= $mesg->entry(0);
798                 $data{'admin_base'}= $entry->dn;
799                 $data{'department'}= $entry->get_value("ou");
801                 # Append unit Tag
802                 $data{'unit_tag'}= $unit_tag;
803         }
805         # Send information
806         return &build_msg("new_ldap_config", $server_address, $address, \%data);
810 #===  FUNCTION  ================================================================
811 #         NAME:  hardware_config
812 #   PARAMETERS:  address - string - ip address and port of a host
813 #      RETURNS:  
814 #  DESCRIPTION:  
815 #===============================================================================
816 sub hardware_config {
817         my ($address, $gotoHardwareChecksum) = @_ ;
819         my $sql_statement= "SELECT * FROM known_clients WHERE hostname='$address'";
820         my $res = $main::known_clients_db->select_dbentry( $sql_statement );
822         # check hit
823         my $hit_counter = keys %{$res};
824         if( not $hit_counter == 1 ) {
825                 &main::daemon_log("ERROR: more or no hit found in known_clients_db by query by '$address'", 1);
826         }
828         my $macaddress = $res->{1}->{macaddress};
829         my $hostkey = $res->{1}->{hostkey};
831         if (not defined $macaddress) {
832                 &main::daemon_log("ERROR: no mac address found for client $address", 1);
833                 return;
834         }
836         # Build LDAP connection
837   &main::refresh_ldap_handle();
838         if( not defined $main::ldap_handle ) {
839                 &main::daemon_log("ERROR: cannot connect to ldap: $ldap_uri", 1);
840                 return;
841         } 
843         # Perform search
844         $mesg = $main::ldap_handle->search(
845                 base   => $ldap_base,
846                 scope  => 'sub',
847                 filter => "(&(objectClass=GOhard)(|(macAddress=$macaddress)(dhcpHWaddress=ethernet $macaddress)))"
848         );
850         if($mesg->count() == 0) {
851                 &main::daemon_log("Host was not found in LDAP!", 1);
852         } else {
853                 my $entry= $mesg->entry(0);
854                 my $dn= $entry->dn;
855                 if(defined($entry->get_value("gotoHardwareChecksum"))) {
856                         if(! $entry->get_value("gotoHardwareChecksum") eq $gotoHardwareChecksum) {
857                                 $entry->replace(gotoHardwareChecksum => $gotoHardwareChecksum);
858                                 if($entry->update($main::ldap_handle)) {
859                                         &main::daemon_log("Hardware changed! Detection triggered.", 4);
860                                 }
861                         } else {
862                                 # Nothing to do
863                                 return;
864                         }
865                 }
866         } 
868         # Assemble data package
869         my %data = ();
871         # Need to append GOto settings?
872         if (defined $goto_admin and defined $goto_secret){
873                 $data{'goto_admin'}= $goto_admin;
874                 $data{'goto_secret'}= $goto_secret;
875         }
877         &main::daemon_log("Send detect_hardware message to $address", 4);
879         # Send information
880         return &build_msg("detect_hardware", $server_address, $address, \%data);
883 sub server_matches {
884         my $target = shift;
885         my $target_ip = sprintf("%s", $target =~ /^([0-9\.]*?):.*$/);
886         my $result = 0;
888         if($server_ip eq $target_ip) {
889                 $result= 1;
890         } elsif ($server_ip eq "0.0.0.0") {     
891                 if ($target_ip eq "127.0.0.1") {
892                         $result= 1;
893                 } else {
894                         my $PROC_NET_ROUTE= ('/proc/net/route');
896                         open(PROC_NET_ROUTE, "<$PROC_NET_ROUTE")
897                                 or die "Could not open $PROC_NET_ROUTE";
899                         my @ifs = <PROC_NET_ROUTE>;
901                         close(PROC_NET_ROUTE);
903                         # Eat header line
904                         shift @ifs;
905                         chomp @ifs;
906                         foreach my $line(@ifs) {
907                                 my ($Iface,$Destination,$Gateway,$Flags,$RefCnt,$Use,$Metric,$Mask,$MTU,$Window,$IRTT)=split(/\s/, $line);
908                                 my $destination;
909                                 my $mask;
910                                 my ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Destination);
911                                 $destination= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d));
912                                 ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Mask);
913                                 $mask= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d));
914                                 if(new NetAddr::IP($target_ip)->within(new NetAddr::IP($destination, $mask))) {
915                                         # destination matches route, save mac and exit
916                                         $result= 1;
917                                         last;
918                                 }
919                         }
920                 }
921         } else {
922                 &main::daemon_log("Target ip $target_ip does not match Server ip $server_ip",1);
923         }
925         return $result;
928 1;