45d4cac4aa211aac31d1327e0238080a4638ea03
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 recieves 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 } else {
82 &main::daemon_log("start server: $server_address", 1);
83 }
84 }
86 # TODO
87 # füge den server selbst zu known_server hinzu, msgs können nämlich auch von sich selbst kommen (gosa!!!)
90 # register at bus
91 if ($main::no_bus > 0) {
92 $bus_activ = "off"
93 }
94 if($bus_activ eq "on") {
95 &main::daemon_log(" ", 1);
96 ®ister_at_bus();
97 }
99 ### functions #################################################################
101 #sub get_module_tags {
102 #
103 # # lese config file aus dort gibt es eine section Basic
104 # # dort stehen drei packettypen, für die sich das modul anmelden kann, gosa-admin-packages,
105 # # server-packages, client-packages
106 # my %tag_hash = (gosa_admin_packages => "yes",
107 # server_packages => "yes",
108 # client_packages => "yes",
109 # );
110 # return \%tag_hash;
111 #}
114 sub get_module_info {
115 my @info = ($server_address,
116 $server_passwd,
117 $server,
118 $server_activ,
119 "socket",
120 );
121 return \@info;
122 }
125 #=== FUNCTION ================================================================
126 # NAME: read_configfile
127 # PARAMETERS: cfg_file - string -
128 # RETURNS: nothing
129 # DESCRIPTION: read cfg_file and set variables
130 #===============================================================================
131 sub read_configfile {
132 my $cfg;
133 if( defined( $main::cfg_file) && ( length($main::cfg_file) > 0 )) {
134 if( -r $main::cfg_file ) {
135 $cfg = Config::IniFiles->new( -file => $main::cfg_file );
136 } else {
137 print STDERR "Couldn't read config file!";
138 }
139 } else {
140 $cfg = Config::IniFiles->new() ;
141 }
142 foreach my $section (keys %cfg_defaults) {
143 foreach my $param (keys %{$cfg_defaults{ $section }}) {
144 my $pinfo = $cfg_defaults{ $section }{ $param };
145 ${@$pinfo[0]} = $cfg->val( $section, $param, @$pinfo[1] );
146 }
147 }
149 # Read non predefined sections
150 my $param;
151 if ($cfg->SectionExists('ldap')){
152 foreach $param ($cfg->Parameters('ldap')){
153 push (@ldap_cfg, "$param ".$cfg->val('ldap', $param));
154 }
155 }
156 if ($cfg->SectionExists('pam_ldap')){
157 foreach $param ($cfg->Parameters('pam_ldap')){
158 push (@pam_cfg, "$param ".$cfg->val('pam_ldap', $param));
159 }
160 }
161 if ($cfg->SectionExists('nss_ldap')){
162 foreach $param ($cfg->Parameters('nss_ldap')){
163 push (@nss_cfg, "$param ".$cfg->val('nss_ldap', $param));
164 }
165 }
166 if ($cfg->SectionExists('goto')){
167 $goto_admin= $cfg->val('goto', 'terminal_admin');
168 $goto_secret= $cfg->val('goto', 'terminal_secret');
169 } else {
170 $goto_admin= undef;
171 $goto_secret= undef;
172 }
174 }
176 #=== FUNCTION ================================================================
177 # NAME: get_interface_for_ip
178 # PARAMETERS: ip address (i.e. 192.168.0.1)
179 # RETURNS: array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else
180 # DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces.
181 #===============================================================================
182 sub get_interface_for_ip {
183 my $result;
184 my $ip= shift;
185 if ($ip && length($ip) > 0) {
186 my @ifs= &get_interfaces();
187 if($ip eq "0.0.0.0") {
188 $result = "all";
189 } else {
190 foreach (@ifs) {
191 my $if=$_;
192 if(get_ip($if) eq $ip) {
193 $result = $if;
194 }
195 }
196 }
197 }
198 return $result;
199 }
201 #=== FUNCTION ================================================================
202 # NAME: get_interfaces
203 # PARAMETERS: none
204 # RETURNS: (list of interfaces)
205 # DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces.
206 #===============================================================================
207 sub get_interfaces {
208 my @result;
209 my $PROC_NET_DEV= ('/proc/net/dev');
211 open(PROC_NET_DEV, "<$PROC_NET_DEV")
212 or die "Could not open $PROC_NET_DEV";
214 my @ifs = <PROC_NET_DEV>;
216 close(PROC_NET_DEV);
218 # Eat first two line
219 shift @ifs;
220 shift @ifs;
222 chomp @ifs;
223 foreach my $line(@ifs) {
224 my $if= (split /:/, $line)[0];
225 $if =~ s/^\s+//;
226 push @result, $if;
227 }
229 return @result;
230 }
232 #=== FUNCTION ================================================================
233 # NAME: get_mac
234 # PARAMETERS: interface name (i.e. eth0)
235 # RETURNS: (mac address)
236 # DESCRIPTION: Uses ioctl to get mac address directly from system.
237 #===============================================================================
238 sub get_mac {
239 my $ifreq= shift;
240 my $result;
241 if ($ifreq && length($ifreq) > 0) {
242 if($ifreq eq "all") {
243 $result = "00:00:00:00:00:00";
244 } else {
245 my $SIOCGIFHWADDR= 0x8927; # man 2 ioctl_list
247 # A configured MAC Address should always override a guessed value
248 if ($server_mac_address and length($server_mac_address) > 0) {
249 return $server_mac_address;
250 }
252 socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip')
253 or die "socket: $!";
255 if(ioctl SOCKET, $SIOCGIFHWADDR, $ifreq) {
256 my ($if, $mac)= unpack 'h36 H12', $ifreq;
258 if (length($mac) > 0) {
259 $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])$/;
260 $mac= sprintf("%s:%s:%s:%s:%s:%s", $1, $2, $3, $4, $5, $6);
261 $result = $mac;
262 }
263 }
264 }
265 }
266 return $result;
267 }
269 #=== FUNCTION ================================================================
270 # NAME: get_ip
271 # PARAMETERS: interface name (i.e. eth0)
272 # RETURNS: (ip address)
273 # DESCRIPTION: Uses ioctl to get ip address directly from system.
274 #===============================================================================
275 sub get_ip {
276 my $ifreq= shift;
277 my $result= "";
278 my $SIOCGIFADDR= 0x8915; # man 2 ioctl_list
279 my $proto= getprotobyname('ip');
281 socket SOCKET, PF_INET, SOCK_DGRAM, $proto
282 or die "socket: $!";
284 if(ioctl SOCKET, $SIOCGIFADDR, $ifreq) {
285 my ($if, $sin) = unpack 'a16 a16', $ifreq;
286 my ($port, $addr) = sockaddr_in $sin;
287 my $ip = inet_ntoa $addr;
289 if ($ip && length($ip) > 0) {
290 $result = $ip;
291 }
292 }
294 return $result;
295 }
297 #=== FUNCTION ================================================================
298 # NAME: open_socket
299 # PARAMETERS: PeerAddr string something like 192.168.1.1 or 192.168.1.1:10000
300 # [PeerPort] string necessary if port not appended by PeerAddr
301 # RETURNS: socket IO::Socket::INET
302 # DESCRIPTION: open a socket to PeerAddr
303 #===============================================================================
304 sub open_socket {
305 my ($PeerAddr, $PeerPort) = @_ ;
306 if(defined($PeerPort)){
307 $PeerAddr = $PeerAddr.":".$PeerPort;
308 }
309 my $socket;
310 $socket = new IO::Socket::INET(PeerAddr => $PeerAddr ,
311 Porto => "tcp" ,
312 Type => SOCK_STREAM,
313 Timeout => 5,
314 );
315 if(not defined $socket) {
316 return;
317 }
318 &main::daemon_log("open_socket to: $PeerAddr", 7);
319 return $socket;
320 }
322 #=== FUNCTION ================================================================
323 # NAME: register_at_bus
324 # PARAMETERS: nothing
325 # RETURNS: nothing
326 # DESCRIPTION: creates an entry in known_daemons and send a 'here_i_am' msg to bus
327 #===============================================================================
328 sub register_at_bus {
330 # add bus to known_server_db
331 my $res = $main::known_server_db->add_dbentry( {table=>'known_server',
332 primkey=>'hostname',
333 hostname=>$bus_address,
334 status=>'bus',
335 hostkey=>$bus_passwd,
336 timestamp=>&get_time,
337 } );
338 # if ($res == 3) {
339 # my $update_hash = { table=>'known_server' };
340 # $update_hash->{where} = [ { hostname=>[$bus_address] } ];
341 # $update_hash->{update} = [ {
342 # hostkey=>[$bus_passwd],
343 # timestamp=>[&get_time],
344 # } ];
345 # $res = $main::known_server_db->update_dbentry( $update_hash );
346 # }
348 my $msg_hash = &create_xml_hash("here_i_am", $server_address, $bus_address);
349 my $answer = "";
350 $answer = &send_msg_hash2address($msg_hash, $bus_address, $bus_passwd);
351 if ($answer == 0) {
352 &main::daemon_log("register at bus: $bus_address", 1);
353 } else {
354 &main::daemon_log("unable to send 'register'-msg to bus '$bus_address': $answer", 1);
355 }
356 return;
357 }
359 #=== FUNCTION ================================================================
360 # NAME: process_incoming_msg
361 # PARAMETERS: crypted_msg - string - incoming crypted message
362 # RETURNS: nothing
363 # DESCRIPTION: handels the proceeded distribution to the appropriated functions
364 #===============================================================================
365 sub process_incoming_msg {
366 my ($crypted_msg) = @_ ;
367 if(not defined $crypted_msg) {
368 &main::daemon_log("function 'process_incoming_msg': got no msg", 7);
369 }
371 &main::daemon_log("ServerPackages: incoming msg: \n$crypted_msg", 7);
373 $crypted_msg =~ /^([\s\S]*?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)$/;
374 $crypted_msg = $1;
375 my $host = sprintf("%s.%s.%s.%s", $2, $3, $4, $5);
377 my $msg;
378 my $msg_hash;
379 my $host_name;
380 my $host_key;
382 # check wether incoming msg is a new msg
383 $host_name = $server_address;
384 $host_key = $server_passwd;
385 &main::daemon_log("ServerPackage: host_name: $host_name", 7);
386 &main::daemon_log("ServerPackage: host_key: $host_key", 7);
387 eval{
388 my $key_cipher = &create_ciphering($host_key);
389 $msg = &decrypt_msg($crypted_msg, $key_cipher);
390 $msg_hash = &transform_msg2hash($msg);
391 };
392 if($@) {
393 &main::daemon_log("ServerPackage: deciphering raise error", 7);
394 &main::daemon_log("$@", 8);
395 $msg = undef;
396 $msg_hash = undef;
397 $host_name = undef;
398 $host_key = undef;
399 }
401 # check wether incoming msg is from a known_server
402 if( not defined $msg ) {
403 my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server'} );
404 while( my ($hit_num, $hit) = each %{ $query_res } ) {
405 $host_name = $hit->{hostname};
406 if( not $host_name =~ "^$host") {
407 next;
408 }
409 $host_key = $hit->{hostkey};
410 &main::daemon_log("ServerPackage: host_name: $host_name", 7);
411 &main::daemon_log("ServerPackage: host_key: $host_key", 7);
412 eval{
413 my $key_cipher = &create_ciphering($host_key);
414 $msg = &decrypt_msg($crypted_msg, $key_cipher);
415 $msg_hash = &transform_msg2hash($msg);
416 };
417 if($@) {
418 &main::daemon_log("ServerPackage: deciphering raise error", 7);
419 &main::daemon_log("$@", 8);
420 $msg = undef;
421 $msg_hash = undef;
422 $host_name = undef;
423 $host_key = undef;
424 } else {
425 last;
426 }
427 }
428 }
430 # check wether incoming msg is from a known_client
431 if( not defined $msg ) {
432 my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients'} );
433 while( my ($hit_num, $hit) = each %{ $query_res } ) {
434 $host_name = $hit->{hostname};
435 if( not $host_name =~ "^$host") {
436 next;
437 }
438 $host_key = $hit->{hostkey};
439 &main::daemon_log("ServerPackage: host_name: $host_name", 7);
440 &main::daemon_log("ServerPackage: host_key: $host_key", 7);
441 eval{
442 my $key_cipher = &create_ciphering($host_key);
443 $msg = &decrypt_msg($crypted_msg, $key_cipher);
444 $msg_hash = &transform_msg2hash($msg);
445 };
446 if($@) {
447 &main::daemon_log("ServerPackage: deciphering raise error", 7);
448 &main::daemon_log("$@", 8);
449 $msg = undef;
450 $msg_hash = undef;
451 $host_name = undef;
452 $host_key = undef;
453 } else {
454 last;
455 }
456 }
457 }
459 if( not defined $msg ) {
460 &main::daemon_log("WARNING: ServerPackage do not understand the message:", 5);
461 &main::daemon_log("$@", 7);
462 return;
463 }
465 # process incoming msg
466 my $header = @{$msg_hash->{header}}[0];
467 my $source = @{$msg_hash->{source}}[0];
469 &main::daemon_log("recieve '$header' at ServerPackages from $host", 1);
470 &main::daemon_log("ServerPackages: msg to process: \n$msg", 5);
472 my @targets = @{$msg_hash->{target}};
473 my $len_targets = @targets;
474 if ($len_targets == 0){
475 &main::daemon_log("ERROR: ServerPackages: no target specified for msg $header", 1);
477 } elsif ($len_targets == 1){
478 # we have only one target symbol
479 my $target = $targets[0];
480 &main::daemon_log("SeverPackages: msg is for: $target", 7);
482 if ($target eq $server_address) {
483 # msg is for server
484 if ($header eq 'new_passwd'){ &new_passwd($msg_hash)}
485 elsif ($header eq 'here_i_am') { &here_i_am($msg_hash)}
486 elsif ($header eq 'who_has') { &who_has($msg_hash) }
487 elsif ($header eq 'who_has_i_do') { &who_has_i_do($msg_hash)}
488 elsif ($header eq 'update_status') { &update_status($msg_hash) }
489 elsif ($header eq 'got_ping') { &got_ping($msg_hash)}
490 elsif ($header eq 'get_load') { &execute_actions($msg_hash)}
491 else { &main::daemon_log("ERROR: ServerPackages: no function assigned to this msg", 5) }
493 } elsif ($target eq "*") {
494 # msg is for all clients
495 my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients'} );
496 while( my ($hit_num, $hit) = each %{ $query_res } ) {
497 $host_name = $hit->{hostname};
498 $host_key = $hit->{hostkey};
499 $msg_hash->{target} = [$host_name];
500 &send_msg_hash2address($msg_hash, $host_name, $host_key);
501 }
502 return;
504 } else {
505 # msg is for one host
506 my $query_res;
507 $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients', hostname=>$target} );
508 if( 1 == keys %{$query_res} ) {
509 $host_key = $query_res->{1}->{host_key};
510 &send_msg_hash2address($msg_hash, $target, $host_key);
511 return;
512 }
514 $query_res = $main::known_server_db->select_dbentry( {table=>'known_server', hostname=>$target} );
515 if( 1 == keys %{$query_res} ) {
516 $host_key = $query_res->{1}->{host_key};
517 &send_msg_hash2address($msg_hash, $target, $host_key);
518 return;
519 }
521 &main::daemon_log("ERROR: ServerPackages: target '$target' is not known neither in known_clients nor in known_server",1);
522 return;
523 }
525 } elsif ($len_targets > 1 ) {
526 # we have more than one target
527 return;
528 }
530 return ;
531 }
534 #=== FUNCTION ================================================================
535 # NAME: got_ping
536 # PARAMETERS: msg_hash - hash - hash from function create_xml_hash
537 # RETURNS: nothing
538 # DESCRIPTION: process this incoming message
539 #===============================================================================
540 sub got_ping {
541 my ($msg_hash) = @_;
543 my $source = @{$msg_hash->{source}}[0];
544 my $target = @{$msg_hash->{target}}[0];
545 my $header = @{$msg_hash->{header}}[0];
547 if(exists $main::known_daemons->{$source}) {
548 &main::add_content2known_daemons(hostname=>$source, status=>$header);
549 } else {
550 &main::add_content2known_clients(hostname=>$source, status=>$header);
551 }
553 return;
554 }
557 #=== FUNCTION ================================================================
558 # NAME: new_passwd
559 # PARAMETERS: msg_hash - ref - hash from function create_xml_hash
560 # RETURNS: nothing
561 # DESCRIPTION: process this incoming message
562 #===============================================================================
563 sub new_passwd {
564 my ($msg_hash) = @_;
566 my $header = @{$msg_hash->{header}}[0];
567 my $source_name = @{$msg_hash->{source}}[0];
568 my $source_key = @{$msg_hash->{new_passwd}}[0];
569 my $query_res;
571 # check known_clients_db
572 $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients', hostname=>$source_name} );
573 if( 1 == keys %{$query_res} ) {
574 my $update_hash = { table=>'known_clients' };
575 $update_hash->{where} = [ { hostname=>[$source_name] } ];
576 $update_hash->{update} = [ {
577 hostkey=>[$source_key],
578 timestamp=>[&get_time],
579 } ];
580 my $res = $main::known_clients_db->update_dbentry( $update_hash );
582 my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name);
583 &send_msg_hash2address($hash, $source_name, $source_key);
584 return;
585 }
587 # check known_server_db
588 $query_res = $main::known_server_db->select_dbentry( {table=>'known_server', hostname=>$source_name } );
589 if( 1 == keys %{$query_res} ) {
590 my $update_hash = { table=>'known_server' };
591 $update_hash->{where} = [ { hostname=>[$source_name] } ];
592 $update_hash->{update} = [ {
593 hostkey=>[$source_key],
594 timestamp=>[&get_time],
595 } ];
596 my $res = $main::known_server_db->update_dbentry( $update_hash );
598 my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name);
599 &send_msg_hash2address($hash, $source_name, $source_key);
600 return;
601 }
603 &main::daemon_log("ERROR: $source_name not known for '$header'-msg", 1);
604 return;
605 }
608 sub send_msg_hash {
609 my ($hash, $host_name, $host_key);
612 my $answer = &send_msg_hash2address($hash, $host_name, $host_key);
614 return;
615 }
618 #=== FUNCTION ================================================================
619 # NAME: here_i_am
620 # PARAMETERS: msg_hash - hash - hash from function create_xml_hash
621 # RETURNS: nothing
622 # DESCRIPTION: process this incoming message
623 #===============================================================================
624 sub here_i_am {
625 my ($msg_hash) = @_;
627 my $source = @{$msg_hash->{source}}[0];
628 my $mac_address = @{$msg_hash->{mac_address}}[0];
629 my $out_hash;
631 # number of known clients
632 my $nu_clients = keys %{$main::known_clients_db->select_dbentry( {table=>'known_clients'} )};
634 # check wether client address or mac address is already known
635 if (exists $main::known_clients->{$source}) {
636 &main::daemon_log("WARNING: $source is already known as a client", 1);
637 &main::daemon_log("WARNING: values for $source are being overwritten", 1);
638 $nu_clients --;
639 }
641 # number of actual activ clients
642 my $act_nu_clients = $nu_clients;
644 &main::daemon_log("number of actual activ clients: $act_nu_clients", 5);
645 &main::daemon_log("number of maximal allowed clients: $max_clients", 5);
647 if($max_clients <= $act_nu_clients) {
648 my $out_hash = &create_xml_hash("denied", $server_address, $source);
649 &add_content2xml_hash($out_hash, "denied", "I_cannot_take_any_more_clients!");
650 my $passwd = @{$msg_hash->{new_passwd}}[0];
651 &send_msg_hash2address($out_hash, $source, $passwd);
652 return;
653 }
655 # new client accepted
656 my $new_passwd = @{$msg_hash->{new_passwd}}[0];
658 # create entry in known_clients
659 my $events = @{$msg_hash->{events}}[0];
661 # add entry to known_clients_db
662 my $res = $main::known_clients_db->add_dbentry( {table=>'known_clients',
663 primkey=>'hostname',
664 hostname=>$source,
665 events=>$events,
666 macaddress=>$mac_address,
667 status=>'registered',
668 hostkey=>$new_passwd,
669 timestamp=>&get_time,
670 } );
672 if ($res != 0) {
673 &main::daemon_log("ERROR: cannot add entry to known_clients: $res");
674 return;
675 }
677 # return acknowledgement to client
678 $out_hash = &create_xml_hash("registered", $server_address, $source);
679 &send_msg_hash2address($out_hash, $source, $new_passwd);
681 # notify registered client to bus
682 if( $bus_activ eq "on") {
683 # fetch actual bus key
684 my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server'} );
685 my $hostkey = $query_res->{1}->{hostkey};
687 # send update msg to bus
688 $out_hash = &create_xml_hash("new_client", $server_address, $bus_address, $source);
689 &send_msg_hash2address($out_hash, $bus_address, $hostkey);
691 &main::daemon_log("send bus msg that client '$source' has registerd at server '$server_address'", 3);
692 }
694 # give the new client his ldap config
695 &new_ldap_config($source);
697 return;
698 }
701 #=== FUNCTION ================================================================
702 # NAME: who_has
703 # PARAMETERS: msg_hash - hash - hash from function create_xml_hash
704 # RETURNS: nothing
705 # DESCRIPTION: process this incoming message
706 #===============================================================================
707 sub who_has {
708 my ($msg_hash) = @_ ;
710 # what is your search pattern
711 my $search_pattern = @{$msg_hash->{who_has}}[0];
712 my $search_element = @{$msg_hash->{$search_pattern}}[0];
713 &main::daemon_log("who_has-msg looking for $search_pattern $search_element", 7);
715 # scanning known_clients for search_pattern
716 my @host_addresses = keys %$main::known_clients;
717 my $known_clients_entries = length @host_addresses;
718 my $host_address;
719 foreach my $host (@host_addresses) {
720 my $client_element = $main::known_clients->{$host}->{$search_pattern};
721 if ($search_element eq $client_element) {
722 $host_address = $host;
723 last;
724 }
725 }
727 # search was successful
728 if (defined $host_address) {
729 my $source = @{$msg_hash->{source}}[0];
730 my $out_msg = &create_xml_hash("who_has_i_do", $server_address, $source, "mac_address");
731 &add_content2xml_hash($out_msg, "mac_address", $search_element);
732 &send_msg_hash2address($out_msg, $bus_address);
733 }
734 return;
735 }
738 sub who_has_i_do {
739 my ($msg_hash) = @_ ;
740 my $header = @{$msg_hash->{header}}[0];
741 my $source = @{$msg_hash->{source}}[0];
742 my $search_param = @{$msg_hash->{$header}}[0];
743 my $search_value = @{$msg_hash->{$search_param}}[0];
744 print "\ngot msg $header:\nserver $source has client with $search_param $search_value\n";
745 }
748 #=== FUNCTION ================================================================
749 # NAME: new_ldap_config
750 # PARAMETERS: address - string - ip address and port of a host
751 # RETURNS: nothing
752 # DESCRIPTION: send to address the ldap configuration found for dn gotoLdapServer
753 #===============================================================================
754 sub new_ldap_config {
755 my ($address) = @_ ;
757 my $res = $main::known_clients_db->select_dbentry( { table=>'known_clients', hostname=>$address } );
759 # check hit
760 my $hit_counter = keys %{$res};
761 if( not $hit_counter == 1 ) {
762 &main::daemon_log("ERROR: more or no hit found in known_clients_db by query by '$address'", 1);
763 }
765 my $macaddress = $res->{1}->{macaddress};
766 my $hostkey = $res->{1}->{hostkey};
768 if (not defined $macaddress) {
769 &main::daemon_log("ERROR: no mac address found for client $address", 1);
770 return;
771 }
773 # Build LDAP connection
774 my $ldap = Net::LDAP->new($ldap_uri);
775 if( not defined $ldap ) {
776 &main::daemon_log("ERROR: cannot connect to ldap: $ldap_uri", 1);
777 return;
778 }
781 # Bind to a directory with dn and password
782 my $mesg= $ldap->bind($ldap_admin_dn, $ldap_admin_password);
784 # Perform search
785 $mesg = $ldap->search( base => $ldap_base,
786 scope => 'sub',
787 attrs => ['dn', 'gotoLdapServer'],
788 filter => "(&(objectClass=GOhard)(macaddress=$macaddress))");
789 $mesg->code && die $mesg->error;
791 # Sanity check
792 if ($mesg->count != 1) {
793 &main::daemon_log("WARNING: client mac address $macaddress not found/not unique in ldap search", 1);
794 &main::daemon_log("\tbase: $ldap_base", 1);
795 &main::daemon_log("\tscope: sub", 1);
796 &main::daemon_log("\tattrs: dn, gotoLdapServer", 1);
797 &main::daemon_log("\tfilter: (&(objectClass=GOhard)(macaddress=$macaddress))", 1);
798 return;
799 }
801 my $entry= $mesg->entry(0);
802 my $dn= $entry->dn;
803 my @servers= $entry->get_value("gotoLdapServer");
804 my @ldap_uris;
805 my $server;
806 my $base;
808 # Do we need to look at an object class?
809 if ($#servers < 1){
810 $mesg = $ldap->search( base => $ldap_base,
811 scope => 'sub',
812 attrs => ['dn', 'gotoLdapServer'],
813 filter => "(&(objectClass=gosaGroupOfNames)(member=$dn))");
814 $mesg->code && die $mesg->error;
816 # Sanity check
817 if ($mesg->count != 1) {
818 &main::daemon_log("WARNING: no LDAP information found for client mac $macaddress", 1);
819 return;
820 }
822 $entry= $mesg->entry(0);
823 $dn= $entry->dn;
824 @servers= $entry->get_value("gotoLdapServer");
825 }
827 @servers= sort (@servers);
829 foreach $server (@servers){
830 $base= $server;
831 $server =~ s%^[^:]+:[^:]+:(ldap.*://[^/]+)/.*$%$1%;
832 $base =~ s%^[^:]+:[^:]+:ldap.*://[^/]+/(.*)$%$1%;
833 push (@ldap_uris, $server);
834 }
836 # Unbind
837 $mesg = $ldap->unbind;
839 # Assemble data package
840 my %data = ( 'ldap_uri' => \@ldap_uris, 'ldap_base' => $base,
841 'ldap_cfg' => \@ldap_cfg, 'pam_cfg' => \@pam_cfg,'nss_cfg' => \@nss_cfg );
843 # Need to append GOto settings?
844 if (defined $goto_admin and defined $goto_secret){
845 $data{'goto_admin'}= $goto_admin;
846 $data{'goto_secret'}= $goto_secret;
847 }
849 # Send information
850 send_msg("new_ldap_config", $server_address, $address, \%data, $hostkey);
852 return;
853 }
856 #=== FUNCTION ================================================================
857 # NAME: execute_actions
858 # PARAMETERS: msg_hash - hash - hash from function create_xml_hash
859 # RETURNS: nothing
860 # DESCRIPTION: invokes the script specified in msg_hash which is located under
861 # /etc/gosad/actions
862 #===============================================================================
863 sub execute_actions {
864 my ($msg_hash) = @_ ;
865 my $configdir= '/etc/gosad/actions/';
866 my $result;
868 my $header = @{$msg_hash->{header}}[0];
869 my $source = @{$msg_hash->{source}}[0];
870 my $target = @{$msg_hash->{target}}[0];
872 if((not defined $source)
873 && (not defined $target)
874 && (not defined $header)) {
875 &main::daemon_log("ERROR: Entries missing in XML msg for gosad actions under /etc/gosad/actions");
876 } else {
877 my $parameters="";
878 my @params = @{$msg_hash->{$header}};
879 my $params = join(", ", @params);
880 &main::daemon_log("execute_actions: got parameters: $params", 5);
882 if (@params) {
883 foreach my $param (@params) {
884 my $param_value = (&get_content_from_xml_hash($msg_hash, $param))[0];
885 &main::daemon_log("execute_actions: parameter -> value: $param -> $param_value", 7);
886 $parameters.= " ".$param_value;
887 }
888 }
890 my $cmd= $configdir.$header."$parameters";
891 &main::daemon_log("execute_actions: executing cmd: $cmd", 7);
892 $result= "";
893 open(PIPE, "$cmd 2>&1 |");
894 while(<PIPE>) {
895 $result.=$_;
896 }
897 close(PIPE);
898 }
900 # process the event result
903 return;
904 }
907 1;