Code

c2fc7eea99469bc917aa7e10db3886562e6ee891
[gosa.git] / contrib / daemon / 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 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 GosaSupportDaemon;
13 BEGIN{}
15 END {}
18 ### START ##########
22 sub get_module_tags {
23     
24     # lese config file aus dort gibt es eine section Basic
25     # dort stehen drei packettypen, für die sich das modul anmelden kann, gosa-admin-packages, 
26     #   server-packages, client-packages
27     my %tag_hash = (gosa_admin_packages => "yes", 
28                     server_packages => "yes", 
29                     client_packages => "yes",
30                     );
31     return \%tag_hash;
32 }
35 sub process_incoming_msg {
36     my ($crypted_msg) = @_ ;
37     if(not defined $crypted_msg) {
38         &main::daemon_log("function 'process_incoming_msg': got no msg", 7);
39     }
40     $crypted_msg =~ /^([\s\S]*?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)$/;
41     $crypted_msg = $1;
42     my $host = sprintf("%s.%s.%s.%s", $2, $3, $4, $5);
44     # collect addresses from possible incoming clients
45     my @valid_keys;
46     my @host_keys = keys %$main::known_daemons;
47     foreach my $host_key (@host_keys) {    
48         if($host_key =~ "^$host") {
49             push(@valid_keys, $host_key);
50         }
51     }
52     my @client_keys = keys %$main::known_clients;
53     foreach my $client_key (@client_keys) {
54         if($client_key =~ "^$host"){
55             push(@valid_keys, $client_key);
56         }
57     }
58     push(@valid_keys, $main::server_address);
59     
60     my $l = @valid_keys;
61     my $msg_hash;
62     my $msg_flag = 0;    
63     my $msg = "";
65     # determine the correct passwd for deciphering of the incoming msgs
66     foreach my $host_key (@valid_keys) {
67         eval{
68             &main::daemon_log("ServerPackage: host_key: $host_key", 7);
69             my $key_passwd;
70             if (exists $main::known_daemons->{$host_key}) {
71                 $key_passwd = $main::known_daemons->{$host_key}->{passwd};
72             } elsif (exists $main::known_clients->{$host_key}) {
73                 $key_passwd = $main::known_clients->{$host_key}->{passwd};
74             } elsif ($host_key eq $main::server_address) {
75                 $key_passwd = $main::server_passwd;
76             } 
77             &main::daemon_log("ServerPackage: key_passwd: $key_passwd", 7);
78             my $key_cipher = &create_ciphering($key_passwd);
79             $msg = &decrypt_msg($crypted_msg, $key_cipher);
80             &main::daemon_log("ServerPackages: decrypted msg: $msg", 7);
81             $msg_hash = $main::xml->XMLin($msg, ForceArray=>1);
82             #my $tmp = printf Dumper $msg_hash;
83             #&main::daemon_log("DEBUG: ServerPackages: xml hash: $tmp", 7);
84         };
85         if($@) {
86             &main::daemon_log("ServerPackage: key raise error: $@", 7);
87             $msg_flag += 1;
88         } else {
89             last;
90         }
91     } 
92     
93     if($msg_flag >= $l)  {
94         &main::daemon_log("WARNING: ServerPackage do not understand the message:", 5);
95         &main::daemon_log("$@", 7);
96         return;
97     }
99     # process incoming msg
100     my $header = @{$msg_hash->{header}}[0]; 
101     my $source = @{$msg_hash->{source}}[0];
103     &main::daemon_log("ServerPackages: msg from host:", 5);
104     &main::daemon_log("\t$host", 5);
105     &main::daemon_log("ServerPackages: header from msg:", 5);
106     &main::daemon_log("\t$header", 5);
107     &main::daemon_log("ServerPackages: msg to process:", 5);
108     &main::daemon_log("\t$msg", 5);
110     my @targets = @{$msg_hash->{target}};
111     my $len_targets = @targets;
112     if ($len_targets == 0){     
113         &main::daemon_log("ERROR: ServerPackages: no target specified for msg $header", 1);
115     }  elsif ($len_targets == 1){
116         # we have only one target symbol
118         my $target = $targets[0];
119         &main::daemon_log("SeverPackages: msg is for:", 7);
120         &main::daemon_log("\t$target", 7);
122         if ($target eq $main::server_address) {
123             # msg is for server
124             if ($header eq 'new_passwd'){ &new_passwd($msg_hash)}
125             elsif ($header eq 'here_i_am') { &here_i_am($msg_hash)}
126             elsif ($header eq 'who_has') { &who_has($msg_hash) }
127             elsif ($header eq 'who_has_i_do') { &who_has_i_do($msg_hash)}
128             elsif ($header eq 'update_status') { &update_status($msg_hash) }
129             elsif ($header eq 'got_ping') { &got_ping($msg_hash)}
130             elsif ($header eq 'get_load') { &execute_actions($msg_hash)}
131             else { &main::daemon_log("ERROR: ServerPackages: no function assigned to this msg", 5) }
133         
134        } elsif ($target eq "*") {
135             # msg is for all clients
137             my @target_addresses = keys(%$main::known_clients);
138             foreach my $target_address (@target_addresses) {
139                 if ($target_address eq $source) { next; }
140                 $msg_hash->{target} = [$target_address];
141                 &send_msg_hash2address($msg_hash, $target_address);
142             }           
143         } else {
144             # msg is for one host
146             if (exists $main::known_clients->{$target}) {
147                 &send_msg_hash2address($msg_hash, $target);
148             } elsif (exists $main::known_daemons->{$target}) {
149                 # target is known
150                 &send_msg_hash2address($msg_hash, $target);
151             } else {
152                 # target is not known
153                 &main::daemon_log("ERROR: ServerPackages: target $target is not known neither in known_clients nor in known_daemons", 1);
154             }
155         }
156     }
158     return ;
162 #===  FUNCTION  ================================================================
163 #         NAME:  got_ping
164 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
165 #      RETURNS:  nothing
166 #  DESCRIPTION:  process this incoming message
167 #===============================================================================
168 sub got_ping {
169     my ($msg_hash) = @_;
170     
171     my $source = @{$msg_hash->{source}}[0];
172     my $target = @{$msg_hash->{target}}[0];
173     my $header = @{$msg_hash->{header}}[0];
174     
175     if(exists $main::known_daemons->{$source}) {
176         &main::add_content2known_daemons(hostname=>$source, status=>$header);
177     } else {
178         &main::add_content2known_clients(hostname=>$source, status=>$header);
179     }
180     
181     return;
185 #===  FUNCTION  ================================================================
186 #         NAME:  new_passwd
187 #   PARAMETERS:  msg_hash - ref - hash from function create_xml_hash
188 #      RETURNS:  nothing
189 #  DESCRIPTION:  process this incoming message
190 #===============================================================================
191 sub new_passwd {
192     my ($msg_hash) = @_;
194     my $source = @{$msg_hash->{source}}[0];
195     my $passwd = @{$msg_hash->{new_passwd}}[0];
197     if (exists $main::known_daemons->{$source}) {
198         &main::add_content2known_daemons(hostname=>$source, status=>"new_passwd", passwd=>$passwd);
199         my $hash = &create_xml_hash("confirm_new_passwd", $main::server_address, $source);
200         &send_msg_hash2address($hash, $source);
202     } elsif (exists $main::known_clients->{$source}) {
203         &main::add_content2known_clients(hostname=>$source, status=>"new_passwd", passwd=>$passwd);
205     } else {
206         &main::daemon_log("ERROR: $source not known, neither in known_daemons nor in known_clients", 1)   
207     }
209     return;
213 #===  FUNCTION  ================================================================
214 #         NAME:  here_i_am
215 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
216 #      RETURNS:  nothing
217 #  DESCRIPTION:  process this incoming message
218 #===============================================================================
219 sub here_i_am {
220     my ($msg_hash) = @_;
222     my $source = @{$msg_hash->{source}}[0];
223     my $mac_address = @{$msg_hash->{mac_address}}[0];
224     my $out_hash;
226     # number of known clients
227     my $nu_clients = keys %$main::known_clients;
229     # check wether client address or mac address is already known
230     if (exists $main::known_clients->{$source}) {
231         &main::daemon_log("WARNING: $source is already known as a client", 1);
232         &main::daemon_log("WARNING: values for $source are being overwritten", 1);   
233         $nu_clients --;
234     }
236     # number of actual activ clients
237     my $act_nu_clients = $nu_clients;
239     &main::daemon_log("number of actual activ clients: $act_nu_clients", 5);
240     &main::daemon_log("number of maximal allowed clients: $main::max_clients", 5);
242     if($main::max_clients <= $act_nu_clients) {
243         my $out_hash = &create_xml_hash("denied", $main::server_address, $source);
244         &add_content2xml_hash($out_hash, "denied", "I_cannot_take_any_more_clients!");
245         my $passwd = @{$msg_hash->{new_passwd}}[0]; 
246         &send_msg_hash2address($out_hash, $source, $passwd);
247         return;
248     }
249     
250     # new client accepted
251     my $new_passwd = @{$msg_hash->{new_passwd}}[0];
253     # create known_daemons entry
254     my $events = @{$msg_hash->{events}}[0];
255     &main::create_known_client($source);
256     &main::add_content2known_clients(hostname=>$source, events=>$events, mac_address=>$mac_address, 
257                                 status=>"registered", passwd=>$new_passwd);
259     # return acknowledgement to client
260     $out_hash = &create_xml_hash("registered", $main::server_address, $source);
261     &send_msg_hash2address($out_hash, $source);
263     # notify registered client to bus
264     $out_hash = &main::create_xml_hash("new_client", $main::server_address, $main::bus_address, $source);
265     &main::send_msg_hash2bus($out_hash);
267     # give the new client his ldap config
268     &new_ldap_config($source);
270     return;
274 #===  FUNCTION  ================================================================
275 #         NAME:  who_has
276 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
277 #      RETURNS:  nothing 
278 #  DESCRIPTION:  process this incoming message
279 #===============================================================================
280 sub who_has {
281     my ($msg_hash) = @_ ;
282     
283     # what is your search pattern
284     my $search_pattern = @{$msg_hash->{who_has}}[0];
285     my $search_element = @{$msg_hash->{$search_pattern}}[0];
286     &main::daemon_log("who_has-msg looking for $search_pattern $search_element", 7);
288     # scanning known_clients for search_pattern
289     my @host_addresses = keys %$main::known_clients;
290     my $known_clients_entries = length @host_addresses;
291     my $host_address;
292     foreach my $host (@host_addresses) {
293         my $client_element = $main::known_clients->{$host}->{$search_pattern};
294         if ($search_element eq $client_element) {
295             $host_address = $host;
296             last;
297         }
298     }
299         
300     # search was successful
301     if (defined $host_address) {
302         my $source = @{$msg_hash->{source}}[0];
303         my $out_msg = &main::create_xml_hash("who_has_i_do", $main::server_address, $source, "mac_address");
304         &main::add_content2xml_hash($out_msg, "mac_address", $search_element);
305         &main::send_msg_hash2address($out_msg, $main::bus_address);
306     }
307     return;
311 sub who_has_i_do {
312     my ($msg_hash) = @_ ;
313     my $header = @{$msg_hash->{header}}[0];
314     my $source = @{$msg_hash->{source}}[0];
315     my $search_param = @{$msg_hash->{$header}}[0];
316     my $search_value = @{$msg_hash->{$search_param}}[0];
317     print "\ngot msg $header:\nserver $source has client with $search_param $search_value\n";
321 #===  FUNCTION  ================================================================
322 #         NAME:  new_ldap_config
323 #   PARAMETERS:  address - string - ip address and port of a host
324 #      RETURNS:  nothing
325 #  DESCRIPTION:  send to address the ldap configuration found for dn gotoLdapServer
326 #===============================================================================
327 sub new_ldap_config {
328     my ($address) = @_ ;
329     
330     if (not exists $main::known_clients->{$address}) {
331         &main::daemon_log("ERROR: $address does not exist in known_clients, cannot send him his ldap config", 1);
332         return;
333     }
334     
335     my $mac_address = $main::known_clients->{$address}->{"mac_address"};
336     if (not defined $mac_address) {
337         &main::daemon_log("ERROR: no mac address found for client $address", 1);
338         return;
339     }
341     # fetch dn
342     my $goHard_cmd = "ldapsearch -x '(&(objectClass=goHard)(macAddress=00:11:22:33:44:57))' dn gotoLdapServer";
343     my $dn;
344     my @gotoLdapServer;
345     open (PIPE, "$goHard_cmd 2>&1 |");
346 #    my $rbits = "";
347 #    vec($rbits, fileno PIPE, 1) = 1;
348 #    my $rout;
349 #    my $nf = select($rout=$rbits, undef, undef, $ldap_timeout);
350     while(<PIPE>) {
351         chomp $_;
352         # If it's a comment, goto next
353         if ($_ =~ m/^[#]/) { next;}
354         if ($_ =~ m/^dn: ([\S]+?)$/) {
355             $dn = $1;
356         } elsif ($_ =~ m/^gotoLdapServer: ([\S]+?)$/) {
357             push(@gotoLdapServer, $1);
358         }
359     }
360     close(PIPE);
361     
362     # no dn found
363     if (not defined $dn) {
364         &main::daemon_log("ERROR: no dn arose from command: $goHard_cmd", 1);
365         return;
366     }
367     
368     # no gotoLdapServer found
369     my $gosaGroupOfNames_cmd = "ldapsearch -x '(&(objectClass=gosaGroupOfNames)(member=$dn))' gotoLdapServer";
370     if (@gotoLdapServer == 0) {
371         open (PIPE, "$gosaGroupOfNames_cmd 2>&1 |");
372         while(<PIPE>) {
373             chomp $_;
374             if ($_ =~ m/^[#]/) { next; }
375             if ($_ =~ m/^gotoLdapServer: ([\S]+?)$/) {
376                 push(@gotoLdapServer, $1);
377             }
378         }
379         close(PIPE);
380     }
382     # still no gotoLdapServer found
383     if (@gotoLdapServer == 0) {
384         &main::daemon_log("ERROR: cannot find gotoLdapServer entry in command: $gosaGroupOfNames_cmd", 1);
385         return;
386     }
388     # sort @gotoLdapServer and then split of ranking
389     my @sorted_gotoLdapServer = sort(@gotoLdapServer);
390     @gotoLdapServer = reverse(@sorted_gotoLdapServer);
391     foreach (@gotoLdapServer) {
392         $_ =~ s/^\d://;
393     }
395     my $t = join(" ", @gotoLdapServer);
396  
397     my $out_hash = &main::create_xml_hash("new_ldap_config", $main::server_address, $address);
398     map(&main::add_content2xml_hash($out_hash, "new_ldap_config", $_), @gotoLdapServer);
399     &main::send_msg_hash2address($out_hash, $address);
401     return;
405 #===  FUNCTION  ================================================================
406 #         NAME:  execute_actions
407 #   PARAMETERS:  msg_hash - hash - hash from function create_xml_hash
408 #      RETURNS:  nothing
409 #  DESCRIPTION:  invokes the script specified in msg_hash which is located under
410 #                /etc/gosad/actions
411 #===============================================================================
412 sub execute_actions {
413     my ($msg_hash) = @_ ;
414     my $configdir= '/etc/gosad/actions/';
415     my $result;
417     my $header = @{$msg_hash->{header}}[0];
418     my $source = @{$msg_hash->{source}}[0];
419     my $target = @{$msg_hash->{target}}[0];
420  
421     if((not defined $source)
422             && (not defined $target)
423             && (not defined $header)) {
424         &main::daemon_log("ERROR: Entries missing in XML msg for gosad actions under /etc/gosad/actions");
425     } else {
426         my $parameters="";
427         my @params = @{$msg_hash->{$header}};
428         my $params = join(", ", @params);
429         &main::daemon_log("execute_actions: got parameters: $params", 5);
431         if (@params) {
432             foreach my $param (@params) {
433                 my $param_value = (&get_content_from_xml_hash($msg_hash, $param))[0];
434                 &main::daemon_log("execute_actions: parameter -> value: $param -> $param_value", 7);
435                 $parameters.= " ".$param_value;
436             }
437         }
439         my $cmd= $configdir.$header."$parameters";
440         &main::daemon_log("execute_actions: executing cmd: $cmd", 7);
441         $result= "";
442         open(PIPE, "$cmd 2>&1 |");
443         while(<PIPE>) {
444             $result.=$_;
445         }
446         close(PIPE);
447     }
449     # process the event result
452     return;
455 1;