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.
4 # @author Andreas Rettenberger <rettenberger@gonicus.de>
5 # @date 2008
6 # @version 1.0
8 package gosaTriggered;
9 use Exporter;
10 @ISA = qw(Exporter);
11 my @events = (
12 "get_events",
13 "get_login_usr_for_client",
14 "get_client_for_login_usr",
15 "gen_smb_hash",
16 "trigger_reload_ldap_config",
17 "ping",
18 "network_completition",
19 "set_activated_for_installation",
20 "new_key_for_client",
21 "detect_hardware",
22 "get_login_usr",
23 "get_login_client",
24 "trigger_action_localboot",
25 "trigger_action_faireboot",
26 "trigger_action_reboot",
27 "trigger_action_activate",
28 "trigger_action_lock",
29 "trigger_action_halt",
30 "trigger_action_update",
31 "trigger_action_reinstall",
32 "trigger_action_memcheck",
33 "trigger_action_sysinfo",
34 "trigger_action_instant_update",
35 "trigger_action_rescan",
36 "trigger_action_wake",
37 "recreate_fai_server_db",
38 "recreate_fai_release_db",
39 "recreate_packages_list_db",
40 "send_user_msg",
41 "get_available_kernel",
42 "trigger_activate_new",
43 # "get_dak_keyring",
44 # "import_dak_key",
45 # "remove_dak_key",
46 # "get_dak_queue",
47 );
48 @EXPORT = @events;
50 use strict;
51 use warnings;
52 use GOSA::GosaSupportDaemon;
53 use Data::Dumper;
54 use Crypt::SmbHash;
55 use Net::ARP;
56 use Net::Ping;
57 use Socket;
58 use Time::HiRes qw( usleep);
59 use MIME::Base64;
61 BEGIN {}
63 END {}
65 ### Start ######################################################################
67 ## @method get_events()
68 # A brief function returning a list of functions which are exported by importing the module.
69 # @return List of all provided functions
70 sub get_events {
71 return \@events;
72 }
74 ## @method send_usr_msg($msg, $msg_hash, $session_id)
75 # This function accepts usr messages from GOsa, split mulitple target messages to mulitiple single target messages and put all messages into messaging_db
76 # @param msg - STRING - xml message
77 # @param msg_hash - HASHREF - message information parsed into a hash
78 # @param session_id - INTEGER - POE session id of the processing of this message
79 # @return (out_msg) - ARRAY - Array containing the answer message from client
80 sub send_user_msg {
81 my ($msg, $msg_hash, $session_id) = @_ ;
82 my $header = @{$msg_hash->{'header'}}[0];
83 my $source = @{$msg_hash->{'source'}}[0];
84 my $target = @{$msg_hash->{'target'}}[0];
86 #my $subject = &decode_base64(@{$msg_hash->{'subject'}}[0]); # just for debugging
87 my $subject = @{$msg_hash->{'subject'}}[0];
88 my $from = @{$msg_hash->{'from'}}[0];
89 my @users = exists $msg_hash->{'users'} ? @{$msg_hash->{'users'}} : () ;
90 my @groups = exists $msg_hash->{'groups'} ? @{$msg_hash->{'groups'}} : ();
91 my $delivery_time = @{$msg_hash->{'delivery_time'}}[0];
92 #my $message = &decode_base64(@{$msg_hash->{'message'}}[0]); # just for debugging
93 my $message = @{$msg_hash->{'message'}}[0];
95 # keep job queue uptodate if necessary
96 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
97 if( defined $jobdb_id) {
98 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
99 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
100 my $res = $main::job_db->exec_statement($sql_statement);
101 }
103 # error handling
104 if (not $delivery_time =~ /^\d{14}$/) {
105 my $error_string = "delivery_time '$delivery_time' is not a valid timestamp, please use format 'yyyymmddhhmmss'";
106 &main::daemon_log("$session_id ERROR: $error_string", 1);
107 return &create_xml_string(&create_xml_hash($header, $target, $source, $error_string));
108 }
110 # determine new message id
111 my $new_msg_id = 1;
112 my $new_msg_id_sql = "SELECT MAX(CAST(id AS INTEGER)) FROM $main::messaging_tn";
113 my $new_msg_id_res = $main::messaging_db->exec_statement($new_msg_id_sql);
114 if (defined @{@{$new_msg_id_res}[0]}[0] ) {
115 $new_msg_id = int(@{@{$new_msg_id_res}[0]}[0]);
116 $new_msg_id += 1;
117 }
119 # highlight user name and group name
120 my @receiver_l;
121 @users = map(push(@receiver_l, "u_$_"), @users);
122 @groups = map(push(@receiver_l, "g_$_"), @groups);
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 '$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";
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";
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";
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 my $source = @{$msg_hash->{'source'}}[0];
210 my $target = @{$msg_hash->{'target'}}[0];
211 my $client = @{$msg_hash->{'client'}}[0];
213 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
214 if( defined $jobdb_id) {
215 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
216 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
217 my $res = $main::job_db->exec_statement($sql_statement);
218 }
220 $header =~ s/^gosa_//;
222 my $sql_statement = "SELECT * FROM known_clients WHERE hostname='$client' OR macaddress LIKE '$client'";
223 my $res = $main::known_clients_db->select_dbentry($sql_statement);
225 my $out_msg = "<xml><header>$header</header><source>$target</source><target>$source</target>";
226 $out_msg .= &db_res2xml($res);
227 $out_msg .= "</xml>";
229 my @out_msg_l = ( $out_msg );
230 return @out_msg_l;
231 }
234 sub get_client_for_login_usr {
235 my ($msg, $msg_hash, $session_id) = @_ ;
236 my $header = @{$msg_hash->{'header'}}[0];
237 my $source = @{$msg_hash->{'source'}}[0];
238 my $target = @{$msg_hash->{'target'}}[0];
240 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
241 if( defined $jobdb_id) {
242 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
243 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
244 my $res = $main::job_db->exec_statement($sql_statement);
245 }
247 my $usr = @{$msg_hash->{'usr'}}[0];
248 $header =~ s/^gosa_//;
250 my $sql_statement = "SELECT * FROM known_clients WHERE login LIKE '%$usr%'";
251 my $res = $main::known_clients_db->select_dbentry($sql_statement);
253 my $out_msg = "<xml><header>$header</header><source>$target</source><target>$source</target>";
254 $out_msg .= &db_res2xml($res);
255 $out_msg .= "</xml>";
256 my @out_msg_l = ( $out_msg );
257 return @out_msg_l;
259 }
262 sub ping {
263 my ($msg, $msg_hash, $session_id) = @_ ;
264 my $header = @{$msg_hash->{header}}[0];
265 my $target = @{$msg_hash->{target}}[0];
266 my $source = @{$msg_hash->{source}}[0];
267 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
268 my $error = 0;
269 my $answer_msg;
270 my ($sql, $res);
272 if( defined $jobdb_id) {
273 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
274 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
275 my $res = $main::job_db->exec_statement($sql_statement);
276 }
278 # send message
279 $sql = "SELECT * FROM $main::known_clients_tn WHERE ((hostname='$target') || (macaddress LIKE '$target'))";
280 $res = $main::known_clients_db->exec_statement($sql);
282 # sanity check of db result
283 my ($host_name, $host_key);
284 if ((defined $res) && (@$res > 0) && @{@$res[0]} > 0) {
285 $host_name = @{@$res[0]}[0];
286 $host_key = @{@$res[0]}[2];
287 } else {
288 &main::daemon_log("$session_id ERROR: cannot determine host_name and host_key from known_clients_db at function ping\n$msg", 1);
289 my %data = ( 'answer_xml' => 'host not found in known_clients_db' );
290 $answer_msg = &build_msg("got_ping_error", $target, $source, \%data);
291 $error = 1;
292 }
294 if (not $error) {
295 my $client_hash = &create_xml_hash("ping", $main::server_address, $host_name);
296 &add_content2xml_hash($client_hash, 'session_id', $session_id);
297 my $client_msg = &create_xml_string($client_hash);
298 &main::send_msg_to_target($client_msg, $host_name, $host_key, $header, $session_id);
300 my $message_id;
301 my $i = 0;
302 while (1) {
303 $i++;
304 $sql = "SELECT * FROM $main::incoming_tn WHERE headertag='answer_$session_id'";
305 $res = $main::incoming_db->exec_statement($sql);
306 if (ref @$res[0] eq "ARRAY") {
307 $message_id = @{@$res[0]}[0];
308 last;
309 }
311 # do not run into a endless loop
312 if ($i > 100) { last; }
313 usleep(100000);
314 }
316 # if an answer to the question exists
317 if (defined $message_id) {
318 my $answer_xml = @{@$res[0]}[3];
319 my %data = ( 'answer_xml' => 'bin noch da' );
320 $answer_msg = &build_msg("got_ping", $target, $source, \%data);
321 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
322 if (defined $forward_to_gosa){
323 $answer_msg =~s/<\/xml>/<forward_to_gosa>$forward_to_gosa<\/forward_to_gosa><\/xml>/;
324 }
325 $sql = "DELETE FROM $main::incoming_tn WHERE id=$message_id";
326 $res = $main::incoming_db->exec_statement($sql);
327 }
329 }
331 return ( $answer_msg );
332 }
336 sub gen_smb_hash {
337 my ($msg, $msg_hash, $session_id) = @_ ;
338 my $source = @{$msg_hash->{source}}[0];
339 my $target = @{$msg_hash->{target}}[0];
340 my $password = @{$msg_hash->{password}}[0];
342 my %data= ('hash' => join(q[:], ntlmgen $password));
343 my $out_msg = &build_msg("gen_smb_hash", $target, $source, \%data );
344 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
345 if (defined $forward_to_gosa) {
346 $out_msg =~s/<\/xml>/<forward_to_gosa>$forward_to_gosa<\/forward_to_gosa><\/xml>/;
347 }
349 return ( $out_msg );
350 }
353 sub network_completition {
354 my ($msg, $msg_hash, $session_id) = @_ ;
355 my $source = @{$msg_hash->{source}}[0];
356 my $target = @{$msg_hash->{target}}[0];
357 my $name = @{$msg_hash->{hostname}}[0];
359 # Can we resolv the name?
360 my %data;
361 if (inet_aton($name)){
362 my $address = inet_ntoa(inet_aton($name));
363 my $p = Net::Ping->new('tcp');
364 my $mac= "";
365 if ($p->ping($address, 1)){
366 $mac = Net::ARP::arp_lookup("", $address);
367 }
369 %data= ('ip' => $address, 'mac' => $mac);
370 } else {
371 %data= ('ip' => '', 'mac' => '');
372 }
374 my $out_msg = &build_msg("network_completition", $target, $source, \%data );
375 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
376 if (defined $forward_to_gosa) {
377 $out_msg =~s/<\/xml>/<forward_to_gosa>$forward_to_gosa<\/forward_to_gosa><\/xml>/;
378 }
380 return ( $out_msg );
381 }
384 sub detect_hardware {
385 my ($msg, $msg_hash, $session_id) = @_ ;
386 # just forward msg to client, but dont forget to split off 'gosa_' in header
387 my $source = @{$msg_hash->{source}}[0];
388 my $target = @{$msg_hash->{target}}[0];
389 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
390 if( defined $jobdb_id) {
391 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
392 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
393 my $res = $main::job_db->exec_statement($sql_statement);
394 }
396 my $out_hash = &create_xml_hash("detect_hardware", $source, $target);
397 if( defined $jobdb_id ) {
398 &add_content2xml_hash($out_hash, 'jobdb_id', $jobdb_id);
399 }
400 my $out_msg = &create_xml_string($out_hash);
402 my @out_msg_l = ( $out_msg );
403 return @out_msg_l;
405 }
408 sub trigger_reload_ldap_config {
409 my ($msg, $msg_hash, $session_id) = @_ ;
410 my $target = @{$msg_hash->{target}}[0];
412 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
413 if( defined $jobdb_id) {
414 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
415 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
416 my $res = $main::job_db->exec_statement($sql_statement);
417 }
419 my $out_msg = &ClientPackages::new_ldap_config($target, $session_id);
420 my @out_msg_l = ( $out_msg );
422 return @out_msg_l;
423 }
426 sub set_activated_for_installation {
427 my ($msg, $msg_hash, $session_id) = @_;
428 my $header = @{$msg_hash->{header}}[0];
429 my $source = @{$msg_hash->{source}}[0];
430 my $target = @{$msg_hash->{target}}[0];
431 my @out_msg_l;
433 # update status of job
434 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
435 if( defined $jobdb_id) {
436 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
437 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
438 my $res = $main::job_db->exec_statement($sql_statement);
439 }
441 # create set_activated_for_installation message for delivery
442 my $out_hash = &create_xml_hash("set_activated_for_installation", $source, $target);
443 if( defined $jobdb_id ) {
444 &add_content2xml_hash($out_hash, 'jobdb_id', $jobdb_id);
445 }
446 my $out_msg = &create_xml_string($out_hash);
447 push(@out_msg_l, $out_msg);
449 return @out_msg_l;
450 }
453 sub trigger_action_faireboot {
454 my ($msg, $msg_hash, $session_id) = @_;
455 my $macaddress = @{$msg_hash->{macaddress}}[0];
456 my $source = @{$msg_hash->{source}}[0];
458 my @out_msg_l;
459 $msg =~ s/<header>gosa_trigger_action_faireboot<\/header>/<header>trigger_action_faireboot<\/header>/;
460 push(@out_msg_l, $msg);
462 &main::change_goto_state('locked', \@{$msg_hash->{macaddress}}, $session_id);
463 &main::change_fai_state('install', \@{$msg_hash->{macaddress}}, $session_id);
465 # set job to status 'done', job will be deleted automatically
466 my $sql_statement = "UPDATE $main::job_queue_tn ".
467 "SET status='done', modified='1'".
468 "WHERE (macaddress='$macaddress' AND status='processing')";
469 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
470 my $res = $main::job_db->update_dbentry( $sql_statement );
472 return @out_msg_l;
473 }
476 sub trigger_action_lock {
477 my ($msg, $msg_hash, $session_id) = @_;
478 my $macaddress = @{$msg_hash->{macaddress}}[0];
479 my $source = @{$msg_hash->{source}}[0];
481 &main::change_goto_state('locked', \@{$msg_hash->{macaddress}}, $session_id);
482 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
483 if( defined $jobdb_id) {
484 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
485 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
486 my $res = $main::job_db->exec_statement($sql_statement);
487 }
489 my @out_msg_l;
490 return @out_msg_l;
491 }
494 sub trigger_action_activate {
495 my ($msg, $msg_hash, $session_id) = @_;
496 my $macaddress = @{$msg_hash->{macaddress}}[0];
497 my $source = @{$msg_hash->{source}}[0];
499 &main::change_goto_state('active', \@{$msg_hash->{macaddress}}, $session_id);
500 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
501 if( defined $jobdb_id) {
502 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
503 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
504 my $res = $main::job_db->exec_statement($sql_statement);
505 }
507 my $out_hash = &create_xml_hash("set_activated_for_installation", $source, $macaddress);
508 if( exists $msg_hash->{'jobdb_id'} ) {
509 &add_content2xml_hash($out_hash, 'jobdb_id', @{$msg_hash->{'jobdb_id'}}[0]);
510 }
511 my $out_msg = &create_xml_string($out_hash);
513 return ( $out_msg );
514 }
517 sub trigger_action_localboot {
518 my ($msg, $msg_hash, $session_id) = @_;
519 $msg =~ s/<header>gosa_trigger_action_localboot<\/header>/<header>trigger_action_localboot<\/header>/;
520 &main::change_fai_state('localboot', \@{$msg_hash->{macaddress}}, $session_id);
521 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
522 if( defined $jobdb_id) {
523 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
524 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
525 my $res = $main::job_db->exec_statement($sql_statement);
526 }
528 my @out_msg_l = ($msg);
529 return @out_msg_l;
530 }
533 sub trigger_action_halt {
534 my ($msg, $msg_hash, $session_id) = @_;
535 $msg =~ s/<header>gosa_trigger_action_halt<\/header>/<header>trigger_action_halt<\/header>/;
537 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
538 if( defined $jobdb_id) {
539 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
540 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
541 my $res = $main::job_db->exec_statement($sql_statement);
542 }
544 my @out_msg_l = ($msg);
545 return @out_msg_l;
546 }
549 sub trigger_action_reboot {
550 my ($msg, $msg_hash, $session_id) = @_;
551 $msg =~ s/<header>gosa_trigger_action_reboot<\/header>/<header>trigger_action_reboot<\/header>/;
553 &main::change_fai_state('reboot', \@{$msg_hash->{macaddress}}, $session_id);
554 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
555 if( defined $jobdb_id) {
556 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
557 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
558 my $res = $main::job_db->exec_statement($sql_statement);
559 }
561 my @out_msg_l = ($msg);
562 return @out_msg_l;
563 }
566 sub trigger_action_memcheck {
567 my ($msg, $msg_hash, $session_id) = @_ ;
568 $msg =~ s/<header>gosa_trigger_action_memcheck<\/header>/<header>trigger_action_memcheck<\/header>/;
570 &main::change_fai_state('memcheck', \@{$msg_hash->{macaddress}}, $session_id);
571 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
572 if( defined $jobdb_id) {
573 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
574 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
575 my $res = $main::job_db->exec_statement($sql_statement);
576 }
578 my @out_msg_l = ($msg);
579 return @out_msg_l;
580 }
583 sub trigger_action_reinstall {
584 my ($msg, $msg_hash, $session_id) = @_;
585 $msg =~ s/<header>gosa_trigger_action_reinstall<\/header>/<header>trigger_action_reinstall<\/header>/;
587 &main::change_fai_state('reinstall', \@{$msg_hash->{macaddress}}, $session_id);
589 my %data = ( 'macAddress' => \@{$msg_hash->{macaddress}} );
590 my $wake_msg = &build_msg("trigger_wake", "GOSA", "KNOWN_SERVER", \%data);
591 my @out_msg_l = ($wake_msg, $msg);
592 return @out_msg_l;
593 }
596 sub trigger_action_update {
597 my ($msg, $msg_hash, $session_id) = @_;
598 $msg =~ s/<header>gosa_trigger_action_update<\/header>/<header>trigger_action_update<\/header>/;
600 &main::change_fai_state('update', \@{$msg_hash->{macaddress}}, $session_id);
602 my %data = ( 'macAddress' => \@{$msg_hash->{macaddress}} );
603 my $wake_msg = &build_msg("trigger_wake", "GOSA", "KNOWN_SERVER", \%data);
604 my @out_msg_l = ($wake_msg, $msg);
605 return @out_msg_l;
606 }
609 sub trigger_action_instant_update {
610 my ($msg, $msg_hash, $session_id) = @_;
611 $msg =~ s/<header>gosa_trigger_action_instant_update<\/header>/<header>trigger_action_instant_update<\/header>/;
613 &main::change_fai_state('update', \@{$msg_hash->{macaddress}}, $session_id);
615 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
616 if( defined $jobdb_id) {
617 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
618 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
619 my $res = $main::job_db->exec_statement($sql_statement);
620 }
622 my %data = ( 'macAddress' => \@{$msg_hash->{macaddress}} );
623 my $wake_msg = &build_msg("trigger_wake", "GOSA", "KNOWN_SERVER", \%data);
624 my @out_msg_l = ($wake_msg, $msg);
625 return @out_msg_l;
626 }
629 sub trigger_action_sysinfo {
630 my ($msg, $msg_hash, $session_id) = @_;
631 $msg =~ s/<header>gosa_trigger_action_sysinfo<\/header>/<header>trigger_action_sysinfo<\/header>/;
633 &main::change_fai_state('sysinfo', \@{$msg_hash->{macaddress}}, $session_id);
634 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
635 if( defined $jobdb_id) {
636 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
637 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
638 my $res = $main::job_db->exec_statement($sql_statement);
639 }
641 my @out_msg_l = ($msg);
642 return @out_msg_l;
643 }
646 sub new_key_for_client {
647 my ($msg, $msg_hash, $session_id) = @_;
649 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
650 if( defined $jobdb_id) {
651 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
652 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
653 my $res = $main::job_db->exec_statement($sql_statement);
654 }
656 $msg =~ s/<header>gosa_new_key_for_client<\/header>/<header>new_key<\/header>/;
657 my @out_msg_l = ($msg);
658 return @out_msg_l;
659 }
662 sub trigger_action_rescan {
663 my ($msg, $msg_hash, $session_id) = @_;
665 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
666 if( defined $jobdb_id) {
667 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
668 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
669 my $res = $main::job_db->exec_statement($sql_statement);
670 }
673 $msg =~ s/<header>gosa_trigger_action_rescan<\/header>/<header>detect_hardware<header>/;
674 my @out_msg_l = ($msg);
675 return @out_msg_l;
676 }
679 sub trigger_action_wake {
680 my ($msg, $msg_hash, $session_id) = @_;
682 my $jobdb_id = @{$msg_hash->{'jobdb_id'}}[0];
683 if( defined $jobdb_id) {
684 my $sql_statement = "UPDATE $main::job_queue_tn SET status='processed' WHERE id=jobdb_id";
685 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
686 my $res = $main::job_db->exec_statement($sql_statement);
687 }
689 # build out message
690 my $out_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
691 foreach (@{$msg_hash->{target}}) {
692 &add_content2xml_hash($out_hash, 'macAddress', $_);
693 }
694 my $out_msg = &create_xml_string($out_hash);
696 # invoke trigger wake for this gosa-si-server
697 &main::server_server_com::trigger_wake($out_msg, $out_hash, $session_id);
699 # send trigger wake to all other gosa-si-server
700 my @out_msg_l = ($out_msg);
701 return @out_msg_l;
702 }
705 sub get_available_kernel {
706 my ($msg, $msg_hash, $session_id) = @_;
708 my $source = @{$msg_hash->{'source'}}[0];
709 my $target = @{$msg_hash->{'target'}}[0];
710 my $release= @{$msg_hash->{'release'}}[0];
712 my @kernel;
713 # Get Kernel packages for release
714 my $sql_statement = "SELECT * FROM $main::packages_list_tn WHERE distribution='$release' AND package LIKE 'linux\-image\-%'";
715 my $res_hash = $main::packages_list_db->select_dbentry($sql_statement);
716 my %data;
717 my $i=1;
719 foreach my $package (keys %{$res_hash}) {
720 $data{"answer".$i++}= $data{"answer".$i++}= ${$res_hash}{$package}->{'package'};
721 }
722 $data{"answer".$i++}= "default";
724 my $out_msg = &build_msg("get_available_kernel", $target, $source, \%data);
725 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
726 if (defined $forward_to_gosa) {
727 $out_msg =~s/<\/xml>/<forward_to_gosa>$forward_to_gosa<\/forward_to_gosa><\/xml>/;
728 }
730 return ( $out_msg );
731 }
734 sub trigger_activate_new {
735 my ($msg, $msg_hash, $session_id) = @_;
737 my $source = @{$msg_hash->{'source'}}[0];
738 my $target = @{$msg_hash->{'target'}}[0];
739 my $header= @{$msg_hash->{'header'}}[0];
740 my $mac= (defined($msg_hash->{'mac'}))?@{$msg_hash->{'mac'}}[0]:undef;
741 my $ogroup= (defined($msg_hash->{'ogroup'}))?@{$msg_hash->{'ogroup'}}[0]:undef;
742 my $timestamp= (defined($msg_hash->{'timestamp'}))?@{$msg_hash->{'timestamp'}}[0]:undef;
743 my $base= (defined($msg_hash->{'base'}))?@{$msg_hash->{'base'}}[0]:undef;
744 my $hostname= (defined($msg_hash->{'fqdn'}))?@{$msg_hash->{'fqdn'}}[0]:undef;
745 my $ip_address= (defined($msg_hash->{'ip'}))?@{$msg_hash->{'ip'}}[0]:undef;
746 my $dhcp_statement= (defined($msg_hash->{'dhcp'}))?@{$msg_hash->{'dhcp'}}[0]:undef;
747 my $jobdb_id= (defined($msg_hash->{'jobdb_id'}))?@{$msg_hash->{'jobdb_id'}}[0]:undef;
749 my $ldap_handle = &main::get_ldap_handle();
750 my $ldap_entry;
751 my $ogroup_entry;
752 my $changed_attributes_counter = 0;
754 eval {
756 my $ldap_mesg= $ldap_handle->search(
757 base => $main::ldap_base,
758 scope => 'sub',
759 filter => "(&(objectClass=gosaGroupOfnames)(cn=$ogroup))",
760 );
761 if($ldap_mesg->count == 1) {
762 $ogroup_entry= $ldap_mesg->pop_entry();
763 } elsif ($ldap_mesg->count == 0) {
764 &main::daemon_log("ERROR: A GosaGroupOfNames with cn '$ogroup' was not found in base '".$main::ldap_base."'!", 1);
765 } else {
766 &main::daemon_log("ERROR: More than one ObjectGroups with cn '$ogroup' was found in base '".$main::ldap_base."'!", 1);
767 }
769 # build the base, use optional base parameter or take it from ogroup
770 if(!(defined($base) && (length($base) > 0))) {
771 # Subtract the ObjectGroup cn
772 $base = $1 if $ogroup_entry->dn =~ /cn=$ogroup,ou=groups,(.*)$/;
773 }
775 # prepend ou=systems (configurable through config)
776 $base = $main::new_systems_ou.",".$base;
778 # Search for an existing entry (should be in ou=incoming)
779 $ldap_mesg= $ldap_handle->search(
780 base => $main::ldap_base,
781 scope => 'sub',
782 filter => "(&(objectClass=GOhard)(|(macAddress=$mac)(dhcpHWaddress=$mac)))",
783 );
785 # TODO: Find a way to guess an ip address for hosts with no ldap entry (MAC->ARP->IP)
787 if($ldap_mesg->count == 1) {
788 &main::daemon_log("DEBUG: One system with mac address '$mac' was found in base '".$main::ldap_base."'!", 6);
789 # Get the entry from LDAP
790 $ldap_entry= $ldap_mesg->pop_entry();
792 if(!($ldap_entry->dn() eq "cn=".$ldap_entry->get_value('cn').",$base")) {
793 # Move the entry to the new ou
794 $ldap_entry->changetype('moddn');
795 $ldap_entry->add(
796 newrdn => "cn=".$ldap_entry->get_value('cn'),
797 deleteoldrdn => 1,
798 newsuperior => $base,
799 );
800 }
802 }
804 $ldap_mesg= $ldap_handle->search(
805 base => $main::ldap_base,
806 scope => 'sub',
807 filter => "(&(objectClass=GOhard)(|(macAddress=$mac)(dhcpHWaddress=$mac)))",
808 );
810 # TODO: Find a way to guess an ip address for hosts with no ldap entry (MAC->ARP->IP)
812 if($ldap_mesg->count == 1) {
813 $ldap_entry= $ldap_mesg->pop_entry();
814 # Check for needed objectClasses
815 my $oclasses = $ldap_entry->get_value('objectClass', asref => 1);
816 foreach my $oclass ("FAIobject", "GOhard") {
817 if(!(scalar grep $_ eq $oclass, map {$_ => 1} @$oclasses)) {
818 &main::daemon_log("Adding objectClass $oclass", 1);
819 $ldap_entry->add(
820 objectClass => $oclass,
821 );
822 my $oclass_result = $ldap_entry->update($ldap_handle);
823 }
824 }
826 # Set FAIstate
827 if(defined($ldap_entry->get_value('FAIstate'))) {
828 if(!($ldap_entry->get_value('FAIstate') eq 'install')) {
829 $ldap_entry->replace(
830 'FAIstate' => 'install'
831 );
832 my $replace_result = $ldap_entry->update($ldap_handle);
833 }
834 } else {
835 $ldap_entry->add(
836 'FAIstate' => 'install'
837 );
838 my $add_result = $ldap_entry->update($ldap_handle);
839 }
842 } elsif ($ldap_mesg->count == 0) {
843 # TODO: Create a new entry
844 # $ldap_entry = Net::LDAP::Entry->new();
845 # $ldap_entry->dn("cn=$mac,$base");
846 &main::daemon_log("WARNING: No System with mac address '$mac' was found in base '".$main::ldap_base."'! Re-queuing job.", 4);
847 $main::job_db->exec_statement("UPDATE jobs SET status = 'waiting', timestamp = '".&get_time()."' WHERE id = $jobdb_id");
848 } else {
849 &main::daemon_log("ERROR: More than one system with mac address '$mac' was found in base '".$main::ldap_base."'!", 1);
850 }
852 # Add to ObjectGroup
853 if(!(scalar grep $_, map {$_ => 1} $ogroup_entry->get_value('member', asref => 1))) {
854 $ogroup_entry->add (
855 'member' => $ldap_entry->dn(),
856 );
857 my $ogroup_result = $ogroup_entry->update($ldap_handle);
858 if ($ogroup_result->code() != 0) {
859 &main::daemon_log("ERROR: Updating the ObjectGroup '$ogroup' failed (code '".$ogroup_result->code()."') with '".$ogroup_result->{'errorMessage'}."'!", 1);
860 }
861 }
863 # Finally set gotoMode to active
864 if(defined($ldap_entry->get_value('gotoMode'))) {
865 if(!($ldap_entry->get_value('gotoMode') eq 'active')) {
866 $ldap_entry->replace(
867 'gotoMode' => 'active'
868 );
869 my $activate_result = $ldap_entry->update($ldap_handle);
870 if ($activate_result->code() != 0) {
871 &main::daemon_log("ERROR: Activating system '".$ldap_entry->dn()."' failed (code '".$activate_result->code()."') with '".$activate_result->{'errorMessage'}."'!", 1);
872 }
873 }
874 } else {
875 $ldap_entry->add(
876 'gotoMode' => 'active'
877 );
878 my $activate_result = $ldap_entry->update($ldap_handle);
879 if ($activate_result->code() != 0) {
880 &main::daemon_log("ERROR: Activating system '".$ldap_entry->dn()."' failed (code '".$activate_result->code()."') with '".$activate_result->{'errorMessage'}."'!", 1);
881 }
882 }
883 };
884 if($@) {
885 &main::daemon_log("ERROR: activate_new failed with '$@'!", 1);
886 }
888 # Delete job
889 $main::job_db->exec_statement("DELETE FROM jobs WHERE id = $jobdb_id");
891 # create set_activated_for_installation message for delivery
892 my $out_hash = &create_xml_hash("set_activated_for_installation", $source, $target);
893 my $out_msg = &create_xml_string($out_hash);
894 my @out_msg_l = ($out_msg);
896 return @out_msg_l;
897 }
900 #sub get_dak_keyring {
901 # my ($msg, $msg_hash) = @_;
902 # my $source = @{$msg_hash->{'source'}}[0];
903 # my $target = @{$msg_hash->{'target'}}[0];
904 # my $header= @{$msg_hash->{'header'}}[0];
905 # my $session_id = @{$msg_hash->{'session_id'}}[0];
906 #
907 # # build return message with twisted target and source
908 # my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
909 # &add_content2xml_hash($out_hash, "session_id", $session_id);
910 #
911 # my @keys;
912 # my %data;
913 #
914 # my $keyring = $main::dak_signing_keys_directory."/keyring.gpg";
915 #
916 # my $gpg_cmd = `which gpg`; chomp $gpg_cmd;
917 # my $gpg = "$gpg_cmd --no-default-keyring --no-random-seed --keyring $keyring";
918 #
919 # # Check if the keyrings are in place and readable
920 # if(
921 # &run_as($main::dak_user, "test -r $keyring")->{'resultCode'} != 0
922 # ) {
923 # &add_content2xml_hash($out_hash, "error", "DAK Keyring is not readable");
924 # } else {
925 # my $command = "$gpg --list-keys";
926 # my $output = &run_as($main::dak_user, $command);
927 # &main::daemon_log("$session_id DEBUG: ".$output->{'command'}, 7);
928 #
929 # my $i=0;
930 # foreach (@{$output->{'output'}}) {
931 # if ($_ =~ m/^pub\s.*$/) {
932 # ($keys[$i]->{'pub'}->{'length'}, $keys[$i]->{'pub'}->{'uid'}, $keys[$i]->{'pub'}->{'created'}) = ($1, $2, $3)
933 # if $_ =~ m/^pub\s*?(\w*?)\/(\w*?)\s(\d{4}-\d{2}-\d{2})/;
934 # $keys[$i]->{'pub'}->{'expires'} = $1 if $_ =~ m/^pub\s*?\w*?\/\w*?\s\d{4}-\d{2}-\d{2}\s\[expires:\s(\d{4}-\d{2}-\d{2})\]/;
935 # $keys[$i]->{'pub'}->{'expired'} = $1 if $_ =~ m/^pub\s*?\w*?\/\w*?\s\d{4}-\d{2}-\d{2}\s\[expired:\s(\d{4}-\d{2}-\d{2})\]/;
936 # } elsif ($_ =~ m/^sub\s.*$/) {
937 # ($keys[$i]->{'sub'}->{'length'}, $keys[$i]->{'sub'}->{'uid'}, $keys[$i]->{'sub'}->{'created'}) = ($1, $2, $3)
938 # if $_ =~ m/^sub\s*?(\w*?)\/(\w*?)\s(\d{4}-\d{2}-\d{2})/;
939 # $keys[$i]->{'sub'}->{'expires'} = $1 if $_ =~ m/^pub\s*?\w*?\/\w*?\s\d{4}-\d{2}-\d{2}\s\[expires:\s(\d{4}-\d{2}-\d{2})\]/;
940 # $keys[$i]->{'sub'}->{'expired'} = $1 if $_ =~ m/^pub\s*?\w*?\/\w*?\s\d{4}-\d{2}-\d{2}\s\[expired:\s(\d{4}-\d{2}-\d{2})\]/;
941 # } elsif ($_ =~ m/^uid\s.*$/) {
942 # push @{$keys[$i]->{'uid'}}, $1 if $_ =~ m/^uid\s*?([^\s].*?)$/;
943 # } elsif ($_ =~ m/^$/) {
944 # $i++;
945 # }
946 # }
947 # }
948 #
949 # my $i=0;
950 # foreach my $key (@keys) {
951 # # &main::daemon_log(Dumper($key));
952 # &add_content2xml_hash($out_hash, "answer".$i++, $key);
953 # }
954 # my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
955 # if (defined $forward_to_gosa) {
956 # &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
957 # }
958 # return &create_xml_string($out_hash);
959 #}
960 #
961 #
962 #sub import_dak_key {
963 # my ($msg, $msg_hash) = @_;
964 # my $source = @{$msg_hash->{'source'}}[0];
965 # my $target = @{$msg_hash->{'target'}}[0];
966 # my $header= @{$msg_hash->{'header'}}[0];
967 # my $session_id = @{$msg_hash->{'session_id'}}[0];
968 # my $key = &decode_base64(@{$msg_hash->{'key'}}[0]);
969 #
970 # # build return message with twisted target and source
971 # my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
972 # &add_content2xml_hash($out_hash, "session_id", $session_id);
973 #
974 # my %data;
975 #
976 # my $keyring = $main::dak_signing_keys_directory."/keyring.gpg";
977 #
978 # my $gpg_cmd = `which gpg`; chomp $gpg_cmd;
979 # my $gpg = "$gpg_cmd --no-default-keyring --no-random-seed --keyring $keyring";
980 #
981 # # Check if the keyrings are in place and writable
982 # if(
983 # &run_as($main::dak_user, "test -w $keyring")->{'resultCode'} != 0
984 # ) {
985 # &add_content2xml_hash($out_hash, "error", "DAK Keyring is not writable");
986 # } else {
987 # my $keyfile;
988 # open($keyfile, ">/tmp/gosa_si_tmp_dak_key");
989 # print $keyfile $key;
990 # close($keyfile);
991 # my $command = "$gpg --import /tmp/gosa_si_tmp_dak_key";
992 # my $output = &run_as($main::dak_user, $command);
993 # &main::daemon_log("$session_id DEBUG: ".$output->{'command'}, 7);
994 # unlink("/tmp/gosa_si_tmp_dak_key");
995 #
996 # if($output->{'resultCode'} != 0) {
997 # &add_content2xml_hash($out_hash, "error", "Import of DAK key failed! Output was '".$output->{'output'}."'");
998 # } else {
999 # &add_content2xml_hash($out_hash, "answer", "Import of DAK key successfull! Output was '".$output->{'output'}."'");
1000 # }
1001 # }
1002 #
1003 # my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1004 # if (defined $forward_to_gosa) {
1005 # &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1006 # }
1007 # return &create_xml_string($out_hash);
1008 #}
1009 #
1010 #
1011 #sub remove_dak_key {
1012 # my ($msg, $msg_hash) = @_;
1013 # my $source = @{$msg_hash->{'source'}}[0];
1014 # my $target = @{$msg_hash->{'target'}}[0];
1015 # my $header= @{$msg_hash->{'header'}}[0];
1016 # my $session_id = @{$msg_hash->{'session_id'}}[0];
1017 # my $key = @{$msg_hash->{'keyid'}}[0];
1018 # # build return message with twisted target and source
1019 # my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
1020 # &add_content2xml_hash($out_hash, "session_id", $session_id);
1021 #
1022 # my %data;
1023 #
1024 # my $keyring = $main::dak_signing_keys_directory."/keyring.gpg";
1025 #
1026 # my $gpg_cmd = `which gpg`; chomp $gpg_cmd;
1027 # my $gpg = "$gpg_cmd --no-default-keyring --no-random-seed --homedir ".$main::dak_signing_keys_directory." --keyring $keyring";
1028 #
1029 # # Check if the keyrings are in place and writable
1030 # if(
1031 # &run_as($main::dak_user, "test -w $keyring")->{'resultCode'} != 0
1032 # ) {
1033 # &add_content2xml_hash($out_hash, "error", "DAK keyring is not writable");
1034 # } else {
1035 # # Check if the key is present in the keyring
1036 # if(&run_as($main::dak_user, "$gpg --list-keys $key")->{'resultCode'} == 0) {
1037 # my $command = "$gpg --batch --yes --delete-key $key";
1038 # my $output = &run_as($main::dak_user, $command);
1039 # &main::daemon_log("$session_id DEBUG: ".$output->{'command'}, 7);
1040 # } else {
1041 # &add_content2xml_hash($out_hash, "error", "DAK key with id '$key' was not found in keyring");
1042 # }
1043 # }
1044 #
1045 # my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1046 # if (defined $forward_to_gosa) {
1047 # &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1048 # }
1049 # return &create_xml_string($out_hash);
1050 #}
1053 #sub get_dak_queue {
1054 # my ($msg, $msg_hash, $session_id) = @_;
1055 # my %data;
1056 # my $source = @{$msg_hash->{'source'}}[0];
1057 # my $target = @{$msg_hash->{'target'}}[0];
1058 # my $header= @{$msg_hash->{'header'}}[0];
1059 #
1060 # my %data;
1061 #
1062 # foreach my $dir ("unchecked", "new", "accepted") {
1063 # foreach my $file(<"$main::dak_queue_directory/$dir/*.changes">) {
1064 # }
1065 # }
1066 #
1067 # my $out_msg = &build_msg("get_dak_queue", $target, $source, \%data);
1068 # my @out_msg_l = ($out_msg);
1069 # return @out_msg_l;
1070 #}
1073 # vim:ts=4:shiftwidth:expandtab
1074 1;