Code

Moved to gosa-si
[gosa.git] / gosa-si / modules / ServerPackages.pm
1 package ServerPackages;
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 Net::LDAP;
16 use Socket qw/PF_INET SOCK_DGRAM inet_ntoa sockaddr_in/;
18 BEGIN{}
19 END {}
21 my ($known_clients_file_name);
22 my ($server_activ, $server_ip, $server_mac_address, $server_port, $server_passwd, $max_clients, $ldap_uri, $ldap_base, $ldap_admin_dn, $ldap_admin_password);
23 my ($bus_activ, $bus_passwd, $bus_ip, $bus_port);
24 my $server;
25 my $network_interface;
26 my $no_bus;
27 my (@ldap_cfg, @pam_cfg, @nss_cfg, $goto_admin, $goto_secret);
30 my %cfg_defaults =
31 (
32 "server" =>
33     {"server_activ" => [\$server_activ, "on"],
34     "server_ip" => [\$server_ip, "0.0.0.0"],
35     "server_mac_address" => [\$server_mac_address, ""],
36     "server_port" => [\$server_port, "20081"],
37     "server_passwd" => [\$server_passwd, ""],
38     "max_clients" => [\$max_clients, 100],
39     "ldap_uri" => [\$ldap_uri, ""],
40     "ldap_base" => [\$ldap_base, ""],
41     "ldap_admin_dn" => [\$ldap_admin_dn, ""],
42     "ldap_admin_password" => [\$ldap_admin_password, ""],
43     },
44 "bus" =>
45     {"bus_activ" => [\$bus_activ, "on"],
46     "bus_passwd" => [\$bus_passwd, ""],
47     "bus_ip" => [\$bus_ip, ""],
48     "bus_port" => [\$bus_port, "20080"],
49     },
50 );
52 ### START #####################################################################
54 # read configfile and import variables
55 &read_configfile();
57 # detect interfaces and mac address
58 $network_interface= &get_interface_for_ip($server_ip);
59 $server_mac_address= &get_mac($network_interface); 
61 &main::daemon_log("server ip address detected: $server_ip", 1);
62 &main::daemon_log("server mac address detected: $server_mac_address", 1);
64 # complete addresses
65 my $server_address = "$server_ip:$server_port";
66 my $bus_address = "$bus_ip:$bus_port";
68 # create general settings for this module
69 my $xml = new XML::Simple();
71 ## open server socket
72 #if($server_activ eq "on"){
73 #    &main::daemon_log(" ", 1);
74 #    $server = IO::Socket::INET->new(LocalPort => $server_port,
75 #            Type => SOCK_STREAM,
76 #            Reuse => 1,
77 #            Listen => 20,
78 #            ); 
79 #    if(not defined $server){
80 #        &main::daemon_log("cannot be a tcp server at $server_port : $@");
81 #        die;
82 #    } else {
83 #        &main::daemon_log("start server: $server_address", 1);
84 #    }
85 #}
86 #
87 #
88 ## register at bus
89 #if ($main::no_bus > 0) {
90 #    $bus_activ = "off"
91 #}
92 #if($bus_activ eq "on") {
93 #    &main::daemon_log(" ", 1);
94 #    &register_at_bus();
95 #}
97 ### functions #################################################################
100 sub get_module_info {
101     my @info = ($server_address,
102                 $server_passwd,
103                 $server,
104                 $server_activ,
105                 "socket",
106                 );
107     return \@info;
111 #===  FUNCTION  ================================================================
112 #         NAME:  read_configfile
113 #   PARAMETERS:  cfg_file - string -
114 #      RETURNS:  nothing
115 #  DESCRIPTION:  read cfg_file and set variables
116 #===============================================================================
117 sub read_configfile {
118     my $cfg;
119     if( defined( $main::cfg_file) && ( length($main::cfg_file) > 0 )) {
120         if( -r $main::cfg_file ) {
121             $cfg = Config::IniFiles->new( -file => $main::cfg_file );
122         } else {
123             print STDERR "Couldn't read config file!";
124         }
125     } else {
126         $cfg = Config::IniFiles->new() ;
127     }
128     foreach my $section (keys %cfg_defaults) {
129         foreach my $param (keys %{$cfg_defaults{ $section }}) {
130             my $pinfo = $cfg_defaults{ $section }{ $param };
131             ${@$pinfo[0]} = $cfg->val( $section, $param, @$pinfo[1] );
132         }
133     }
135     # Read non predefined sections
136     my $param;
137     if ($cfg->SectionExists('ldap')){
138                 foreach $param ($cfg->Parameters('ldap')){
139                         push (@ldap_cfg, "$param ".$cfg->val('ldap', $param));
140                 }
141     }
142     if ($cfg->SectionExists('pam_ldap')){
143                 foreach $param ($cfg->Parameters('pam_ldap')){
144                         push (@pam_cfg, "$param ".$cfg->val('pam_ldap', $param));
145                 }
146     }
147     if ($cfg->SectionExists('nss_ldap')){
148                 foreach $param ($cfg->Parameters('nss_ldap')){
149                         push (@nss_cfg, "$param ".$cfg->val('nss_ldap', $param));
150                 }
151     }
152     if ($cfg->SectionExists('goto')){
153         $goto_admin= $cfg->val('goto', 'terminal_admin');
154         $goto_secret= $cfg->val('goto', 'terminal_secret');
155     } else {
156         $goto_admin= undef;
157         $goto_secret= undef;
158     }
162 #===  FUNCTION  ================================================================
163 #         NAME:  get_interface_for_ip
164 #   PARAMETERS:  ip address (i.e. 192.168.0.1)
165 #      RETURNS:  array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else
166 #  DESCRIPTION:  Uses proc fs (/proc/net/dev) to get list of interfaces.
167 #===============================================================================
168 sub get_interface_for_ip {
169         my $result;
170         my $ip= shift;
171         if ($ip && length($ip) > 0) {
172                 my @ifs= &get_interfaces();
173                 if($ip eq "0.0.0.0") {
174                         $result = "all";
175                 } else {
176                         foreach (@ifs) {
177                                 my $if=$_;
178                                 if(get_ip($if) eq $ip) {
179                                         $result = $if;
180                                 }
181                         }       
182                 }
183         }       
184         return $result;
187 #===  FUNCTION  ================================================================
188 #         NAME:  get_interfaces 
189 #   PARAMETERS:  none
190 #      RETURNS:  (list of interfaces) 
191 #  DESCRIPTION:  Uses proc fs (/proc/net/dev) to get list of interfaces.
192 #===============================================================================
193 sub get_interfaces {
194         my @result;
195         my $PROC_NET_DEV= ('/proc/net/dev');
197         open(PROC_NET_DEV, "<$PROC_NET_DEV")
198                 or die "Could not open $PROC_NET_DEV";
200         my @ifs = <PROC_NET_DEV>;
202         close(PROC_NET_DEV);
204         # Eat first two line
205         shift @ifs;
206         shift @ifs;
208         chomp @ifs;
209         foreach my $line(@ifs) {
210                 my $if= (split /:/, $line)[0];
211                 $if =~ s/^\s+//;
212                 push @result, $if;
213         }
215         return @result;
218 #===  FUNCTION  ================================================================
219 #         NAME:  get_mac 
220 #   PARAMETERS:  interface name (i.e. eth0)
221 #      RETURNS:  (mac address) 
222 #  DESCRIPTION:  Uses ioctl to get mac address directly from system.
223 #===============================================================================
224 sub get_mac {
225         my $ifreq= shift;
226         my $result;
227         if ($ifreq && length($ifreq) > 0) { 
228                 if($ifreq eq "all") {
229                         $result = "00:00:00:00:00:00";
230                 } else {
231                         my $SIOCGIFHWADDR= 0x8927;     # man 2 ioctl_list
233                         # A configured MAC Address should always override a guessed value
234                         if ($server_mac_address and length($server_mac_address) > 0) {
235                                 $result= $server_mac_address;
236                         }
238                         socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip')
239                                 or die "socket: $!";
241                         if(ioctl SOCKET, $SIOCGIFHWADDR, $ifreq) {
242                                 my ($if, $mac)= unpack 'h36 H12', $ifreq;
244                                 if (length($mac) > 0) {
245                                         $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])$/;
246                                         $mac= sprintf("%s:%s:%s:%s:%s:%s", $1, $2, $3, $4, $5, $6);
247                                         $result = $mac;
248                                 }
249                         }
250                 }
251         }
252         return $result;
255 #===  FUNCTION  ================================================================
256 #         NAME:  get_ip 
257 #   PARAMETERS:  interface name (i.e. eth0)
258 #      RETURNS:  (ip address) 
259 #  DESCRIPTION:  Uses ioctl to get ip address directly from system.
260 #===============================================================================
261 sub get_ip {
262         my $ifreq= shift;
263         my $result= "";
264         my $SIOCGIFADDR= 0x8915;       # man 2 ioctl_list
265         my $proto= getprotobyname('ip');
267         socket SOCKET, PF_INET, SOCK_DGRAM, $proto
268                 or die "socket: $!";
270         if(ioctl SOCKET, $SIOCGIFADDR, $ifreq) {
271                 my ($if, $sin)    = unpack 'a16 a16', $ifreq;
272                 my ($port, $addr) = sockaddr_in $sin;
273                 my $ip            = inet_ntoa $addr;
275                 if ($ip && length($ip) > 0) {
276                         $result = $ip;
277                 }
278         }
280         return $result;
283 #===  FUNCTION  ================================================================
284 #         NAME:  open_socket
285 #   PARAMETERS:  PeerAddr string something like 192.168.1.1 or 192.168.1.1:10000
286 #                [PeerPort] string necessary if port not appended by PeerAddr
287 #      RETURNS:  socket IO::Socket::INET
288 #  DESCRIPTION:  open a socket to PeerAddr
289 #===============================================================================
290 #sub open_socket {
291 #    my ($PeerAddr, $PeerPort) = @_ ;
292 #    if(defined($PeerPort)){
293 #        $PeerAddr = $PeerAddr.":".$PeerPort;
294 #    }
295 #    my $socket;
296 #    $socket = new IO::Socket::INET(PeerAddr => $PeerAddr ,
297 #            Porto => "tcp" ,
298 #            Type => SOCK_STREAM,
299 #            Timeout => 5,
300 #            );
301 #    if(not defined $socket) {
302 #        return;
303 #    }
304 #    &main::daemon_log("open_socket to: $PeerAddr", 7);
305 #    return $socket;
306 #}
308 #===  FUNCTION  ================================================================
309 #         NAME:  register_at_bus
310 #   PARAMETERS:  nothing
311 #      RETURNS:  nothing
312 #  DESCRIPTION:  creates an entry in known_daemons and send a 'here_i_am' msg to bus
313 #===============================================================================
314 sub register_at_bus {
316     # add bus to known_server_db
317     my $res = $main::known_server_db->add_dbentry( {table=>'known_server',
318                                                     primkey=>'hostname',
319                                                     hostname=>$bus_address,
320                                                     status=>'bus',
321                                                     hostkey=>$bus_passwd,
322                                                     timestamp=>&get_time,
323                                                 } );
324     my $msg_hash = &create_xml_hash("here_i_am", $server_address, $bus_address);
325     my $answer = "";
326     $answer = &send_msg_hash2address($msg_hash, $bus_address, $bus_passwd);
327     if ($answer == 0) {
328         &main::daemon_log("register at bus: $bus_address", 1);
329     } else {
330         &main::daemon_log("unable to send 'register'-msg to bus '$bus_address': $answer", 1);
331     }
332     return;
335 #===  FUNCTION  ================================================================
336 #         NAME:  process_incoming_msg
337 #   PARAMETERS:  crypted_msg - string - incoming crypted message
338 #      RETURNS:  nothing
339 #  DESCRIPTION:  handels the proceeded distribution to the appropriated functions
340 #===============================================================================
341 sub process_incoming_msg {
342     my ($crypted_msg) = @_ ;
343     if(not defined $crypted_msg) {
344         &main::daemon_log("function 'process_incoming_msg': got no msg", 7);
345     }
347     &main::daemon_log("ServerPackages: incoming msg: \n$crypted_msg", 8);
349     $crypted_msg =~ /^([\s\S]*?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)$/;
350     $crypted_msg = $1;
351         my $host="0.0.0.0";
352         if($1 && $2 && $3 && $4) {
353                 $host = sprintf("%s.%s.%s.%s", $2, $3, $4, $5);
354         }
356     my $msg;
357     my $msg_hash;
358     my $host_name;
359     my $host_key;
361     # check wether incoming msg is a new msg
362     $host_name = $server_address;
363     $host_key = $server_passwd;
364     &main::daemon_log("ServerPackage: host_name: $host_name", 7);
365     &main::daemon_log("ServerPackage: host_key: $host_key", 7);
366     eval{
367         my $key_cipher = &create_ciphering($host_key);
368                 $msg = &decrypt_msg($crypted_msg, $key_cipher);
369         $msg_hash = &transform_msg2hash($msg);
370     };
371     if($@) {
372         &main::daemon_log("ServerPackage: deciphering raise error", 7);
373         &main::daemon_log("$@", 8);
374         $msg = undef;
375         $msg_hash = undef;
376         $host_name = undef;
377         $host_key = undef;
378     } 
380     # check wether incoming msg is from a known_server
381     if( not defined $msg ) {
382         my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server'} ); 
383         while( my ($hit_num, $hit) = each %{ $query_res } ) {  
384             $host_name = $hit->{hostname};
385             if( not $host_name =~ "^$host") {
386                 next;
387             }
388             $host_key = $hit->{hostkey};
389             &main::daemon_log("ServerPackage: host_name: $host_name", 7);
390             &main::daemon_log("ServerPackage: host_key: $host_key", 7);
391             eval{
392                 my $key_cipher = &create_ciphering($host_key);
393                 $msg = &decrypt_msg($crypted_msg, $key_cipher);
394                 $msg_hash = &transform_msg2hash($msg);
395             };
396             if($@) {
397                 &main::daemon_log("ServerPackage: deciphering raise error", 7);
398                 &main::daemon_log("$@", 8);
399                 $msg = undef;
400                 $msg_hash = undef;
401                 $host_name = undef;
402                 $host_key = undef;
403             } else {
404                 last;
405             }
406         }
407     }
409     # check wether incoming msg is from a known_client
410     if( not defined $msg ) {
411         my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients'} ); 
412         while( my ($hit_num, $hit) = each %{ $query_res } ) {    
413             $host_name = $hit->{hostname};
414             if( not $host_name =~ "^$host") {
415                 next;
416             }
417             $host_key = $hit->{hostkey};
418             &main::daemon_log("ServerPackage: host_name: $host_name", 7);
419             &main::daemon_log("ServerPackage: host_key: $host_key", 7);
420             eval{
421                 my $key_cipher = &create_ciphering($host_key);
422                 $msg = &decrypt_msg($crypted_msg, $key_cipher);
423                 $msg_hash = &transform_msg2hash($msg);
424             };
425             if($@) {
426                 &main::daemon_log("ServerPackage: deciphering raise error", 7);
427                 &main::daemon_log("$@", 8);
428                 $msg = undef;
429                 $msg_hash = undef;
430                 $host_name = undef;
431                 $host_key = undef;
432             } else {
433                 last;
434             }
435         }
436     }
438     if( not defined $msg ) {
439         &main::daemon_log("WARNING: ServerPackage do not understand the message:", 5);
440         &main::daemon_log("$@", 7);
441         return;
442     }
444     # process incoming msg
445     my $header = @{$msg_hash->{header}}[0]; 
446     my $source = @{$msg_hash->{source}}[0];
448     &main::daemon_log("receive '$header' at ServerPackages from $host", 1);
449     &main::daemon_log("ServerPackages: msg to process: \n$msg", 5);
451     my @targets = @{$msg_hash->{target}};
452     my $len_targets = @targets;
453     if ($len_targets == 0){     
454         &main::daemon_log("ERROR: ServerPackages: no target specified for msg $header", 1);
456     }  elsif ($len_targets == 1){
457         # we have only one target symbol
458         my $target = $targets[0];
459         &main::daemon_log("SeverPackages: msg is for: $target", 7);
461         # msg is for server
462         if ($header eq 'new_passwd'){ &new_passwd($msg_hash)}
463         elsif ($header eq 'here_i_am') { &here_i_am($msg_hash)}
464         elsif ($header eq 'who_has') { &who_has($msg_hash) }
465         elsif ($header eq 'who_has_i_do') { &who_has_i_do($msg_hash)}
466         elsif ($header eq 'update_status') { &update_status($msg_hash) }
467         elsif ($header eq 'got_ping') { &got_ping($msg_hash)}
468         elsif ($header eq 'get_load') { &execute_actions($msg_hash)}
469         else { 
470             if ($target eq "*") {
471                 # msg is for all clients
472                 my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients'} ); 
473                 while( my ($hit_num, $hit) = each %{ $query_res } ) {    
474                     $host_name = $hit->{hostname};
475                     $host_key = $hit->{hostkey};
476                     $msg_hash->{target} = [$host_name];
477                     &send_msg_hash2address($msg_hash, $host_name, $host_key);
478                 }
480             } else {
481                 # msg is for one host
482                 my $host_key;
485                 if( not defined $host_key ) {
486                     my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients', hostname=>$target} );
487                     if( 1 == keys %{$query_res} ) {
488                         $host_key = $query_res->{1}->{host_key};
489                     }
490                 } 
492                 if( not defined $host_key ) {
493                     my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server', hostname=>$target} );
494                     if( 1 == keys %{$query_res} ) {
495                         $host_key = $query_res->{1}->{host_key};
496                     }
497                 }
499                 if( not defined $host_key ) { 
500                     &main::daemon_log("ERROR: ServerPackages: target '".$target.
501                             "' is not known neither in known_clients nor in known_server",1);
502                 } else {
503                     &send_msg_hash2address($msg_hash, $target, $host_key);
504                 }               
505             }
506         }
508     } elsif ($len_targets > 1 ) {
509         # we have more than one target 
510         # TODO to be implemented
511     }
513     return ;
517 #===  FUNCTION  ================================================================
518 #         NAME:  got_ping
519 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
520 #      RETURNS:  nothing
521 #  DESCRIPTION:  process this incoming message
522 #===============================================================================
523 sub got_ping {
524     my ($msg_hash) = @_;
525     
526     my $source = @{$msg_hash->{source}}[0];
527     my $target = @{$msg_hash->{target}}[0];
528     my $header = @{$msg_hash->{header}}[0];
529     
530     if(exists $main::known_daemons->{$source}) {
531         &main::add_content2known_daemons(hostname=>$source, status=>$header);
532     } else {
533         &main::add_content2known_clients(hostname=>$source, status=>$header);
534     }
535     
536     return;
540 #===  FUNCTION  ================================================================
541 #         NAME:  new_passwd
542 #   PARAMETERS:  msg_hash - ref - hash from function create_xml_hash
543 #      RETURNS:  nothing
544 #  DESCRIPTION:  process this incoming message
545 #===============================================================================
546 sub new_passwd {
547     my ($msg_hash) = @_;
549     my $header = @{$msg_hash->{header}}[0];
550     my $source_name = @{$msg_hash->{source}}[0];
551     my $source_key = @{$msg_hash->{new_passwd}}[0];
552     my $query_res;
554     # check known_clients_db
555     $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients', hostname=>$source_name} );
556     if( 1 == keys %{$query_res} ) {
557         my $update_hash = { table=>'known_clients' };
558         $update_hash->{where} = [ { hostname=>[$source_name] } ];
559         $update_hash->{update} = [ {
560             hostkey=>[$source_key],
561             timestamp=>[&get_time],
562         } ];
563         my $res = $main::known_clients_db->update_dbentry( $update_hash );
565         my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name);
566         &send_msg_hash2address($hash, $source_name, $source_key);
567         return;
568     }
570     # check known_server_db
571     $query_res = $main::known_server_db->select_dbentry( {table=>'known_server', hostname=>$source_name } );
572     if( 1 == keys %{$query_res} ) {
573         my $update_hash = { table=>'known_server' };
574         $update_hash->{where} = [ { hostname=>[$source_name] } ];
575         $update_hash->{update} = [ {
576             hostkey=>[$source_key],
577                 timestamp=>[&get_time],
578         } ];
579         my $res = $main::known_server_db->update_dbentry( $update_hash );
581         my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name);
582         &send_msg_hash2address($hash, $source_name, $source_key);
583         return;
584     }
586     &main::daemon_log("ERROR: $source_name not known for '$header'-msg", 1);
587     return;
591 sub send_msg_hash {
592     my ($hash, $host_name, $host_key);
594     
595     my $answer = &send_msg_hash2address($hash, $host_name, $host_key);
596     
597     return;
601 #===  FUNCTION  ================================================================
602 #         NAME:  here_i_am
603 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
604 #      RETURNS:  nothing
605 #  DESCRIPTION:  process this incoming message
606 #===============================================================================
607 sub here_i_am {
608     my ($msg_hash) = @_;
610     my $source = @{$msg_hash->{source}}[0];
611     my $mac_address = @{$msg_hash->{mac_address}}[0];
612     my $out_hash;
614     # number of known clients
615     my $nu_clients = keys %{ $main::known_clients_db->select_dbentry( {table=>'known_clients'} ) };
617     # check wether client address or mac address is already known
618     if (exists $main::known_clients->{$source}) {
619         &main::daemon_log("WARNING: $source is already known as a client", 1);
620         &main::daemon_log("WARNING: values for $source are being overwritten", 1);   
621         $nu_clients --;
622     }
624     # number of actual activ clients
625     my $act_nu_clients = $nu_clients;
627     &main::daemon_log("number of actual activ clients: $act_nu_clients", 5);
628     &main::daemon_log("number of maximal allowed clients: $max_clients", 5);
630     if($max_clients <= $act_nu_clients) {
631         my $out_hash = &create_xml_hash("denied", $server_address, $source);
632         &add_content2xml_hash($out_hash, "denied", "I_cannot_take_any_more_clients!");
633         my $passwd = @{$msg_hash->{new_passwd}}[0]; 
634         &send_msg_hash2address($out_hash, $source, $passwd);
635         return;
636     }
637     
638     # new client accepted
639     my $new_passwd = @{$msg_hash->{new_passwd}}[0];
641     # create entry in known_clients
642     my $events = @{$msg_hash->{events}}[0];
643     
644     # add entry to known_clients_db
645     my $res = $main::known_clients_db->add_dbentry( {table=>'known_clients', 
646                                                 primkey=>'hostname',
647                                                 hostname=>$source,
648                                                 events=>$events,
649                                                 macaddress=>$mac_address,
650                                                 status=>'registered',
651                                                 hostkey=>$new_passwd,
652                                                 timestamp=>&get_time,
653                                                 } );
655     if ($res != 0)  {
656         &main::daemon_log("ERROR: cannot add entry to known_clients: $res");
657         return;
658     }
659     
660     # return acknowledgement to client
661     $out_hash = &create_xml_hash("registered", $server_address, $source);
662     &send_msg_hash2address($out_hash, $source, $new_passwd);
664     # notify registered client to bus
665     if( $bus_activ eq "on") {
666         # fetch actual bus key
667         my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server'} );
668         my $hostkey = $query_res->{1}->{hostkey};
669         
670         # send update msg to bus
671         $out_hash = &create_xml_hash("new_client", $server_address, $bus_address, $source);
672         &send_msg_hash2address($out_hash, $bus_address, $hostkey);
673         
674         &main::daemon_log("send bus msg that client '$source' has registerd at server '$server_address'", 3);
675     }
677     # give the new client his ldap config
678     &new_ldap_config($source);
680     return;
684 #===  FUNCTION  ================================================================
685 #         NAME:  who_has
686 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
687 #      RETURNS:  nothing 
688 #  DESCRIPTION:  process this incoming message
689 #===============================================================================
690 sub who_has {
691     my ($msg_hash) = @_ ;
692     
693     # what is your search pattern
694     my $search_pattern = @{$msg_hash->{who_has}}[0];
695     my $search_element = @{$msg_hash->{$search_pattern}}[0];
696     &main::daemon_log("who_has-msg looking for $search_pattern $search_element", 7);
698     # scanning known_clients for search_pattern
699     my @host_addresses = keys %$main::known_clients;
700     my $known_clients_entries = length @host_addresses;
701     my $host_address;
702     foreach my $host (@host_addresses) {
703         my $client_element = $main::known_clients->{$host}->{$search_pattern};
704         if ($search_element eq $client_element) {
705             $host_address = $host;
706             last;
707         }
708     }
709         
710     # search was successful
711     if (defined $host_address) {
712         my $source = @{$msg_hash->{source}}[0];
713         my $out_msg = &create_xml_hash("who_has_i_do", $server_address, $source, "mac_address");
714         &add_content2xml_hash($out_msg, "mac_address", $search_element);
715         &send_msg_hash2address($out_msg, $bus_address);
716     }
717     return;
721 sub who_has_i_do {
722     my ($msg_hash) = @_ ;
723     my $header = @{$msg_hash->{header}}[0];
724     my $source = @{$msg_hash->{source}}[0];
725     my $search_param = @{$msg_hash->{$header}}[0];
726     my $search_value = @{$msg_hash->{$search_param}}[0];
727     print "\ngot msg $header:\nserver $source has client with $search_param $search_value\n";
731 #===  FUNCTION  ================================================================
732 #         NAME:  new_ldap_config
733 #   PARAMETERS:  address - string - ip address and port of a host
734 #      RETURNS:  nothing
735 #  DESCRIPTION:  send to address the ldap configuration found for dn gotoLdapServer
736 #===============================================================================
737 sub new_ldap_config {
738     my ($address) = @_ ;
739     
740     my $res = $main::known_clients_db->select_dbentry( { table=>'known_clients', hostname=>$address } );
742     # check hit
743     my $hit_counter = keys %{$res};
744     if( not $hit_counter == 1 ) {
745         &main::daemon_log("ERROR: more or no hit found in known_clients_db by query by '$address'", 1);
746     }
748     my $macaddress = $res->{1}->{macaddress};
749     my $hostkey = $res->{1}->{hostkey};
751     if (not defined $macaddress) {
752         &main::daemon_log("ERROR: no mac address found for client $address", 1);
753         return;
754     }
756     # Build LDAP connection
757     my $ldap = Net::LDAP->new($ldap_uri);
758     if( not defined $ldap ) {
759         &main::daemon_log("ERROR: cannot connect to ldap: $ldap_uri", 1);
760         return;
761     } 
764     # Bind to a directory with dn and password
765     my $mesg= $ldap->bind($ldap_admin_dn, $ldap_admin_password);
767     # Perform search
768     $mesg = $ldap->search( base   => $ldap_base,
769                     scope  => 'sub',
770                     attrs => ['dn', 'gotoLdapServer'],
771                     filter => "(&(objectClass=GOhard)(macaddress=$macaddress))");
772     $mesg->code && die $mesg->error;
774     # Sanity check
775     if ($mesg->count != 1) {
776             &main::daemon_log("WARNING: client mac address $macaddress not found/not unique in ldap search", 1);
777         &main::daemon_log("\tbase: $ldap_base", 1);
778         &main::daemon_log("\tscope: sub", 1);
779         &main::daemon_log("\tattrs: dn, gotoLdapServer", 1);
780         &main::daemon_log("\tfilter: (&(objectClass=GOhard)(macaddress=$macaddress))", 1);
781             return;
782     }
784     my $entry= $mesg->entry(0);
785     my $dn= $entry->dn;
786     my @servers= $entry->get_value("gotoLdapServer");
787     my @ldap_uris;
788     my $server;
789     my $base;
791     # Do we need to look at an object class?
792     if ($#servers < 1){
793             $mesg = $ldap->search( base   => $ldap_base,
794                             scope  => 'sub',
795                             attrs => ['dn', 'gotoLdapServer'],
796                             filter => "(&(objectClass=gosaGroupOfNames)(member=$dn))");
797             $mesg->code && die $mesg->error;
799             # Sanity check
800             if ($mesg->count != 1) {
801                     &main::daemon_log("WARNING: no LDAP information found for client mac $macaddress", 1);
802                     return;
803             }
805             $entry= $mesg->entry(0);
806             $dn= $entry->dn;
807             @servers= $entry->get_value("gotoLdapServer");
808     }
810     @servers= sort (@servers);
812     foreach $server (@servers){
813             $base= $server;
814             $server =~ s%^[^:]+:[^:]+:(ldap.*://[^/]+)/.*$%$1%;
815             $base =~ s%^[^:]+:[^:]+:ldap.*://[^/]+/(.*)$%$1%;
816             push (@ldap_uris, $server);
817     }
819     # Unbind
820     $mesg = $ldap->unbind;
822     # Assemble data package
823     my %data = ( 'ldap_uri'  => \@ldap_uris, 'ldap_base' => $base,
824                      'ldap_cfg' => \@ldap_cfg, 'pam_cfg' => \@pam_cfg,'nss_cfg' => \@nss_cfg );
826     # Need to append GOto settings?
827     if (defined $goto_admin and defined $goto_secret){
828             $data{'goto_admin'}= $goto_admin;
829             $data{'goto_secret'}= $goto_secret;
830     }
832     # Send information
833     send_msg("new_ldap_config", $server_address, $address, \%data, $hostkey);
835     return;
839 #===  FUNCTION  ================================================================
840 #         NAME:  execute_actions
841 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
842 #      RETURNS:  nothing
843 #  DESCRIPTION:  invokes the script specified in msg_hash which is located under
844 #                /etc/gosad/actions
845 #===============================================================================
846 sub execute_actions {
847     my ($msg_hash) = @_ ;
848     my $configdir= '/etc/gosad/actions/';
849     my $result;
851     my $header = @{$msg_hash->{header}}[0];
852     my $source = @{$msg_hash->{source}}[0];
853     my $target = @{$msg_hash->{target}}[0];
854  
855     if((not defined $source)
856             && (not defined $target)
857             && (not defined $header)) {
858         &main::daemon_log("ERROR: Entries missing in XML msg for gosad actions under /etc/gosad/actions");
859     } else {
860         my $parameters="";
861         my @params = @{$msg_hash->{$header}};
862         my $params = join(", ", @params);
863         &main::daemon_log("execute_actions: got parameters: $params", 5);
865         if (@params) {
866             foreach my $param (@params) {
867                 my $param_value = (&get_content_from_xml_hash($msg_hash, $param))[0];
868                 &main::daemon_log("execute_actions: parameter -> value: $param -> $param_value", 7);
869                 $parameters.= " ".$param_value;
870             }
871         }
873         my $cmd= $configdir.$header."$parameters";
874         &main::daemon_log("execute_actions: executing cmd: $cmd", 7);
875         $result= "";
876         open(PIPE, "$cmd 2>&1 |");
877         while(<PIPE>) {
878             $result.=$_;
879         }
880         close(PIPE);
881     }
883     # process the event result
886     return;
890 1;