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 {
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);
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 }
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) }
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 ;
159 }
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) = @_;
171 my $source = @{$msg_hash->{source}}[0];
172 my $target = @{$msg_hash->{target}}[0];
173 my $header = @{$msg_hash->{header}}[0];
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 }
181 return;
182 }
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;
210 }
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 }
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;
271 }
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) = @_ ;
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 }
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;
308 }
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";
318 }
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) = @_ ;
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 }
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);
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 }
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);
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;
402 }
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];
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;
453 }
455 1;