Code

bugfix: DBsqlite select_dbentry: correct sorting of the DB output
[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 }
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 = sprintf("%s.%s.%s.%s", $2, $3, $4, $5);
353     my $msg;
354     my $msg_hash;
355     my $host_name;
356     my $host_key;
358     # check wether incoming msg is a new msg
359     $host_name = $server_address;
360     $host_key = $server_passwd;
361     &main::daemon_log("ServerPackage: host_name: $host_name", 7);
362     &main::daemon_log("ServerPackage: host_key: $host_key", 7);
363     eval{
364         my $key_cipher = &create_ciphering($host_key);
365         $msg = &decrypt_msg($crypted_msg, $key_cipher);
366         $msg_hash = &transform_msg2hash($msg);
367     };
368     if($@) {
369         &main::daemon_log("ServerPackage: deciphering raise error", 7);
370         &main::daemon_log("$@", 8);
371         $msg = undef;
372         $msg_hash = undef;
373         $host_name = undef;
374         $host_key = undef;
375     } 
377     # check wether incoming msg is from a known_server
378     if( not defined $msg ) {
379         my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server'} ); 
380         while( my ($hit_num, $hit) = each %{ $query_res } ) {  
381             $host_name = $hit->{hostname};
382             if( not $host_name =~ "^$host") {
383                 next;
384             }
385             $host_key = $hit->{hostkey};
386             &main::daemon_log("ServerPackage: host_name: $host_name", 7);
387             &main::daemon_log("ServerPackage: host_key: $host_key", 7);
388             eval{
389                 my $key_cipher = &create_ciphering($host_key);
390                 $msg = &decrypt_msg($crypted_msg, $key_cipher);
391                 $msg_hash = &transform_msg2hash($msg);
392             };
393             if($@) {
394                 &main::daemon_log("ServerPackage: deciphering raise error", 7);
395                 &main::daemon_log("$@", 8);
396                 $msg = undef;
397                 $msg_hash = undef;
398                 $host_name = undef;
399                 $host_key = undef;
400             } else {
401                 last;
402             }
403         }
404     }
406     # check wether incoming msg is from a known_client
407     if( not defined $msg ) {
408         my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients'} ); 
409         while( my ($hit_num, $hit) = each %{ $query_res } ) {    
410             $host_name = $hit->{hostname};
411             if( not $host_name =~ "^$host") {
412                 next;
413             }
414             $host_key = $hit->{hostkey};
415             &main::daemon_log("ServerPackage: host_name: $host_name", 7);
416             &main::daemon_log("ServerPackage: host_key: $host_key", 7);
417             eval{
418                 my $key_cipher = &create_ciphering($host_key);
419                 $msg = &decrypt_msg($crypted_msg, $key_cipher);
420                 $msg_hash = &transform_msg2hash($msg);
421             };
422             if($@) {
423                 &main::daemon_log("ServerPackage: deciphering raise error", 7);
424                 &main::daemon_log("$@", 8);
425                 $msg = undef;
426                 $msg_hash = undef;
427                 $host_name = undef;
428                 $host_key = undef;
429             } else {
430                 last;
431             }
432         }
433     }
435     if( not defined $msg ) {
436         &main::daemon_log("WARNING: ServerPackage do not understand the message:", 5);
437         &main::daemon_log("$@", 7);
438         return;
439     }
441     # process incoming msg
442     my $header = @{$msg_hash->{header}}[0]; 
443     my $source = @{$msg_hash->{source}}[0];
445     &main::daemon_log("receive '$header' at ServerPackages from $host", 1);
446     &main::daemon_log("ServerPackages: msg to process: \n$msg", 7);
448     my @targets = @{$msg_hash->{target}};
449     my $len_targets = @targets;
450     if ($len_targets == 0){     
451         &main::daemon_log("ERROR: ServerPackages: no target specified for msg $header", 1);
453     }  elsif ($len_targets == 1){
454         # we have only one target symbol
455         my $target = $targets[0];
456         &main::daemon_log("SeverPackages: msg is for: $target", 7);
458         # msg is for server
459         if ($header eq 'new_passwd'){ &new_passwd($msg_hash)}
460         elsif ($header eq 'here_i_am') { &here_i_am($msg_hash)}
461         elsif ($header eq 'who_has') { &who_has($msg_hash) }
462         elsif ($header eq 'who_has_i_do') { &who_has_i_do($msg_hash)}
463         elsif ($header eq 'update_status') { &update_status($msg_hash) }
464         elsif ($header eq 'got_ping') { &got_ping($msg_hash)}
465         elsif ($header eq 'get_load') { &execute_actions($msg_hash)}
466         else { 
467             if ($target eq "*") {
468                 # msg is for all clients
469                 my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients'} ); 
470                 while( my ($hit_num, $hit) = each %{ $query_res } ) {    
471                     $host_name = $hit->{hostname};
472                     $host_key = $hit->{hostkey};
473                     $msg_hash->{target} = [$host_name];
474                     &send_msg_hash2address($msg_hash, $host_name, $host_key);
475                 }
477             } else {
478                 # msg is for one host
479                 my $host_key;
482                 if( not defined $host_key ) {
483                     my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients', hostname=>$target} );
484                     if( 1 == keys %{$query_res} ) {
485                         $host_key = $query_res->{1}->{host_key};
486                     }
487                 } 
489                 if( not defined $host_key ) {
490                     my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server', hostname=>$target} );
491                     if( 1 == keys %{$query_res} ) {
492                         $host_key = $query_res->{1}->{host_key};
493                     }
494                 }
496                 if( not defined $host_key ) { 
497                     &main::daemon_log("ERROR: ServerPackages: target '".$target.
498                             "' is not known neither in known_clients nor in known_server",1);
499                 } else {
500                     &send_msg_hash2address($msg_hash, $target, $host_key);
501                 }               
502             }
503         }
505     } elsif ($len_targets > 1 ) {
506         # we have more than one target 
507         # TODO to be implemented
508     }
510     return ;
514 #===  FUNCTION  ================================================================
515 #         NAME:  got_ping
516 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
517 #      RETURNS:  nothing
518 #  DESCRIPTION:  process this incoming message
519 #===============================================================================
520 sub got_ping {
521     my ($msg_hash) = @_;
522     
523     my $source = @{$msg_hash->{source}}[0];
524     my $target = @{$msg_hash->{target}}[0];
525     my $header = @{$msg_hash->{header}}[0];
526     
527     if(exists $main::known_daemons->{$source}) {
528         &main::add_content2known_daemons(hostname=>$source, status=>$header);
529     } else {
530         &main::add_content2known_clients(hostname=>$source, status=>$header);
531     }
532     
533     return;
537 #===  FUNCTION  ================================================================
538 #         NAME:  new_passwd
539 #   PARAMETERS:  msg_hash - ref - hash from function create_xml_hash
540 #      RETURNS:  nothing
541 #  DESCRIPTION:  process this incoming message
542 #===============================================================================
543 sub new_passwd {
544     my ($msg_hash) = @_;
546     my $header = @{$msg_hash->{header}}[0];
547     my $source_name = @{$msg_hash->{source}}[0];
548     my $source_key = @{$msg_hash->{new_passwd}}[0];
549     my $query_res;
551     # check known_clients_db
552     $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients', hostname=>$source_name} );
553     if( 1 == keys %{$query_res} ) {
554         my $update_hash = { table=>'known_clients' };
555         $update_hash->{where} = [ { hostname=>[$source_name] } ];
556         $update_hash->{update} = [ {
557             hostkey=>[$source_key],
558             timestamp=>[&get_time],
559         } ];
560         my $res = $main::known_clients_db->update_dbentry( $update_hash );
562         my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name);
563         &send_msg_hash2address($hash, $source_name, $source_key);
564         return;
565     }
567     # check known_server_db
568     $query_res = $main::known_server_db->select_dbentry( {table=>'known_server', hostname=>$source_name } );
569     if( 1 == keys %{$query_res} ) {
570         my $update_hash = { table=>'known_server' };
571         $update_hash->{where} = [ { hostname=>[$source_name] } ];
572         $update_hash->{update} = [ {
573             hostkey=>[$source_key],
574                 timestamp=>[&get_time],
575         } ];
576         my $res = $main::known_server_db->update_dbentry( $update_hash );
578         my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name);
579         &send_msg_hash2address($hash, $source_name, $source_key);
580         return;
581     }
583     &main::daemon_log("ERROR: $source_name not known for '$header'-msg", 1);
584     return;
588 sub send_msg_hash {
589     my ($hash, $host_name, $host_key);
591     
592     my $answer = &send_msg_hash2address($hash, $host_name, $host_key);
593     
594     return;
598 #===  FUNCTION  ================================================================
599 #         NAME:  here_i_am
600 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
601 #      RETURNS:  nothing
602 #  DESCRIPTION:  process this incoming message
603 #===============================================================================
604 sub here_i_am {
605     my ($msg_hash) = @_;
607     my $source = @{$msg_hash->{source}}[0];
608     my $mac_address = @{$msg_hash->{mac_address}}[0];
609     my $out_hash;
611     # number of known clients
612     my $nu_clients = keys %{ $main::known_clients_db->select_dbentry( {table=>'known_clients'} ) };
614     # check wether client address or mac address is already known
615     if (exists $main::known_clients->{$source}) {
616         &main::daemon_log("WARNING: $source is already known as a client", 1);
617         &main::daemon_log("WARNING: values for $source are being overwritten", 1);   
618         $nu_clients --;
619     }
621     # number of actual activ clients
622     my $act_nu_clients = $nu_clients;
624     &main::daemon_log("number of actual activ clients: $act_nu_clients", 5);
625     &main::daemon_log("number of maximal allowed clients: $max_clients", 5);
627     if($max_clients <= $act_nu_clients) {
628         my $out_hash = &create_xml_hash("denied", $server_address, $source);
629         &add_content2xml_hash($out_hash, "denied", "I_cannot_take_any_more_clients!");
630         my $passwd = @{$msg_hash->{new_passwd}}[0]; 
631         &send_msg_hash2address($out_hash, $source, $passwd);
632         return;
633     }
634     
635     # new client accepted
636     my $new_passwd = @{$msg_hash->{new_passwd}}[0];
638     # create entry in known_clients
639     my $events = @{$msg_hash->{events}}[0];
640     
641     # add entry to known_clients_db
642     my $res = $main::known_clients_db->add_dbentry( {table=>'known_clients', 
643                                                 primkey=>'hostname',
644                                                 hostname=>$source,
645                                                 events=>$events,
646                                                 macaddress=>$mac_address,
647                                                 status=>'registered',
648                                                 hostkey=>$new_passwd,
649                                                 timestamp=>&get_time,
650                                                 } );
652     if ($res != 0)  {
653         &main::daemon_log("ERROR: cannot add entry to known_clients: $res");
654         return;
655     }
656     
657     # return acknowledgement to client
658     $out_hash = &create_xml_hash("registered", $server_address, $source);
659     &send_msg_hash2address($out_hash, $source, $new_passwd);
661     # notify registered client to bus
662     if( $bus_activ eq "on") {
663         # fetch actual bus key
664         my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server'} );
665         my $hostkey = $query_res->{1}->{hostkey};
666         
667         # send update msg to bus
668         $out_hash = &create_xml_hash("new_client", $server_address, $bus_address, $source);
669         &send_msg_hash2address($out_hash, $bus_address, $hostkey);
670         
671         &main::daemon_log("send bus msg that client '$source' has registerd at server '$server_address'", 3);
672     }
674     # give the new client his ldap config
675     &new_ldap_config($source);
677     return;
681 #===  FUNCTION  ================================================================
682 #         NAME:  who_has
683 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
684 #      RETURNS:  nothing 
685 #  DESCRIPTION:  process this incoming message
686 #===============================================================================
687 sub who_has {
688     my ($msg_hash) = @_ ;
689     
690     # what is your search pattern
691     my $search_pattern = @{$msg_hash->{who_has}}[0];
692     my $search_element = @{$msg_hash->{$search_pattern}}[0];
693     &main::daemon_log("who_has-msg looking for $search_pattern $search_element", 7);
695     # scanning known_clients for search_pattern
696     my @host_addresses = keys %$main::known_clients;
697     my $known_clients_entries = length @host_addresses;
698     my $host_address;
699     foreach my $host (@host_addresses) {
700         my $client_element = $main::known_clients->{$host}->{$search_pattern};
701         if ($search_element eq $client_element) {
702             $host_address = $host;
703             last;
704         }
705     }
706         
707     # search was successful
708     if (defined $host_address) {
709         my $source = @{$msg_hash->{source}}[0];
710         my $out_msg = &create_xml_hash("who_has_i_do", $server_address, $source, "mac_address");
711         &add_content2xml_hash($out_msg, "mac_address", $search_element);
712         &send_msg_hash2address($out_msg, $bus_address);
713     }
714     return;
718 sub who_has_i_do {
719     my ($msg_hash) = @_ ;
720     my $header = @{$msg_hash->{header}}[0];
721     my $source = @{$msg_hash->{source}}[0];
722     my $search_param = @{$msg_hash->{$header}}[0];
723     my $search_value = @{$msg_hash->{$search_param}}[0];
724     print "\ngot msg $header:\nserver $source has client with $search_param $search_value\n";
728 #===  FUNCTION  ================================================================
729 #         NAME:  new_ldap_config
730 #   PARAMETERS:  address - string - ip address and port of a host
731 #      RETURNS:  nothing
732 #  DESCRIPTION:  send to address the ldap configuration found for dn gotoLdapServer
733 #===============================================================================
734 sub new_ldap_config {
735     my ($address) = @_ ;
736     
737     my $res = $main::known_clients_db->select_dbentry( { table=>'known_clients', hostname=>$address } );
739     # check hit
740     my $hit_counter = keys %{$res};
741     if( not $hit_counter == 1 ) {
742         &main::daemon_log("ERROR: more or no hit found in known_clients_db by query by '$address'", 1);
743     }
745     my $macaddress = $res->{1}->{macaddress};
746     my $hostkey = $res->{1}->{hostkey};
748     if (not defined $macaddress) {
749         &main::daemon_log("ERROR: no mac address found for client $address", 1);
750         return;
751     }
753     # Build LDAP connection
754     my $ldap = Net::LDAP->new($ldap_uri);
755     if( not defined $ldap ) {
756         &main::daemon_log("ERROR: cannot connect to ldap: $ldap_uri", 1);
757         return;
758     } 
761     # Bind to a directory with dn and password
762     my $mesg= $ldap->bind($ldap_admin_dn, $ldap_admin_password);
764     # Perform search
765     $mesg = $ldap->search( base   => $ldap_base,
766                     scope  => 'sub',
767                     attrs => ['dn', 'gotoLdapServer'],
768                     filter => "(&(objectClass=GOhard)(macaddress=$macaddress))");
769     $mesg->code && die $mesg->error;
771     # Sanity check
772     if ($mesg->count != 1) {
773             &main::daemon_log("WARNING: client mac address $macaddress not found/not unique in ldap search", 1);
774         &main::daemon_log("\tbase: $ldap_base", 1);
775         &main::daemon_log("\tscope: sub", 1);
776         &main::daemon_log("\tattrs: dn, gotoLdapServer", 1);
777         &main::daemon_log("\tfilter: (&(objectClass=GOhard)(macaddress=$macaddress))", 1);
778             return;
779     }
781     my $entry= $mesg->entry(0);
782     my $dn= $entry->dn;
783     my @servers= $entry->get_value("gotoLdapServer");
784     my @ldap_uris;
785     my $server;
786     my $base;
788     # Do we need to look at an object class?
789     if ($#servers < 1){
790             $mesg = $ldap->search( base   => $ldap_base,
791                             scope  => 'sub',
792                             attrs => ['dn', 'gotoLdapServer'],
793                             filter => "(&(objectClass=gosaGroupOfNames)(member=$dn))");
794             $mesg->code && die $mesg->error;
796             # Sanity check
797             if ($mesg->count != 1) {
798                     &main::daemon_log("WARNING: no LDAP information found for client mac $macaddress", 1);
799                     return;
800             }
802             $entry= $mesg->entry(0);
803             $dn= $entry->dn;
804             @servers= $entry->get_value("gotoLdapServer");
805     }
807     @servers= sort (@servers);
809     foreach $server (@servers){
810             $base= $server;
811             $server =~ s%^[^:]+:[^:]+:(ldap.*://[^/]+)/.*$%$1%;
812             $base =~ s%^[^:]+:[^:]+:ldap.*://[^/]+/(.*)$%$1%;
813             push (@ldap_uris, $server);
814     }
816     # Unbind
817     $mesg = $ldap->unbind;
819     # Assemble data package
820     my %data = ( 'ldap_uri'  => \@ldap_uris, 'ldap_base' => $base,
821                      'ldap_cfg' => \@ldap_cfg, 'pam_cfg' => \@pam_cfg,'nss_cfg' => \@nss_cfg );
823     # Need to append GOto settings?
824     if (defined $goto_admin and defined $goto_secret){
825             $data{'goto_admin'}= $goto_admin;
826             $data{'goto_secret'}= $goto_secret;
827     }
829     # Send information
830     send_msg("new_ldap_config", $server_address, $address, \%data, $hostkey);
832     return;
836 #===  FUNCTION  ================================================================
837 #         NAME:  execute_actions
838 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
839 #      RETURNS:  nothing
840 #  DESCRIPTION:  invokes the script specified in msg_hash which is located under
841 #                /etc/gosad/actions
842 #===============================================================================
843 sub execute_actions {
844     my ($msg_hash) = @_ ;
845     my $configdir= '/etc/gosad/actions/';
846     my $result;
848     my $header = @{$msg_hash->{header}}[0];
849     my $source = @{$msg_hash->{source}}[0];
850     my $target = @{$msg_hash->{target}}[0];
851  
852     if((not defined $source)
853             && (not defined $target)
854             && (not defined $header)) {
855         &main::daemon_log("ERROR: Entries missing in XML msg for gosad actions under /etc/gosad/actions");
856     } else {
857         my $parameters="";
858         my @params = @{$msg_hash->{$header}};
859         my $params = join(", ", @params);
860         &main::daemon_log("execute_actions: got parameters: $params", 5);
862         if (@params) {
863             foreach my $param (@params) {
864                 my $param_value = (&get_content_from_xml_hash($msg_hash, $param))[0];
865                 &main::daemon_log("execute_actions: parameter -> value: $param -> $param_value", 7);
866                 $parameters.= " ".$param_value;
867             }
868         }
870         my $cmd= $configdir.$header."$parameters";
871         &main::daemon_log("execute_actions: executing cmd: $cmd", 7);
872         $result= "";
873         open(PIPE, "$cmd 2>&1 |");
874         while(<PIPE>) {
875             $result.=$_;
876         }
877         close(PIPE);
878     }
880     # process the event result
883     return;
887 1;