1 ## @file
2 # @details A GOsa-SI event module containing all functions common used by GOsa
3 # @brief Implementation of a GOsa-SI event module.
5 package gosaTriggered;
7 use strict;
8 use warnings;
10 use Exporter;
11 use GOSA::GosaSupportDaemon;
12 use Crypt::SmbHash;
13 use Net::ARP;
14 use Net::Ping;
15 use Socket;
16 use Time::HiRes qw( usleep);
17 use MIME::Base64;
18 use Data::Dumper;
20 our @ISA = qw(Exporter);
22 my @events = (
23 "get_events",
24 "get_login_usr_for_client",
25 "get_client_for_login_usr",
26 "gen_smb_hash",
27 "trigger_reload_syslog_config",
28 "trigger_reload_ntp_config",
29 "trigger_reload_ldap_config",
30 "network_completition",
31 "set_activated_for_installation",
32 "new_key_for_client",
33 "detect_hardware",
34 "trigger_action_localboot",
35 "trigger_action_faireboot",
36 "trigger_action_reboot",
37 "trigger_action_activate",
38 "trigger_action_lock",
39 "trigger_action_halt",
40 "trigger_action_update",
41 "trigger_action_reinstall",
42 "trigger_action_sysinfo",
43 "trigger_action_instant_update",
44 "trigger_action_rescan",
45 "trigger_action_wake",
46 "recreate_fai_server_db",
47 "recreate_fai_release_db",
48 "recreate_packages_list_db",
49 "send_user_msg",
50 "get_available_kernel",
51 "trigger_activate_new",
52 "get_hosts_with_module",
53 );
55 our @EXPORT = @events;
57 BEGIN {}
59 END {}
61 ### Start ######################################################################
63 ## @method get_events()
64 # A brief function returning a list of functions which are exported by importing the module.
65 # @return List of all provided functions
66 sub get_events {
67 return \@events;
68 }
70 ## @method send_usr_msg($msg, $msg_hash, $session_id)
71 # This function accepts usr messages from GOsa, split mulitple target messages to mulitiple single target messages and put all messages into messaging_db
72 # @param msg - STRING - xml message
73 # @param msg_hash - HASHREF - message information parsed into a hash
74 # @param session_id - INTEGER - POE session id of the processing of this message
75 # @return (out_msg) - ARRAY - Array containing the answer message from client
76 sub send_user_msg {
77 my ($msg, $msg_hash, $session_id) = @_ ;
78 my $header = @{$msg_hash->{'header'}}[0];
79 my $source = @{$msg_hash->{'source'}}[0];
80 my $target = @{$msg_hash->{'target'}}[0];
82 my $subject = @{$msg_hash->{'subject'}}[0];
83 my $from = @{$msg_hash->{'from'}}[0];
84 my @users = exists $msg_hash->{'user'} ? @{$msg_hash->{'user'}} : () ;
85 my @groups = exists $msg_hash->{'group'} ? @{$msg_hash->{'group'}} : ();
86 my $delivery_time = @{$msg_hash->{'delivery_time'}}[0];
87 my $message = @{$msg_hash->{'message'}}[0];
89 # # keep job queue uptodate if necessary
90 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
91 # if( defined $jobdb_id) {
92 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
93 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
94 # my $res = $main::job_db->exec_statement($sql_statement);
95 # }
97 # error handling
98 if (not $delivery_time =~ /^\d{14}$/) {
99 my $error_string = "delivery_time '$delivery_time' is not a valid timestamp, please use format 'yyyymmddhhmmss'";
100 &main::daemon_log("$session_id ERROR: $error_string", 1);
101 return &create_xml_string(&create_xml_hash($header, $target, $source, $error_string));
102 }
104 # determine new message id
105 my $new_msg_id = 1;
106 my $new_msg_id_sql = "SELECT MAX(id) FROM $main::messaging_tn";
107 my $new_msg_id_res = $main::messaging_db->exec_statement($new_msg_id_sql);
108 if (defined @{@{$new_msg_id_res}[0]}[0] ) {
109 $new_msg_id = int(@{@{$new_msg_id_res}[0]}[0]);
110 $new_msg_id += 1;
111 }
113 # highlight user name and group name
114 my @receiver_l;
115 @users = map(push(@receiver_l, "u_$_"), @users);
116 @groups = map(push(@receiver_l, "g_$_"), @groups);
118 # Sanitiy check of receivers list
119 if (@receiver_l == 0) {
120 &main::daemon_log("$session_id ERROR: 'send_usr_msg'-message contains neither a 'usr' nor a 'group' tag. No receiver specified.", 1);
121 return;
122 }
124 # add incoming message to messaging_db
125 my $func_dic = {table=>$main::messaging_tn,
126 primkey=>[],
127 id=>$new_msg_id,
128 subject=>$subject,
129 message_from=>$from,
130 message_to=>join(",", @receiver_l),
131 flag=>"n",
132 direction=>"in",
133 delivery_time=>$delivery_time,
134 message=>$message,
135 timestamp=>&get_time(),
136 };
137 my $res = $main::messaging_db->add_dbentry($func_dic);
138 if (not $res == 0) {
139 &main::daemon_log("$session_id ERROR: gosaTriggered.pm: cannot add message to message_db: $res", 1);
140 } else {
141 &main::daemon_log("$session_id INFO: gosaTriggered.pm: message with subject '".&decode_base64($subject)."' successfully added to message_db", 5);
142 }
144 return;
145 }
148 sub recreate_fai_server_db {
149 my ($msg, $msg_hash, $session_id) = @_ ;
150 my $out_msg;
152 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
153 # if( defined $jobdb_id) {
154 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
155 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
156 # my $res = $main::job_db->exec_statement($sql_statement);
157 # }
159 $main::fai_server_db->create_table("new_fai_server", \@main::fai_server_col_names);
160 &main::create_fai_server_db("new_fai_server",undef,"dont", $session_id);
161 $main::fai_server_db->move_table("new_fai_server", $main::fai_server_tn);
163 my @out_msg_l = ( $out_msg );
164 return @out_msg_l;
165 }
168 sub recreate_fai_release_db {
169 my ($msg, $msg_hash, $session_id) = @_ ;
170 my $out_msg;
172 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
173 # if( defined $jobdb_id) {
174 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
175 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
176 # my $res = $main::job_db->exec_statement($sql_statement);
177 # }
179 $main::fai_release_db->create_table("new_fai_release", \@main::fai_release_col_names);
180 &main::create_fai_release_db("new_fai_release", $session_id);
181 $main::fai_release_db->move_table("new_fai_release", $main::fai_release_tn);
183 my @out_msg_l = ( $out_msg );
184 return @out_msg_l;
185 }
188 sub recreate_packages_list_db {
189 my ($msg, $msg_hash, $session_id) = @_ ;
190 my $out_msg;
192 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
193 # if( defined $jobdb_id) {
194 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
195 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
196 # my $res = $main::job_db->exec_statement($sql_statement);
197 # }
199 &main::create_packages_list_db;
201 my @out_msg_l = ( $out_msg );
202 return @out_msg_l;
203 }
206 sub get_login_usr_for_client {
207 my ($msg, $msg_hash, $session_id) = @_ ;
208 my $header = @{$msg_hash->{'header'}}[0];
209 $header =~ s/^gosa_//;
210 my $source = @{$msg_hash->{'source'}}[0];
211 my $target = @{$msg_hash->{'target'}}[0];
212 my $client = @{$msg_hash->{'client'}}[0];
214 # # Set job status
215 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
216 # if( defined $jobdb_id) {
217 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
218 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
219 # my $res = $main::job_db->exec_statement($sql_statement);
220 # }
222 # If $client is a mac address
223 if ($client =~ /^\w\w:\w\w:\w\w:\w\w:\w\w:\w\w$/i)
224 {
225 # Search for hostname of $client within known_clients_db
226 my $sql = "SELECT * FROM $main::known_clients_tn WHERE macaddress LIKE '$client'";
227 my $res = $main::known_clients_db->select_dbentry($sql);
228 my $found = 0;
229 if (keys(%$res) == 1)
230 {
231 $found = 1;
232 $client = $res->{1}->{hostname};
233 }
234 if (not $found) # Do only if the first search results in nothing
235 {
236 # Search for hostname of $client within known_foreign_db
237 $sql = "SELECT * FROM $main::foreign_clients_tn WHERE macaddress LIKE '$client'";
238 $res = $main::foreign_clients_db->select_dbentry($sql);
239 if (keys(%$res) == 1)
240 {
241 $client = $res->{1}->{hostname};
242 }
243 }
244 }
246 # Search for logged in users at hostname
247 my $sql_statement = "SELECT * FROM $main::login_users_tn WHERE client LIKE '$client'";
248 my $res = $main::login_users_db->select_dbentry($sql_statement);
250 # Create answer message for GOsa
251 my $out_msg;
252 if (keys(%$res) == 0)
253 {
254 my $info = "INFO: No hits found in login_users_db for client '$client'";
255 $out_msg = &create_xml_string(&create_xml_hash($header, $target, $source, $info));
256 &main::daemon_log("$session_id ".$info, 5);
257 }
258 else
259 {
260 $out_msg = "<xml><header>$header</header><source>$target</source><target>$source</target>";
261 $out_msg .= &db_res2xml($res);
262 $out_msg .= "</xml>";
263 }
265 return ($out_msg);
266 }
269 sub get_client_for_login_usr {
270 my ($msg, $msg_hash, $session_id) = @_ ;
271 my $header = @{$msg_hash->{'header'}}[0];
272 $header =~ s/^gosa_//;
273 my $source = @{$msg_hash->{'source'}}[0];
274 my $target = @{$msg_hash->{'target'}}[0];
275 my $usr = @{$msg_hash->{'usr'}}[0];
277 # # Set job status
278 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
279 # if( defined $jobdb_id) {
280 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
281 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
282 # my $res = $main::job_db->exec_statement($sql_statement);
283 # }
285 # Search for clients where $usr is logged in
286 my $sql_statement = "SELECT * FROM $main::login_users_tn WHERE user LIKE '%$usr%'";
287 my $res = $main::login_users_db->select_dbentry($sql_statement);
289 # Create answer message for GOsa
290 my $out_msg = "<xml><header>$header</header><source>$target</source><target>$source</target>";
291 $out_msg .= &db_res2xml($res);
292 $out_msg .= "</xml>";
294 return ( $out_msg );
295 }
298 sub gen_smb_hash {
299 my ($msg, $msg_hash, $session_id) = @_ ;
300 my $source = @{$msg_hash->{source}}[0];
301 my $target = @{$msg_hash->{target}}[0];
302 my $password = @{$msg_hash->{password}}[0];
304 my %data= ('hash' => join(q[:], ntlmgen $password));
305 my $out_msg = &build_msg("gen_smb_hash", $target, $source, \%data );
306 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
307 if (defined $forward_to_gosa) {
308 $out_msg =~s/<\/xml>/<forward_to_gosa>$forward_to_gosa<\/forward_to_gosa><\/xml>/;
309 }
311 return ( $out_msg );
312 }
315 sub network_completition {
316 my ($msg, $msg_hash, $session_id) = @_ ;
317 my $source = @{$msg_hash->{source}}[0];
318 my $target = @{$msg_hash->{target}}[0];
319 my $name = @{$msg_hash->{hostname}}[0];
321 # Can we resolv the name?
322 my %data;
323 if (inet_aton($name)){
324 my $tmp = (inet_aton($name));
325 my $address = inet_ntoa($tmp);
326 my $p = Net::Ping->new('tcp');
327 my $mac= "";
328 if ($p->ping($address, 1)){
329 $mac = Net::ARP::arp_lookup("", $address);
330 }
332 %data= ('ip' => $address, 'mac' => $mac);
333 } else {
334 %data= ('ip' => '', 'mac' => '');
335 }
337 my $out_msg = &build_msg("network_completition", $target, $source, \%data );
338 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
339 if (defined $forward_to_gosa) {
340 $out_msg =~s/<\/xml>/<forward_to_gosa>$forward_to_gosa<\/forward_to_gosa><\/xml>/;
341 }
343 return ( $out_msg );
344 }
347 sub detect_hardware {
348 my ($msg, $msg_hash, $session_id) = @_ ;
349 # just forward msg to client, but dont forget to split off 'gosa_' in header
350 my $source = @{$msg_hash->{source}}[0];
351 my $mac = @{$msg_hash->{macaddress}}[0];
352 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
353 if( defined $jobdb_id) {
354 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
355 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
356 my $res = $main::job_db->exec_statement($sql_statement);
357 }
359 my $out_hash = &create_xml_hash("detect_hardware", $source, $mac);
360 if( defined $jobdb_id ) {
361 &add_content2xml_hash($out_hash, 'jobdb_id', $jobdb_id);
362 }
363 my $out_msg = &create_xml_string($out_hash);
365 my @out_msg_l = ( $out_msg );
366 return @out_msg_l;
368 }
370 sub trigger_reload_syslog_config {
371 my ($msg, $msg_hash, $session_id) = @_ ;
373 # Sanity check of macaddress
374 # TODO
376 my $macaddress = @{$msg_hash->{macaddress}}[0];
378 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
379 # if( defined $jobdb_id) {
380 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
381 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
382 # my $res = $main::job_db->exec_statement($sql_statement);
383 # }
385 my $out_msg = &ClientPackages::new_syslog_config($macaddress, $session_id);
386 my @out_msg_l = ( $out_msg );
388 return @out_msg_l;
391 }
393 sub trigger_reload_ntp_config {
394 my ($msg, $msg_hash, $session_id) = @_ ;
396 # Sanity check of macaddress
397 # TODO
399 my $macaddress = @{$msg_hash->{macaddress}}[0];
401 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
402 # if( defined $jobdb_id) {
403 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
404 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
405 # my $res = $main::job_db->exec_statement($sql_statement);
406 # }
408 my $out_msg = &ClientPackages::new_ntp_config($macaddress, $session_id);
409 my @out_msg_l = ( $out_msg );
411 return @out_msg_l;
413 }
415 sub trigger_reload_ldap_config {
416 my ($msg, $msg_hash, $session_id) = @_ ;
417 my $mac = @{$msg_hash->{macaddress}}[0];
419 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
420 # if( defined $jobdb_id) {
421 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
422 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
423 # my $res = $main::job_db->exec_statement($sql_statement);
424 # }
426 my $out_msg = &ClientPackages::new_ldap_config($mac, $session_id);
427 my @out_msg_l = ( $out_msg );
429 return @out_msg_l;
430 }
433 sub set_activated_for_installation {
434 my ($msg, $msg_hash, $session_id) = @_;
435 my $header = @{$msg_hash->{header}}[0];
436 my $source = @{$msg_hash->{source}}[0];
437 my $mac= (defined($msg_hash->{'macaddress'}))?@{$msg_hash->{'macaddress'}}[0]:undef;
438 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
439 my @out_msg_l;
441 # TODO Sanity check macAddress defined
443 # # update status of job
444 # if( defined $jobdb_id) {
445 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
446 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
447 # my $res = $main::job_db->exec_statement($sql_statement);
448 # }
450 # If a client gets a 'set_activated_for_installation' msg, always deliver a fresh 'new_ldap_config'
451 # just for backup and robustness purposes
452 my $ldap_out_msg = &ClientPackages::new_ldap_config($mac, $session_id);
453 push(@out_msg_l, $ldap_out_msg);
455 # create set_activated_for_installation message for delivery
456 my $out_hash = &create_xml_hash("set_activated_for_installation", $source, $mac);
457 if( defined $jobdb_id ) {
458 &add_content2xml_hash($out_hash, 'jobdb_id', $jobdb_id);
459 }
460 my $out_msg = &create_xml_string($out_hash);
461 push(@out_msg_l, $out_msg);
463 return @out_msg_l;
464 }
467 sub trigger_action_faireboot {
468 my ($msg, $msg_hash, $session_id) = @_;
469 my $mac = @{$msg_hash->{macaddress}}[0];
470 my $source = @{$msg_hash->{source}}[0];
472 # Create message for client
473 my $out_msg = &main::create_xml_string(&main::create_xml_hash("trigger_action_faireboot", $source, $mac));
475 # Set LDAP states
476 &main::change_goto_state('locked', \@{$msg_hash->{macaddress}}, $session_id);
477 &main::change_fai_state('install', \@{$msg_hash->{macaddress}}, $session_id);
479 # # Set job to status 'done', job will be deleted automatically
480 # my $sql_statement = "UPDATE $main::job_queue_tn ".
481 # "SET status='done', modified='1'".
482 # "WHERE (macaddress LIKE '$mac' AND status='processing')";
483 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
484 # my $res = $main::job_db->update_dbentry( $sql_statement );
486 return ( $out_msg );
487 }
490 sub trigger_action_lock {
491 my ($msg, $msg_hash, $session_id) = @_;
493 # Set LDAP state
494 &main::change_goto_state('locked', \@{$msg_hash->{macaddress}}, $session_id);
496 # # Set job status
497 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
498 # if( defined $jobdb_id) {
499 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
500 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
501 # my $res = $main::job_db->exec_statement($sql_statement);
502 # }
504 return;
505 }
508 sub trigger_action_activate {
509 my ($msg, $msg_hash, $session_id) = @_;
510 my $mac = @{$msg_hash->{macaddress}}[0];
511 my $source = @{$msg_hash->{source}}[0];
513 # Set LDAP state
514 &main::change_goto_state('active', \@{$msg_hash->{macaddress}}, $session_id);
516 # # Set job status
517 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
518 # if( defined $jobdb_id) {
519 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
520 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
521 # my $res = $main::job_db->exec_statement($sql_statement);
522 # }
524 # Create message for client
525 my $out_hash = &create_xml_hash("set_activated_for_installation", $source, $mac);
526 if( exists $msg_hash->{'jobdb_id'} ) {
527 &add_content2xml_hash($out_hash, 'jobdb_id', @{$msg_hash->{'jobdb_id'}}[0]);
528 }
529 my $out_msg = &create_xml_string($out_hash);
531 return ( $out_msg );
533 }
536 sub trigger_action_localboot {
537 my ($msg, $msg_hash, $session_id) = @_;
538 my $source = $msg_hash->{source}[0];
539 my $mac = $msg_hash->{macaddress}[0];
540 my $target = $msg_hash->{target}[0];
541 my @out_msg_l;
543 # Create message for client
544 my $out_msg = &main::create_xml_string(&main::create_xml_hash("trigger_action_localboot", $source, $mac));
545 push(@out_msg_l, $out_msg);
547 # Check for running jobs. In that case return a message to GOsa that running jobs have to be deleted/aborted
548 # befor trigger_action_localboot could be effective. Running jobs usually sets FAIstate and GOtomode to
549 # what they need again and again and overwrite the 'trigger_action_localboot' setting
550 my $job_sql= "SELECT * FROM $main::job_queue_tn WHERE macaddress LIKE '$mac'";
551 my $job_res = $main::job_db->select_dbentry($job_sql);
552 my $job_res_count = keys(%$job_res);
553 if ($job_res_count) {
554 push(@out_msg_l, "<xml><header>answer</header><source>$target</source><target>GOSA</target><answer1>existing_job_in_queue</answer1></xml>");
555 }
557 # Set LDAP state
558 &main::change_fai_state('localboot', \@{$msg_hash->{macaddress}}, $session_id);
560 # # Set job status
561 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
562 # if( defined $jobdb_id) {
563 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
564 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
565 # my $res = $main::job_db->exec_statement($sql_statement);
566 # }
568 return @out_msg_l;
569 }
572 sub trigger_action_halt {
573 my ($msg, $msg_hash, $session_id) = @_;
574 my $source = $msg_hash->{source}[0];
575 my $mac = $msg_hash->{macaddress}[0];
577 # Create message for client
578 my $out_msg = &main::create_xml_string(&main::create_xml_hash("trigger_action_halt", $source, $mac));
580 # # Set job status
581 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
582 # if( defined $jobdb_id) {
583 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
584 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
585 # my $res = $main::job_db->exec_statement($sql_statement);
586 # }
588 return ($out_msg);
589 }
592 sub trigger_action_reboot {
593 my ($msg, $msg_hash, $session_id) = @_;
594 my $source = $msg_hash->{source}[0];
595 my $mac = $msg_hash->{macaddress}[0];
597 # Create message for client
598 my $out_msg = &main::create_xml_string(&main::create_xml_hash("trigger_action_reboot", $source, $mac));
600 # Set LDAP state
601 &main::change_fai_state('reboot', \@{$msg_hash->{macaddress}}, $session_id);
603 return ($out_msg);
604 }
607 sub trigger_action_reinstall {
608 my ($msg, $msg_hash, $session_id) = @_;
609 my $source = $msg_hash->{source}[0];
610 my $mac = $msg_hash->{macaddress}[0];
612 # Create message for client
613 my $out_msg = &main::create_xml_string(&main::create_xml_hash("trigger_action_reinstall", $source, $mac));
615 # Set LDAP state
616 &main::change_fai_state('reinstall', \@{$msg_hash->{macaddress}}, $session_id);
618 # Create wakeup message for all foreign server
619 my %data = ( 'macaddress' => \@{$msg_hash->{macaddress}} );
620 my $wake_msg = &build_msg("trigger_wake", "GOSA", "KNOWN_SERVER", \%data);
622 # Invoke trigger wake for this gosa-si-server
623 &main::server_server_com::trigger_wake($msg, $msg_hash, $session_id);
625 return ($wake_msg, $msg);
626 }
629 sub trigger_action_update {
630 my ($msg, $msg_hash, $session_id) = @_;
631 my $source = $msg_hash->{source}[0];
632 my $mac = $msg_hash->{macaddress}[0];
634 # Create message for client
635 my $out_msg = &main::create_xml_string(&main::create_xml_hash("trigger_action_update", $source, $mac));
637 # Set LDAP state
638 &main::change_fai_state('update', \@{$msg_hash->{macaddress}}, $session_id);
640 # Create wakeup message for all foreign server
641 my %data = ( 'macaddress' => \@{$msg_hash->{macaddress}} );
642 my $wake_msg = &build_msg("trigger_wake", "GOSA", "KNOWN_SERVER", \%data);
644 # Invoke trigger wake for this gosa-si-server
645 &main::server_server_com::trigger_wake($msg, $msg_hash, $session_id);
647 return ($wake_msg, $msg);
648 }
651 sub trigger_action_instant_update {
652 my ($msg, $msg_hash, $session_id) = @_;
653 my $source = $msg_hash->{source}[0];
654 my $mac = $msg_hash->{macaddress}[0];
656 # Create message for client
657 my $out_msg = &main::create_xml_string(&main::create_xml_hash("trigger_action_instant_update", $source, $mac));
659 # Set LDAP state
660 &main::change_fai_state('update', \@{$msg_hash->{macaddress}}, $session_id);
662 # # Set job status
663 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
664 # if( defined $jobdb_id) {
665 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
666 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
667 # my $res = $main::job_db->exec_statement($sql_statement);
668 # }
670 # Create wakeup message for all foreign server
671 my %data = ( 'macaddress' => \@{$msg_hash->{macaddress}} );
672 my $wake_msg = &build_msg("trigger_wake", "GOSA", "KNOWN_SERVER", \%data);
674 # Invoke trigger wake for this gosa-si-server
675 &main::server_server_com::trigger_wake($msg, $msg_hash, $session_id);
677 return ($wake_msg, $msg);
678 }
681 sub new_key_for_client {
682 my ($msg, $msg_hash, $session_id) = @_;
683 my $source = $msg_hash->{source}[0];
684 my $mac = $msg_hash->{macaddress}[0];
686 # Create message for client
687 my $out_msg = &main::create_xml_string(&main::create_xml_hash("new_key", $source, $mac));
689 # # Set job status
690 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
691 # if( defined $jobdb_id) {
692 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
693 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
694 # my $res = $main::job_db->exec_statement($sql_statement);
695 # }
697 return ($out_msg);
698 }
701 sub trigger_action_rescan {
702 my ($msg, $msg_hash, $session_id) = @_;
703 my $source = $msg_hash->{source}[0];
704 my $mac = $msg_hash->{macaddress}[0];
706 # Create message for client
707 my $out_msg = &main::create_xml_string(&main::create_xml_hash("detect_hardware", $source, $mac));
709 # # Set job status
710 # my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
711 # if( defined $jobdb_id) {
712 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
713 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
714 # my $res = $main::job_db->exec_statement($sql_statement);
715 # }
717 return ( $out_msg );
718 }
721 sub trigger_action_wake {
722 my ($msg, $msg_hash, $session_id) = @_;
723 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
725 # # Set job status
726 # if( defined $jobdb_id) {
727 # my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE ((id=$jobdb_id) AND (NOT status='done'))";
728 # &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
729 # my $res = $main::job_db->exec_statement($sql_statement);
730 # }
732 # Create wakeup message for all foreign server
733 my $out_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
734 foreach (@{$msg_hash->{'macaddress'}}) {
735 &add_content2xml_hash($out_hash, 'macaddress', $_);
736 }
737 if (defined $jobdb_id){
738 &add_content2xml_hash($out_hash, 'jobdb_id', $jobdb_id);
739 }
740 my $out_msg = &create_xml_string($out_hash);
742 # Invoke trigger wake for this gosa-si-server
743 &main::server_server_com::trigger_wake($out_msg, $out_hash, $session_id);
745 return ( $out_msg );
746 }
749 sub get_available_kernel {
750 my ($msg, $msg_hash, $session_id) = @_;
751 my $source = @{$msg_hash->{'source'}}[0];
752 my $target = @{$msg_hash->{'target'}}[0];
753 my $fai_release= @{$msg_hash->{'fai_release'}}[0];
754 my @kernel;
756 # Get Kernel packages for release
757 my $sql_statement = "SELECT * FROM $main::packages_list_tn WHERE distribution='$fai_release' AND package LIKE 'linux\-image\-%'";
758 my $res_hash = $main::packages_list_db->select_dbentry($sql_statement);
759 my %data;
760 my $i=1;
761 foreach my $package (keys %{$res_hash}) {
762 $data{"answer".$i++}= $data{"answer".$i++}= ${$res_hash}{$package}->{'package'};
763 }
764 $data{"answer".$i++}= "default";
766 # Create answer for GOsa
767 my $out_msg = &build_msg("get_available_kernel", $target, $source, \%data);
768 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
769 if (defined $forward_to_gosa) {
770 $out_msg =~s/<\/xml>/<forward_to_gosa>$forward_to_gosa<\/forward_to_gosa><\/xml>/;
771 }
773 return ( $out_msg );
774 }
776 sub trigger_activate_new {
777 my ($msg, $msg_hash, $session_id) = @_;
778 my $source = @{$msg_hash->{'source'}}[0];
779 my $target = @{$msg_hash->{'target'}}[0];
780 my $header= @{$msg_hash->{'header'}}[0];
781 my $mac= (defined($msg_hash->{'mac'}))?@{$msg_hash->{'mac'}}[0]:undef;
782 my $ogroup= (defined($msg_hash->{'ogroup'}))?@{$msg_hash->{'ogroup'}}[0]:undef;
783 my $timestamp= (defined($msg_hash->{'timestamp'}))?@{$msg_hash->{'timestamp'}}[0]:undef;
784 my $base= (defined($msg_hash->{'base'}))?@{$msg_hash->{'base'}}[0]:undef;
785 my $hostname= (defined($msg_hash->{'fqdn'}))?@{$msg_hash->{'fqdn'}}[0]:undef;
786 my $ip_address= (defined($msg_hash->{'ip'}))?@{$msg_hash->{'ip'}}[0]:undef;
787 my $dhcp_statement= (defined($msg_hash->{'dhcp'}))?@{$msg_hash->{'dhcp'}}[0]:undef;
788 my $jobdb_id= (defined($msg_hash->{'jobdb_id'}))?@{$msg_hash->{'jobdb_id'}}[0]:undef;
790 # Sanity check for base
791 if (ref($base) eq "HASH") {
792 # Incoming msg has a xml tag 'base' but no content
793 $base = undef;
794 }
796 # In case that the client is sleeping, wake it up
797 my %data = ( 'macaddress' => $mac );
798 my $wake_msg = &build_msg("trigger_wake", "GOSA", "KNOWN_SERVER", \%data);
799 &main::server_server_com::trigger_wake($msg, $msg_hash, $session_id);
800 my $sql_statement= "SELECT * FROM $main::known_server_tn";
801 my $query_res = $main::known_server_db->select_dbentry( $sql_statement );
802 while( my ($hit_num, $hit) = each %{ $query_res } ) {
803 my $host_name = $hit->{hostname};
804 my $host_key = $hit->{hostkey};
805 $wake_msg =~ s/<target>\S+<\/target>/<target>$host_name<\/target>/g;
806 my $error = &main::send_msg_to_target($wake_msg, $host_name, $host_key, $header, $session_id);
807 }
809 my $ldap_entry;
810 my $ogroup_entry;
811 my $changed_attributes_counter = 0;
813 my $activate_client = 0;
814 my $ldap_handle=&main::get_ldap_handle();
816 if(defined($ogroup)) {
817 my $ldap_mesg= $ldap_handle->search(
818 base => $main::ldap_base,
819 scope => 'sub',
820 filter => "(&(objectClass=gosaGroupOfnames)(cn=$ogroup))",
821 );
822 if($ldap_mesg->count == 1) {
823 $ogroup_entry= $ldap_mesg->pop_entry();
824 &main::daemon_log("$session_id DEBUG: A GosaGroupOfNames with cn '$ogroup' was found in base '".$main::ldap_base."'!", 5);
825 } elsif ($ldap_mesg->count == 0) {
826 &main::daemon_log("$session_id ERROR: A GosaGroupOfNames with cn '$ogroup' was not found in base '".$main::ldap_base."'!", 1);
827 $main::job_db->exec_statement("UPDATE ".$main::job_queue_tn." SET status = 'waiting', timestamp = '".(&calc_timestamp(&get_time(), 'plus', 60))."' WHERE id = $jobdb_id");
828 &main::release_ldap_handle($ldap_handle);
829 return undef;
830 } else {
831 &main::daemon_log("$session_id ERROR: More than one ObjectGroups with cn '$ogroup' was found in base '".$main::ldap_base."'!", 1);
832 $main::job_db->exec_statement("UPDATE ".$main::job_queue_tn." SET status = 'waiting', timestamp = '".(&calc_timestamp(&get_time(), 'plus', 60))."' WHERE id = $jobdb_id");
833 &main::release_ldap_handle($ldap_handle);
834 return undef;
835 }
837 # build the base, use optional base parameter or take it from ogroup
838 if(!(defined($base) && (length($base) > 0))) {
839 # Subtract the ObjectGroup cn
840 $base = $1 if $ogroup_entry->dn =~ /cn=$ogroup,ou=groups,(.*)$/;
841 &main::daemon_log("$session_id DEBUG: New base for system with mac address '$mac' is '$base'", 5);
842 }
843 }
845 # prepend ou=systems (configurable through config)
846 $base = $main::new_systems_ou.",".$base;
848 # Search for an existing entry (should be in ou=incoming)
849 my $ldap_mesg= $ldap_handle->search(
850 base => $main::ldap_base,
851 scope => 'sub',
852 filter => "(&(objectClass=GOhard)(|(macAddress=$mac)(dhcpHWaddress=$mac)))",
853 );
855 # TODO: Find a way to guess an ip address for hosts with no ldap entry (MAC->ARP->IP)
856 if($ldap_mesg->count == 1) {
857 &main::daemon_log("$session_id DEBUG: One system with mac address '$mac' was found in base '".$main::ldap_base."'!", 5);
858 # Get the entry from LDAP
859 $ldap_entry= $ldap_mesg->pop_entry();
861 if(!($ldap_entry->dn() eq "cn=".$ldap_entry->get_value('cn').",$base")) {
862 # Move the entry to the new ou
863 $ldap_entry->changetype('moddn');
864 $ldap_entry->add(
865 newrdn => "cn=".$ldap_entry->get_value('cn'),
866 deleteoldrdn => 1,
867 newsuperior => $base,
868 );
869 # To prevent replication problems just re-queue the job with 10 seconds in the future
870 my $moddn_result = $ldap_entry->update($ldap_handle);
871 if ($moddn_result->code() != 0) {
872 my $error_string = "Moving the system with mac address '$mac' to new base '$base' failed (code '".$moddn_result->code()."') with '".$moddn_result->{'errorMessage'}."'!";
873 &main::daemon_log("$session_id ERROR: $error_string", 1);
874 my $sql = "UPDATE $main::job_queue_tn SET status='error', result='$error_string' WHERE id=$jobdb_id";
875 &main::release_ldap_handle($ldap_handle);
876 return undef;
877 } else {
878 &main::daemon_log("$session_id INFO: System with mac address '$mac' was moved to base '".$main::ldap_base."'! Re-queuing job.", 4);
879 $main::job_db->exec_statement("UPDATE ".$main::job_queue_tn." SET status = 'waiting', timestamp = '".(&calc_timestamp(&get_time(), 'plus', 10))."' WHERE id = $jobdb_id");
880 &main::release_ldap_handle($ldap_handle);
881 return undef;
882 }
883 }
885 } elsif ($ldap_mesg->count == 0) {
886 &main::daemon_log("$session_id WARNING: No System with mac address '$mac' was found in base '".$main::ldap_base."'! Re-queuing job.", 4);
887 my $sql_statement = "UPDATE ".$main::job_queue_tn.
888 " SET status='waiting', timestamp = '".(&calc_timestamp(&get_time(), 'plus', 60))."' ".
889 " WHERE id = $jobdb_id";
890 $main::job_db->exec_statement($sql_statement);
891 &main::release_ldap_handle($ldap_handle);
892 return undef;
893 }
895 $ldap_mesg= $ldap_handle->search(
896 base => $main::ldap_base,
897 scope => 'sub',
898 filter => "(&(objectClass=GOhard)(|(macAddress=$mac)(dhcpHWaddress=$mac)))",
899 );
901 # TODO: Find a way to guess an ip address for hosts with no ldap entry (MAC->ARP->IP)
902 if($ldap_mesg->count == 1) {
903 $ldap_entry= $ldap_mesg->pop_entry();
904 # Check for needed objectClasses
905 my $oclasses = $ldap_entry->get_value('objectClass', asref => 1);
906 foreach my $oclass ("FAIobject", "GOhard", "gotoWorkstation") {
907 if(!(scalar grep $_ eq $oclass, map {$_ => 1} @$oclasses)) {
908 &main::daemon_log("$session_id INFO: Adding objectClass '$oclass' to system entry with mac adress '$mac'", 1);
909 $ldap_entry->add(
910 objectClass => $oclass,
911 );
912 my $oclass_result = $ldap_entry->update($ldap_handle);
913 if ($oclass_result->code() != 0) {
914 &main::daemon_log("$session_id ERROR: Adding the ObjectClass '$oclass' failed (code '".$oclass_result->code()."') with '".$oclass_result->{'errorMessage'}."'!", 1);
915 } else {
916 &main::daemon_log("$session_id DEBUG: Adding the ObjectClass '$oclass' to '".($ldap_entry->dn())."' succeeded!", 5);
917 }
918 }
919 }
921 # Set FAIstate
922 if(defined($ldap_entry->get_value('FAIstate'))) {
923 if(!($ldap_entry->get_value('FAIstate') eq 'install')) {
924 $ldap_entry->replace(
925 'FAIstate' => 'install'
926 );
927 my $replace_result = $ldap_entry->update($ldap_handle);
928 if ($replace_result->code() != 0) {
929 &main::daemon_log("$session_id ERROR: Setting the FAIstate to install failed with code '".$replace_result->code()."') and message '".$replace_result->{'errorMessage'}."'!", 1);
930 } else {
931 &main::daemon_log("$session_id DEBUG: Setting the FAIstate to install for '".($ldap_entry->dn())."' succeeded!", 5);
932 }
933 }
934 } else {
935 $ldap_entry->add(
936 'FAIstate' => 'install'
937 );
938 my $add_result = $ldap_entry->update($ldap_handle);
939 if ($add_result->code() != 0) {
940 &main::daemon_log("$session_id ERROR: Setting the FAIstate to install failed with code '".$add_result->code()."') and message '".$add_result->{'errorMessage'}."'!", 1);
941 } else {
942 &main::daemon_log("$session_id DEBUG: Setting the FAIstate to install for '".($ldap_entry->dn())."' succeeded!", 5);
943 }
944 }
947 } elsif ($ldap_mesg->count == 0) {
948 # TODO: Create a new entry
949 # $ldap_entry = Net::LDAP::Entry->new();
950 # $ldap_entry->dn("cn=$mac,$base");
951 &main::daemon_log("$session_id WARNING: No System with mac address '$mac' was found in base '".$main::ldap_base."'! Re-queuing job.", 4);
952 $main::job_db->exec_statement("UPDATE ".$main::job_queue_tn." SET status = 'waiting', timestamp = '".(&calc_timestamp(&get_time(), 'plus', 60))."' WHERE id = $jobdb_id");
953 &main::release_ldap_handle($ldap_handle);
954 return undef;
955 } else {
956 &main::daemon_log("$session_id ERROR: More than one system with mac address '$mac' was found in base '".$main::ldap_base."'!", 1);
957 }
959 # Add to ObjectGroup
960 my $ogroup_member = $ogroup_entry->get_value('member', asref => 1);
961 if( (!defined($ogroup_member)) ||
962 (!defined($ldap_entry)) ||
963 (!defined($ldap_entry->dn)) ||
964 (!(scalar grep $_ eq $ldap_entry->dn, @{$ogroup_member}))) {
965 $ogroup_entry->add (
966 'member' => $ldap_entry->dn(),
967 );
968 my $ogroup_result = $ogroup_entry->update($ldap_handle);
969 if ($ogroup_result->code() != 0) {
970 &main::daemon_log("$session_id ERROR: Updating the ObjectGroup '$ogroup' failed (code '".$ogroup_result->code()."') with '".$ogroup_result->{'errorMessage'}."'!", 1);
971 } else {
972 &main::daemon_log("$session_id DEBUG: Updating the ObjectGroup '$ogroup' for member '".($ldap_entry->dn())."' succeeded!", 5);
973 }
974 } else {
975 &main::daemon_log("$session_id DEBUG: System with mac address '$mac' is already a member of ObjectGroup '$ogroup'.", 5);
976 }
978 # Finally set gotoMode to active
979 if(defined($ldap_entry->get_value('gotoMode'))) {
980 if(!($ldap_entry->get_value('gotoMode') eq 'active')) {
981 $ldap_entry->replace(
982 'gotoMode' => 'active'
983 );
984 my $activate_result = $ldap_entry->update($ldap_handle);
985 if ($activate_result->code() != 0) {
986 &main::daemon_log("$session_id ERROR: Activating system '".$ldap_entry->dn()."' failed (code '".$activate_result->code()."') with '".$activate_result->{'errorMessage'}."'!", 1);
987 } else {
988 &main::daemon_log("$session_id DEBUG: Activating system '".$ldap_entry->dn()."' succeeded!", 5);
989 $activate_client = 1;
990 }
991 } else {
992 $activate_client = 1;
993 }
994 } else {
995 $ldap_entry->add(
996 'gotoMode' => 'active'
997 );
998 my $activate_result = $ldap_entry->update($ldap_handle);
999 if ($activate_result->code() != 0) {
1000 &main::daemon_log("$session_id ERROR: Activating system '".$ldap_entry->dn()."' failed (code '".$activate_result->code()."') with '".$activate_result->{'errorMessage'}."'!", 1);
1001 } else {
1002 &main::daemon_log("$session_id DEBUG: Activating system '".$ldap_entry->dn()."' succeeded!", 5);
1003 $activate_client = 1;
1004 }
1005 }
1007 if($activate_client == 1) {
1008 &main::daemon_log("$session_id DEBUG: Activating system with mac address '$mac'!", 5);
1010 # Create delivery list
1011 my @out_msg_l;
1013 # Set job to done
1014 $main::job_db->exec_statement("UPDATE jobs SET status = 'done' WHERE id = $jobdb_id");
1016 # create set_activated_for_installation message for delivery
1017 my $out_hash = &create_xml_hash("set_activated_for_installation", $source, $mac);
1018 my $out_msg = &create_xml_string($out_hash);
1019 push(@out_msg_l, $out_msg);
1021 # Return delivery list of messages
1022 &main::release_ldap_handle($ldap_handle);
1023 return @out_msg_l;
1025 } else {
1026 &main::daemon_log("$session_id WARNING: Activating system with mac address '$mac' failed! Re-queuing job.", 4);
1027 $main::job_db->exec_statement("UPDATE ".$main::job_queue_tn." SET status = 'waiting', timestamp = '".(&calc_timestamp(&get_time(), 'plus', 60))."' WHERE id = $jobdb_id");
1028 }
1029 &main::release_ldap_handle($ldap_handle);
1030 return undef;
1031 }
1034 ## @method get_hosts_with_module
1035 # Reports all GOsa-si-server providing the given module.
1036 # @param msg - STRING - xml message with tag get_hosts_with_module
1037 # @param msg_hash - HASHREF - message information parsed into a hash
1038 # @param session_id - INTEGER - POE session id of the processing of this message
1039 # @return out_msg - STRING - feedback to GOsa in success and error case
1040 sub get_hosts_with_module {
1041 my ($msg, $msg_hash, $session_id) = @_;
1042 my $source = @{$msg_hash->{'source'}}[0];
1043 my $target = @{$msg_hash->{'target'}}[0];
1044 my $header= @{$msg_hash->{'header'}}[0];
1045 my $module_name = @{$msg_hash->{'module_name'}}[0];
1046 my $out_hash = &create_xml_hash($header, $target, $source);
1048 # Sanity check of module_name
1049 if ((not exists $msg_hash->{'module_name'}) || (@{$msg_hash->{'module_name'}} != 1)) {
1050 &add_content2xml_hash($out_hash, "error_string", "no module_name specified or module_name tag invalid");
1051 &add_content2xml_hash($out_hash, "error", "module_name");
1052 &main::daemon_log("$session_id ERROR: no module_name specified or module_name tag invalid: $msg", 1);
1053 return (&create_xml_string($out_hash));
1054 }
1056 my $out_msg = &create_xml_string($out_hash);
1058 # Check localhost for module_name
1059 if (exists @{$main::known_modules->{'GosaPackages'}}[2]->{$module_name}) {
1060 my ($local_ip, $local_port) = split(/:/, $target);
1061 my $network_interface= &get_interface_for_ip($local_ip);
1062 my $local_mac = &get_mac_for_interface($network_interface);
1063 $out_msg =~ s/<\/xml>/<result>host0<\/result> <\/xml>/;
1064 my $host_infos = "<ip>$local_ip</ip>";
1065 $host_infos .= " <mac>$local_mac</mac>";
1066 $out_msg =~ s/<\/xml>/\n<answer0> $host_infos <\/answer0> \n <\/xml>/;
1067 }
1069 # Search for opsi hosts in server_db
1070 my $sql = "SELECT * FROM $main::known_server_tn WHERE loaded_modules LIKE '%$module_name%'";
1071 my $res = $main::known_server_db->select_dbentry($sql);
1072 while (my ($hit_id, $hit_hash) = each %$res) {
1073 $out_msg =~ s/<\/xml>/<result>host$hit_id<\/result> <\/xml>/;
1074 my $host_infos = "<ip>".$hit_hash->{'hostname'}."</ip>";
1075 $host_infos .= " <mac>".$hit_hash->{'macaddress'}."</mac>";
1076 $out_msg =~ s/<\/xml>/\n<answer$hit_id> $host_infos <\/answer$hit_id> \n <\/xml>/;
1077 }
1079 return $out_msg;
1080 }
1082 # vim:ts=4:shiftwidth:expandtab
1083 1;