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