dc82ecbef8735aa547fab5266472648e633bf9b1
1 #!/usr/bin/perl
2 #===============================================================================
3 #
4 # FILE: gosa-sd
5 #
6 # USAGE: ./gosa-sd
7 #
8 # DESCRIPTION:
9 #
10 # OPTIONS: ---
11 # REQUIREMENTS: libconfig-inifiles-perl libcrypt-rijndael-perl libxml-simple-perl
12 # libdata-dumper-simple-perl libdbd-sqlite3-perl libnet-ldap-perl
13 # libpoe-perl
14 # BUGS: ---
15 # NOTES:
16 # AUTHOR: (Andreas Rettenberger), <rettenberger@gonicus.de>
17 # COMPANY:
18 # VERSION: 1.0
19 # CREATED: 12.09.2007 08:54:41 CEST
20 # REVISION: ---
21 #===============================================================================
24 use strict;
25 use warnings;
26 use Getopt::Long;
27 use Config::IniFiles;
28 use POSIX;
30 use Fcntl;
31 use IO::Socket::INET;
32 use IO::Handle;
33 use IO::Select;
34 use Symbol qw(qualify_to_ref);
35 use Crypt::Rijndael;
36 use MIME::Base64;
37 use Digest::MD5 qw(md5 md5_hex md5_base64);
38 use XML::Simple;
39 use Data::Dumper;
40 use Sys::Syslog qw( :DEFAULT setlogsock);
41 use Cwd;
42 use File::Spec;
43 use File::Basename;
44 use File::Find;
45 use File::Copy;
46 use File::Path;
47 use GOSA::DBsqlite;
48 use GOSA::GosaSupportDaemon;
49 use POE qw(Component::Server::TCP Wheel::Run Filter::Reference);
50 use Net::LDAP;
51 use Net::LDAP::Util qw(:escape);
53 my $modules_path = "/usr/lib/gosa-si/modules";
54 use lib "/usr/lib/gosa-si/modules";
55 my $server_version = '$HeadURL$:$Rev$';
56 my $server_headURL;
57 my $server_revision;
58 my $server_status;
61 # TODO es gibt eine globale funktion get_ldap_handle
62 # - ist in einer session dieses ldap handle schon vorhanden, wird es zurückgegeben
63 # - ist es nicht vorhanden, wird es erzeugt, im heap für spätere ldap anfragen gespeichert und zurückgegeben
64 # - sessions die kein ldap handle brauchen, sollen auch keins haben
65 # - wird eine session geschlossen, muss das ldap verbindung vorher beendet werden
66 our $global_kernel;
68 my (%cfg_defaults, $foreground, $verbose, $ping_timeout);
69 my ($bus_activ, $bus, $msg_to_bus, $bus_cipher);
70 my ($server);
71 my ($gosa_server, $job_queue_timeout, $job_queue_loop_delay);
72 my ($messaging_db_loop_delay);
73 my ($known_modules);
74 my ($pid_file, $procid, $pid, $log_file);
75 my ($arp_activ, $arp_fifo);
76 my ($xml);
77 my $sources_list;
78 my $max_clients;
79 my %repo_files=();
80 my $repo_path;
81 my %repo_dirs=();
82 # variables declared in config file are always set to 'our'
83 our (%cfg_defaults, $log_file, $pid_file,
84 $server_ip, $server_port, $SIPackages_key,
85 $arp_activ, $gosa_unit_tag,
86 $GosaPackages_key, $gosa_ip, $gosa_port, $gosa_timeout,
87 );
89 # additional variable which should be globaly accessable
90 our $server_address;
91 our $server_mac_address;
92 our $bus_address;
93 our $gosa_address;
94 our $no_bus;
95 our $no_arp;
96 our $verbose;
97 our $forground;
98 our $cfg_file;
99 #our ($ldap_handle, $ldap_uri, $ldap_base, $ldap_admin_dn, $ldap_admin_password, $ldap_server_dn);
100 our ($ldap_uri, $ldap_base, $ldap_admin_dn, $ldap_admin_password, $ldap_server_dn);
103 # specifies the verbosity of the daemon_log
104 $verbose = 0 ;
106 # if foreground is not null, script will be not forked to background
107 $foreground = 0 ;
109 # specifies the timeout seconds while checking the online status of a registrating client
110 $ping_timeout = 5;
112 $no_bus = 0;
113 $bus_activ = "true";
114 $no_arp = 0;
115 my $packages_list_under_construction = "/tmp/packages_list_creation_in_progress";
116 my @packages_list_statements;
117 my $watch_for_new_jobs_in_progress = 0;
119 our $prg= basename($0);
121 # holds all gosa jobs
122 our $job_db;
123 our $job_queue_tn = 'jobs';
124 my $job_queue_file_name;
125 my @job_queue_col_names = ("id INTEGER PRIMARY KEY",
126 "timestamp DEFAULT 'none'",
127 "status DEFAULT 'none'",
128 "result DEFAULT 'none'",
129 "progress DEFAULT 'none'",
130 "headertag DEFAULT 'none'",
131 "targettag DEFAULT 'none'",
132 "xmlmessage DEFAULT 'none'",
133 "macaddress DEFAULT 'none'",
134 "plainname DEFAULT 'none'",
135 );
137 # holds all other gosa-sd as well as the gosa-sd-bus
138 our $known_server_db;
139 our $known_server_tn = "known_server";
140 my $known_server_file_name;
141 my @known_server_col_names = ("hostname", "status", "hostkey", "timestamp");
143 # holds all registrated clients
144 our $known_clients_db;
145 our $known_clients_tn = "known_clients";
146 my $known_clients_file_name;
147 my @known_clients_col_names = ("hostname", "status", "hostkey", "timestamp", "macaddress", "events");
149 # holds all logged in user at each client
150 our $login_users_db;
151 our $login_users_tn = "login_users";
152 my $login_users_file_name;
153 my @login_users_col_names = ("client", "user", "timestamp");
155 # holds all fai server, the debian release and tag
156 our $fai_server_db;
157 our $fai_server_tn = "fai_server";
158 my $fai_server_file_name;
159 our @fai_server_col_names = ("timestamp", "server", "release", "sections", "tag");
161 our $fai_release_db;
162 our $fai_release_tn = "fai_release";
163 my $fai_release_file_name;
164 our @fai_release_col_names = ("timestamp", "release", "class", "type", "state");
166 # holds all packages available from different repositories
167 our $packages_list_db;
168 our $packages_list_tn = "packages_list";
169 my $packages_list_file_name;
170 our @packages_list_col_names = ("distribution", "package", "version", "section", "description", "template", "timestamp");
171 my $outdir = "/tmp/packages_list_db";
172 my $arch = "i386";
174 # holds all messages which should be delivered to a user
175 our $messaging_db;
176 our $messaging_tn = "messaging";
177 our @messaging_col_names = ("id INTEGER", "subject", "message_from", "message_to",
178 "flag", "direction", "delivery_time", "message", "timestamp" );
179 my $messaging_file_name;
181 # path to directory to store client install log files
182 our $client_fai_log_dir = "/var/log/fai";
184 # queue which stores taskes until one of the $max_children children are ready to process the task
185 my @tasks = qw();
186 my $max_children = 2;
189 %cfg_defaults = (
190 "general" => {
191 "log-file" => [\$log_file, "/var/run/".$prg.".log"],
192 "pid-file" => [\$pid_file, "/var/run/".$prg.".pid"],
193 },
194 "bus" => {
195 "activ" => [\$bus_activ, "true"],
196 },
197 "server" => {
198 "port" => [\$server_port, "20081"],
199 "known-clients" => [\$known_clients_file_name, '/var/lib/gosa-si/clients.db' ],
200 "known-servers" => [\$known_server_file_name, '/var/lib/gosa-si/servers.db'],
201 "login-users" => [\$login_users_file_name, '/var/lib/gosa-si/users.db'],
202 "fai-server" => [\$fai_server_file_name, '/var/lib/gosa-si/fai_server.db'],
203 "fai-release" => [\$fai_release_file_name, '/var/lib/gosa-si/fai_release.db'],
204 "packages-list" => [\$packages_list_file_name, '/var/lib/gosa-si/packages.db'],
205 "messaging" => [\$messaging_file_name, '/var/lib/gosa-si/messaging.db'],
206 "source-list" => [\$sources_list, '/etc/apt/sources.list'],
207 "repo-path" => [\$repo_path, '/srv/www/repository'],
208 "ldap-uri" => [\$ldap_uri, ""],
209 "ldap-base" => [\$ldap_base, ""],
210 "ldap-admin-dn" => [\$ldap_admin_dn, ""],
211 "ldap-admin-password" => [\$ldap_admin_password, ""],
212 "gosa-unit-tag" => [\$gosa_unit_tag, ""],
213 "max-clients" => [\$max_clients, 10],
214 },
215 "GOsaPackages" => {
216 "ip" => [\$gosa_ip, "0.0.0.0"],
217 "port" => [\$gosa_port, "20082"],
218 "job-queue" => [\$job_queue_file_name, '/var/lib/gosa-si/jobs.db'],
219 "job-queue-loop-delay" => [\$job_queue_loop_delay, 3],
220 "messaging-db-loop-delay" => [\$messaging_db_loop_delay, 3],
221 "key" => [\$GosaPackages_key, "none"],
222 },
223 "SIPackages" => {
224 "key" => [\$SIPackages_key, "none"],
225 },
226 );
229 #=== FUNCTION ================================================================
230 # NAME: usage
231 # PARAMETERS: nothing
232 # RETURNS: nothing
233 # DESCRIPTION: print out usage text to STDERR
234 #===============================================================================
235 sub usage {
236 print STDERR << "EOF" ;
237 usage: $prg [-hvf] [-c config]
239 -h : this (help) message
240 -c <file> : config file
241 -f : foreground, process will not be forked to background
242 -v : be verbose (multiple to increase verbosity)
243 -no-bus : starts $prg without connection to bus
244 -no-arp : starts $prg without connection to arp module
246 EOF
247 print "\n" ;
248 }
251 #=== FUNCTION ================================================================
252 # NAME: read_configfile
253 # PARAMETERS: cfg_file - string -
254 # RETURNS: nothing
255 # DESCRIPTION: read cfg_file and set variables
256 #===============================================================================
257 sub read_configfile {
258 my $cfg;
259 if( defined( $cfg_file) && ( (-s $cfg_file) > 0 )) {
260 if( -r $cfg_file ) {
261 $cfg = Config::IniFiles->new( -file => $cfg_file );
262 } else {
263 print STDERR "Couldn't read config file!\n";
264 }
265 } else {
266 $cfg = Config::IniFiles->new() ;
267 }
268 foreach my $section (keys %cfg_defaults) {
269 foreach my $param (keys %{$cfg_defaults{ $section }}) {
270 my $pinfo = $cfg_defaults{ $section }{ $param };
271 ${@$pinfo[ 0 ]} = $cfg->val( $section, $param, @$pinfo[ 1 ] );
272 }
273 }
274 }
277 #=== FUNCTION ================================================================
278 # NAME: logging
279 # PARAMETERS: level - string - default 'info'
280 # msg - string -
281 # facility - string - default 'LOG_DAEMON'
282 # RETURNS: nothing
283 # DESCRIPTION: function for logging
284 #===============================================================================
285 sub daemon_log {
286 # log into log_file
287 my( $msg, $level ) = @_;
288 if(not defined $msg) { return }
289 if(not defined $level) { $level = 1 }
290 if(defined $log_file){
291 open(LOG_HANDLE, ">>$log_file");
292 chmod 0600, $log_file;
293 if(not defined open( LOG_HANDLE, ">>$log_file" )) {
294 print STDERR "cannot open $log_file: $!";
295 return }
296 chomp($msg);
297 $msg =~s/\n//g; # no newlines are allowed in log messages, this is important for later log parsing
298 if($level <= $verbose){
299 my ($seconds, $minutes, $hours, $monthday, $month,
300 $year, $weekday, $yearday, $sommertime) = localtime(time);
301 $hours = $hours < 10 ? $hours = "0".$hours : $hours;
302 $minutes = $minutes < 10 ? $minutes = "0".$minutes : $minutes;
303 $seconds = $seconds < 10 ? $seconds = "0".$seconds : $seconds;
304 my @monthnames = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
305 $month = $monthnames[$month];
306 $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday;
307 $year+=1900;
308 my $name = $prg;
310 my $log_msg = "$month $monthday $hours:$minutes:$seconds $name $msg\n";
311 print LOG_HANDLE $log_msg;
312 if( $foreground ) {
313 print STDERR $log_msg;
314 }
315 }
316 close( LOG_HANDLE );
317 }
318 }
321 #=== FUNCTION ================================================================
322 # NAME: check_cmdline_param
323 # PARAMETERS: nothing
324 # RETURNS: nothing
325 # DESCRIPTION: validates commandline parameter
326 #===============================================================================
327 sub check_cmdline_param () {
328 my $err_config;
329 my $err_counter = 0;
330 if(not defined($cfg_file)) {
331 $cfg_file = "/etc/gosa-si/server.conf";
332 if(! -r $cfg_file) {
333 $err_config = "please specify a config file";
334 $err_counter += 1;
335 }
336 }
337 if( $err_counter > 0 ) {
338 &usage( "", 1 );
339 if( defined( $err_config)) { print STDERR "$err_config\n"}
340 print STDERR "\n";
341 exit( -1 );
342 }
343 }
346 #=== FUNCTION ================================================================
347 # NAME: check_pid
348 # PARAMETERS: nothing
349 # RETURNS: nothing
350 # DESCRIPTION: handels pid processing
351 #===============================================================================
352 sub check_pid {
353 $pid = -1;
354 # Check, if we are already running
355 if( open(LOCK_FILE, "<$pid_file") ) {
356 $pid = <LOCK_FILE>;
357 if( defined $pid ) {
358 chomp( $pid );
359 if( -f "/proc/$pid/stat" ) {
360 my($stat) = `cat /proc/$pid/stat` =~ m/$pid \((.+)\).*/;
361 if( $stat ) {
362 daemon_log("ERROR: Already running",1);
363 close( LOCK_FILE );
364 exit -1;
365 }
366 }
367 }
368 close( LOCK_FILE );
369 unlink( $pid_file );
370 }
372 # create a syslog msg if it is not to possible to open PID file
373 if (not sysopen(LOCK_FILE, $pid_file, O_WRONLY|O_CREAT|O_EXCL, 0644)) {
374 my($msg) = "Couldn't obtain lockfile '$pid_file' ";
375 if (open(LOCK_FILE, '<', $pid_file)
376 && ($pid = <LOCK_FILE>))
377 {
378 chomp($pid);
379 $msg .= "(PID $pid)\n";
380 } else {
381 $msg .= "(unable to read PID)\n";
382 }
383 if( ! ($foreground) ) {
384 openlog( $0, "cons,pid", "daemon" );
385 syslog( "warning", $msg );
386 closelog();
387 }
388 else {
389 print( STDERR " $msg " );
390 }
391 exit( -1 );
392 }
393 }
395 #=== FUNCTION ================================================================
396 # NAME: import_modules
397 # PARAMETERS: module_path - string - abs. path to the directory the modules
398 # are stored
399 # RETURNS: nothing
400 # DESCRIPTION: each file in module_path which ends with '.pm' and activation
401 # state is on is imported by "require 'file';"
402 #===============================================================================
403 sub import_modules {
404 daemon_log(" ", 1);
406 if (not -e $modules_path) {
407 daemon_log("ERROR: cannot find directory or directory is not readable: $modules_path", 1);
408 }
410 opendir (DIR, $modules_path) or die "ERROR while loading modules from directory $modules_path : $!\n";
411 while (defined (my $file = readdir (DIR))) {
412 if (not $file =~ /(\S*?).pm$/) {
413 next;
414 }
415 my $mod_name = $1;
417 if( $file =~ /ArpHandler.pm/ ) {
418 if( $no_arp > 0 ) {
419 next;
420 }
421 }
423 eval { require $file; };
424 if ($@) {
425 daemon_log("ERROR: gosa-si-server could not load module $file", 1);
426 daemon_log("$@", 5);
427 } else {
428 my $info = eval($mod_name.'::get_module_info()');
429 # Only load module if get_module_info() returns a non-null object
430 if( $info ) {
431 my ($input_address, $input_key, $input, $input_active, $input_type) = @{$info};
432 $known_modules->{$mod_name} = $info;
433 daemon_log("INFO: module $mod_name loaded", 5);
434 }
435 }
436 }
437 close (DIR);
438 }
441 #=== FUNCTION ================================================================
442 # NAME: sig_int_handler
443 # PARAMETERS: signal - string - signal arose from system
444 # RETURNS: noting
445 # DESCRIPTION: handels tasks to be done befor signal becomes active
446 #===============================================================================
447 sub sig_int_handler {
448 my ($signal) = @_;
450 # if (defined($ldap_handle)) {
451 # $ldap_handle->disconnect;
452 # }
453 # TODO alle verbliebenden ldap verbindungen aus allen heaps beenden
456 daemon_log("shutting down gosa-si-server", 1);
457 system("kill `ps -C gosa-si-server -o pid=`");
458 }
459 $SIG{INT} = \&sig_int_handler;
462 sub check_key_and_xml_validity {
463 my ($crypted_msg, $module_key, $session_id) = @_;
464 my $msg;
465 my $msg_hash;
466 my $error_string;
467 eval{
468 $msg = &decrypt_msg($crypted_msg, $module_key);
470 if ($msg =~ /<xml>/i){
471 $msg =~ s/\s+/ /g; # just for better daemon_log
472 daemon_log("$session_id DEBUG: decrypted_msg: \n$msg", 8);
473 $msg_hash = $xml->XMLin($msg, ForceArray=>1);
475 ##############
476 # check header
477 if( not exists $msg_hash->{'header'} ) { die "no header specified"; }
478 my $header_l = $msg_hash->{'header'};
479 if( 1 > @{$header_l} ) { die 'empty header tag'; }
480 if( 1 < @{$header_l} ) { die 'more than one header specified'; }
481 my $header = @{$header_l}[0];
482 if( 0 == length $header) { die 'empty string in header tag'; }
484 ##############
485 # check source
486 if( not exists $msg_hash->{'source'} ) { die "no source specified"; }
487 my $source_l = $msg_hash->{'source'};
488 if( 1 > @{$source_l} ) { die 'empty source tag'; }
489 if( 1 < @{$source_l} ) { die 'more than one source specified'; }
490 my $source = @{$source_l}[0];
491 if( 0 == length $source) { die 'source error'; }
493 ##############
494 # check target
495 if( not exists $msg_hash->{'target'} ) { die "no target specified"; }
496 my $target_l = $msg_hash->{'target'};
497 if( 1 > @{$target_l} ) { die 'empty target tag'; }
498 }
499 };
500 if($@) {
501 daemon_log("$session_id DEBUG: do not understand the message: $@", 7);
502 $msg = undef;
503 $msg_hash = undef;
504 }
506 return ($msg, $msg_hash);
507 }
510 sub check_outgoing_xml_validity {
511 my ($msg) = @_;
513 my $msg_hash;
514 eval{
515 $msg_hash = $xml->XMLin($msg, ForceArray=>1);
517 ##############
518 # check header
519 my $header_l = $msg_hash->{'header'};
520 if( 1 != @{$header_l} ) {
521 die 'no or more than one headers specified';
522 }
523 my $header = @{$header_l}[0];
524 if( 0 == length $header) {
525 die 'header has length 0';
526 }
528 ##############
529 # check source
530 my $source_l = $msg_hash->{'source'};
531 if( 1 != @{$source_l} ) {
532 die 'no or more than 1 sources specified';
533 }
534 my $source = @{$source_l}[0];
535 if( 0 == length $source) {
536 die 'source has length 0';
537 }
538 unless( $source =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$/ ||
539 $source =~ /^GOSA$/i ) {
540 die "source '$source' is neither a complete ip-address with port nor 'GOSA'";
541 }
543 ##############
544 # check target
545 my $target_l = $msg_hash->{'target'};
546 if( 0 == @{$target_l} ) {
547 die "no targets specified";
548 }
549 foreach my $target (@$target_l) {
550 if( 0 == length $target) {
551 die "target has length 0";
552 }
553 unless( $target =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$/ ||
554 $target =~ /^GOSA$/i ||
555 $target =~ /^\*$/ ||
556 $target =~ /KNOWN_SERVER/i ||
557 $target =~ /JOBDB/i ||
558 $target =~ /^([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})$/i ){
559 die "target '$target' is not a complete ip-address with port or a valid target name or a mac-address";
560 }
561 }
562 };
563 if($@) {
564 daemon_log("WARNING: outgoing msg is not gosa-si envelope conform", 5);
565 daemon_log("$@ ".(defined($msg) && length($msg)>0)?$msg:"Empty Message", 8);
566 $msg_hash = undef;
567 }
569 return ($msg_hash);
570 }
573 sub input_from_known_server {
574 my ($input, $remote_ip, $session_id) = @_ ;
575 my ($msg, $msg_hash, $module);
577 my $sql_statement= "SELECT * FROM known_server";
578 my $query_res = $known_server_db->select_dbentry( $sql_statement );
580 while( my ($hit_num, $hit) = each %{ $query_res } ) {
581 my $host_name = $hit->{hostname};
582 if( not $host_name =~ "^$remote_ip") {
583 next;
584 }
585 my $host_key = $hit->{hostkey};
586 daemon_log("$session_id DEBUG: input_from_known_server: host_name: $host_name", 7);
587 daemon_log("DEBUG: input_from_known_server: host_key: $host_key", 7);
589 # check if module can open msg envelope with module key
590 my ($tmp_msg, $tmp_msg_hash) = &check_key_and_xml_validity($input, $host_key, $session_id);
591 if( (!$tmp_msg) || (!$tmp_msg_hash) ) {
592 daemon_log("$session_id DEBUG: input_from_known_server: deciphering raise error", 7);
593 daemon_log("$@", 8);
594 next;
595 }
596 else {
597 $msg = $tmp_msg;
598 $msg_hash = $tmp_msg_hash;
599 $module = "SIPackages";
600 last;
601 }
602 }
604 if( (!$msg) || (!$msg_hash) || (!$module) ) {
605 daemon_log("$session_id DEBUG: Incoming message is not from a known server", 7);
606 }
608 return ($msg, $msg_hash, $module);
609 }
612 sub input_from_known_client {
613 my ($input, $remote_ip, $session_id) = @_ ;
614 my ($msg, $msg_hash, $module);
616 my $sql_statement= "SELECT * FROM known_clients";
617 my $query_res = $known_clients_db->select_dbentry( $sql_statement );
618 while( my ($hit_num, $hit) = each %{ $query_res } ) {
619 my $host_name = $hit->{hostname};
620 if( not $host_name =~ /^$remote_ip:\d*$/) {
621 next;
622 }
623 my $host_key = $hit->{hostkey};
624 &daemon_log("$session_id DEBUG: input_from_known_client: host_name: $host_name", 7);
625 &daemon_log("$session_id DEBUG: input_from_known_client: host_key: $host_key", 7);
627 # check if module can open msg envelope with module key
628 ($msg, $msg_hash) = &check_key_and_xml_validity($input, $host_key, $session_id);
630 if( (!$msg) || (!$msg_hash) ) {
631 &daemon_log("$session_id DEGUG: input_from_known_client: deciphering raise error", 7);
632 &daemon_log("$@", 8);
633 next;
634 }
635 else {
636 $module = "SIPackages";
637 last;
638 }
639 }
641 if( (!$msg) || (!$msg_hash) || (!$module) ) {
642 &daemon_log("$session_id DEBUG: Incoming message is not from a known client", 7);
643 }
645 return ($msg, $msg_hash, $module);
646 }
649 sub input_from_unknown_host {
650 no strict "refs";
651 my ($input, $session_id) = @_ ;
652 my ($msg, $msg_hash, $module);
653 my $error_string;
655 my %act_modules = %$known_modules;
657 while( my ($mod, $info) = each(%act_modules)) {
659 # check a key exists for this module
660 my $module_key = ${$mod."_key"};
661 if( not defined $module_key ) {
662 if( $mod eq 'ArpHandler' ) {
663 next;
664 }
665 daemon_log("$session_id ERROR: no key specified in config file for $mod", 1);
666 next;
667 }
668 daemon_log("$session_id DEBUG: $mod: $module_key", 7);
670 # check if module can open msg envelope with module key
671 ($msg, $msg_hash) = &check_key_and_xml_validity($input, $module_key, $session_id);
672 if( (not defined $msg) || (not defined $msg_hash) ) {
673 next;
674 }
675 else {
676 $module = $mod;
677 last;
678 }
679 }
681 if( (!$msg) || (!$msg_hash) || (!$module)) {
682 daemon_log("$session_id DEBUG: Incoming message is not from an unknown host", 7);
683 }
685 return ($msg, $msg_hash, $module);
686 }
689 sub create_ciphering {
690 my ($passwd) = @_;
691 if((!defined($passwd)) || length($passwd)==0) {
692 $passwd = "";
693 }
694 $passwd = substr(md5_hex("$passwd") x 32, 0, 32);
695 my $iv = substr(md5_hex('GONICUS GmbH'),0, 16);
696 my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC());
697 $my_cipher->set_iv($iv);
698 return $my_cipher;
699 }
702 sub encrypt_msg {
703 my ($msg, $key) = @_;
704 my $my_cipher = &create_ciphering($key);
705 my $len;
706 {
707 use bytes;
708 $len= 16-length($msg)%16;
709 }
710 $msg = "\0"x($len).$msg;
711 $msg = $my_cipher->encrypt($msg);
712 chomp($msg = &encode_base64($msg));
713 # there are no newlines allowed inside msg
714 $msg=~ s/\n//g;
715 return $msg;
716 }
719 sub decrypt_msg {
721 my ($msg, $key) = @_ ;
722 $msg = &decode_base64($msg);
723 my $my_cipher = &create_ciphering($key);
724 $msg = $my_cipher->decrypt($msg);
725 $msg =~ s/\0*//g;
726 return $msg;
727 }
730 sub get_encrypt_key {
731 my ($target) = @_ ;
732 my $encrypt_key;
733 my $error = 0;
735 # target can be in known_server
736 if( not defined $encrypt_key ) {
737 my $sql_statement= "SELECT * FROM known_server WHERE hostname='$target'";
738 my $query_res = $known_server_db->select_dbentry( $sql_statement );
739 while( my ($hit_num, $hit) = each %{ $query_res } ) {
740 my $host_name = $hit->{hostname};
741 if( $host_name ne $target ) {
742 next;
743 }
744 $encrypt_key = $hit->{hostkey};
745 last;
746 }
747 }
749 # target can be in known_client
750 if( not defined $encrypt_key ) {
751 my $sql_statement= "SELECT * FROM known_clients WHERE hostname='$target'";
752 my $query_res = $known_clients_db->select_dbentry( $sql_statement );
753 while( my ($hit_num, $hit) = each %{ $query_res } ) {
754 my $host_name = $hit->{hostname};
755 if( $host_name ne $target ) {
756 next;
757 }
758 $encrypt_key = $hit->{hostkey};
759 last;
760 }
761 }
763 return $encrypt_key;
764 }
767 #=== FUNCTION ================================================================
768 # NAME: open_socket
769 # PARAMETERS: PeerAddr string something like 192.168.1.1 or 192.168.1.1:10000
770 # [PeerPort] string necessary if port not appended by PeerAddr
771 # RETURNS: socket IO::Socket::INET
772 # DESCRIPTION: open a socket to PeerAddr
773 #===============================================================================
774 sub open_socket {
775 my ($PeerAddr, $PeerPort) = @_ ;
776 if(defined($PeerPort)){
777 $PeerAddr = $PeerAddr.":".$PeerPort;
778 }
779 my $socket;
780 $socket = new IO::Socket::INET(PeerAddr => $PeerAddr,
781 Porto => "tcp",
782 Type => SOCK_STREAM,
783 Timeout => 5,
784 );
785 if(not defined $socket) {
786 return;
787 }
788 # &daemon_log("DEBUG: open_socket: $PeerAddr", 7);
789 return $socket;
790 }
793 #=== FUNCTION ================================================================
794 # NAME: get_ip
795 # PARAMETERS: interface name (i.e. eth0)
796 # RETURNS: (ip address)
797 # DESCRIPTION: Uses ioctl to get ip address directly from system.
798 #===============================================================================
799 sub get_ip {
800 my $ifreq= shift;
801 my $result= "";
802 my $SIOCGIFADDR= 0x8915; # man 2 ioctl_list
803 my $proto= getprotobyname('ip');
805 socket SOCKET, PF_INET, SOCK_DGRAM, $proto
806 or die "socket: $!";
808 if(ioctl SOCKET, $SIOCGIFADDR, $ifreq) {
809 my ($if, $sin) = unpack 'a16 a16', $ifreq;
810 my ($port, $addr) = sockaddr_in $sin;
811 my $ip = inet_ntoa $addr;
813 if ($ip && length($ip) > 0) {
814 $result = $ip;
815 }
816 }
818 return $result;
819 }
822 sub get_local_ip_for_remote_ip {
823 my $remote_ip= shift;
824 my $result="0.0.0.0";
826 if($remote_ip =~ /^(\d\d?\d?\.){3}\d\d?\d?$/) {
827 if($remote_ip eq "127.0.0.1") {
828 $result = "127.0.0.1";
829 } else {
830 my $PROC_NET_ROUTE= ('/proc/net/route');
832 open(PROC_NET_ROUTE, "<$PROC_NET_ROUTE")
833 or die "Could not open $PROC_NET_ROUTE";
835 my @ifs = <PROC_NET_ROUTE>;
837 close(PROC_NET_ROUTE);
839 # Eat header line
840 shift @ifs;
841 chomp @ifs;
842 foreach my $line(@ifs) {
843 my ($Iface,$Destination,$Gateway,$Flags,$RefCnt,$Use,$Metric,$Mask,$MTU,$Window,$IRTT)=split(/\s/, $line);
844 my $destination;
845 my $mask;
846 my ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Destination);
847 $destination= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d));
848 ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Mask);
849 $mask= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d));
850 if(new NetAddr::IP($remote_ip)->within(new NetAddr::IP($destination, $mask))) {
851 # destination matches route, save mac and exit
852 $result= &get_ip($Iface);
853 last;
854 }
855 }
856 }
857 } else {
858 daemon_log("get_local_ip_for_remote_ip was called with a non-ip parameter: $remote_ip", 1);
859 }
860 return $result;
861 }
864 sub send_msg_to_target {
865 my ($msg, $address, $encrypt_key, $msg_header, $session_id) = @_ ;
866 my $error = 0;
867 my $header;
868 my $new_status;
869 my $act_status;
870 my ($sql_statement, $res);
872 if( $msg_header ) {
873 $header = "'$msg_header'-";
874 } else {
875 $header = "";
876 }
878 # Patch the source ip
879 if($msg =~ /<source>0\.0\.0\.0:\d*?<\/source>/) {
880 my $remote_ip = &get_local_ip_for_remote_ip(sprintf("%s", $address =~ /^([0-9\.]*?):.*$/));
881 $msg =~ s/<source>(0\.0\.0\.0):(\d*?)<\/source>/<source>$remote_ip:$2<\/source>/s;
882 }
884 # encrypt xml msg
885 my $crypted_msg = &encrypt_msg($msg, $encrypt_key);
887 # opensocket
888 my $socket = &open_socket($address);
889 if( !$socket ) {
890 daemon_log("$session_id ERROR: cannot send ".$header."msg to $address , host not reachable", 1);
891 $error++;
892 }
894 if( $error == 0 ) {
895 # send xml msg
896 print $socket $crypted_msg."\n";
898 daemon_log("$session_id INFO: send ".$header."msg to $address", 5);
899 #daemon_log("DEBUG: message:\n$msg", 9);
901 }
903 # close socket in any case
904 if( $socket ) {
905 close $socket;
906 }
908 if( $error > 0 ) { $new_status = "down"; }
909 else { $new_status = $msg_header; }
912 # known_clients
913 $sql_statement = "SELECT * FROM known_clients WHERE hostname='$address'";
914 $res = $known_clients_db->select_dbentry($sql_statement);
915 if( keys(%$res) > 0) {
916 $act_status = $res->{1}->{'status'};
917 if( $act_status eq "down" ) {
918 $sql_statement = "DELETE FROM known_clients WHERE hostname='$address'";
919 $res = $known_clients_db->del_dbentry($sql_statement);
920 daemon_log("$session_id WARNING: failed 2x to send msg to host '$address', delete host from known_clients", 3);
921 } else {
922 $sql_statement = "UPDATE known_clients SET status='$new_status' WHERE hostname='$address'";
923 $res = $known_clients_db->update_dbentry($sql_statement);
924 if($new_status eq "down"){
925 daemon_log("$session_id WARNING: set '$address' from status '$act_status' to '$new_status'", 3);
926 } else {
927 daemon_log("$session_id INFO: set '$address' from status '$act_status' to '$new_status'", 5);
928 }
929 }
930 }
932 # known_server
933 $sql_statement = "SELECT * FROM known_server WHERE hostname='$address'";
934 $res = $known_server_db->select_dbentry($sql_statement);
935 if( keys(%$res) > 0 ) {
936 $act_status = $res->{1}->{'status'};
937 if( $act_status eq "down" ) {
938 $sql_statement = "DELETE FROM known_server WHERE hostname='$address'";
939 $res = $known_server_db->del_dbentry($sql_statement);
940 daemon_log("$session_id WARNING: failed 2x to a send msg to host '$address', delete host from known_server", 3);
941 }
942 else {
943 $sql_statement = "UPDATE known_server SET status='$new_status' WHERE hostname='$address'";
944 $res = $known_server_db->update_dbentry($sql_statement);
945 if($new_status eq "down"){
946 daemon_log("$session_id WARNING: set '$address' from status '$act_status' to '$new_status'", 3);
947 }
948 else {
949 daemon_log("$session_id INFO: set '$address' from status '$act_status' to '$new_status'", 5);
950 }
951 }
952 }
953 return $error;
954 }
957 sub update_jobdb_status_for_send_msgs {
958 my ($answer, $error) = @_;
959 if( $answer =~ /<jobdb_id>(\d+)<\/jobdb_id>/ ) {
960 my $jobdb_id = $1;
962 # sending msg faild
963 if( $error ) {
964 if (not $answer =~ /<header>trigger_action_reinstall<\/header>/) {
965 my $sql_statement = "UPDATE $job_queue_tn ".
966 "SET status='error', result='can not deliver msg, please consult log file' ".
967 "WHERE id=$jobdb_id";
968 my $res = $job_db->update_dbentry($sql_statement);
969 }
971 # sending msg was successful
972 } else {
973 my $sql_statement = "UPDATE $job_queue_tn ".
974 "SET status='done' ".
975 "WHERE id=$jobdb_id AND status='processed'";
976 my $res = $job_db->update_dbentry($sql_statement);
977 }
978 }
979 }
981 sub _start {
982 my ($kernel) = $_[KERNEL];
983 &trigger_db_loop($kernel);
984 $global_kernel = $kernel;
985 $kernel->yield('create_fai_server_db', $fai_server_tn );
986 $kernel->yield('create_fai_release_db', $fai_release_tn );
987 $kernel->sig(USR1 => "sig_handler");
988 $kernel->sig(USR2 => "create_packages_list_db");
989 }
991 sub sig_handler {
992 my ($kernel, $signal) = @_[KERNEL, ARG0] ;
993 daemon_log("0 INFO got signal '$signal'", 1);
994 $kernel->sig_handled();
995 return;
996 }
998 sub next_task {
999 my ($session, $heap) = @_[SESSION, HEAP];
1001 while ( keys( %{ $heap->{task} } ) < $max_children ) {
1002 my $next_task = shift @tasks;
1003 last unless defined $next_task;
1005 my $task = POE::Wheel::Run->new(
1006 Program => sub { process_task($session, $heap, $next_task) },
1007 StdioFilter => POE::Filter::Reference->new(),
1008 StdoutEvent => "task_result",
1009 StderrEvent => "task_debug",
1010 CloseEvent => "task_done",
1011 );
1013 $heap->{task}->{ $task->ID } = $task;
1014 }
1015 }
1017 sub handle_task_result {
1018 my ($kernel, $heap, $result) = @_[KERNEL, HEAP, ARG0];
1019 my $client_answer = $result->{'answer'};
1020 if( $client_answer =~ s/session_id=(\d+)$// ) {
1021 my $session_id = $1;
1022 if( defined $session_id ) {
1023 my $session_reference = $kernel->ID_id_to_session($session_id);
1024 if( defined $session_reference ) {
1025 $heap = $session_reference->get_heap();
1026 }
1027 }
1029 if(exists $heap->{'client'}) {
1030 $heap->{'client'}->put($client_answer);
1031 }
1032 }
1033 $kernel->sig(CHLD => "child_reap");
1034 }
1036 sub handle_task_debug {
1037 my $result = $_[ARG0];
1038 print STDERR "$result\n";
1039 }
1041 sub handle_task_done {
1042 my ( $kernel, $heap, $task_id ) = @_[ KERNEL, HEAP, ARG0 ];
1043 delete $heap->{task}->{$task_id};
1044 $kernel->yield("next_task");
1045 }
1047 sub process_task {
1048 no strict "refs";
1049 my ($session, $heap, $input) = @_;
1050 my $session_id = $session->ID;
1051 my ($msg, $msg_hash, $module);
1052 my $error = 0;
1053 my $answer_l;
1054 my ($answer_header, @answer_target_l, $answer_source);
1055 my $client_answer = "";
1057 daemon_log("", 5);
1058 daemon_log("$session_id INFO: Incoming msg with session ID $session_id from '".$heap->{'remote_ip'}."'", 5);
1059 #daemon_log("$session_id DEBUG: Incoming msg:\n$input", 9);
1061 ####################
1062 # check incoming msg
1063 # msg is from a new client or gosa
1064 ($msg, $msg_hash, $module) = &input_from_unknown_host($input, $session_id);
1065 # msg is from a gosa-si-server or gosa-si-bus
1066 if(( !$msg ) || ( !$msg_hash ) || ( !$module )){
1067 ($msg, $msg_hash, $module) = &input_from_known_server($input, $heap->{'remote_ip'}, $session_id);
1068 }
1069 # msg is from a gosa-si-client
1070 if(( !$msg ) || ( !$msg_hash ) || ( !$module )){
1071 ($msg, $msg_hash, $module) = &input_from_known_client($input, $heap->{'remote_ip'}, $session_id);
1072 }
1073 # an error occurred
1074 if(( !$msg ) || ( !$msg_hash ) || ( !$module )){
1075 # if an incoming msg could not be decrypted (maybe a wrong key), send client a ping. If the client
1076 # could not understand a msg from its server the client cause a re-registering process
1077 daemon_log("$session_id INFO cannot understand incoming msg, send 'ping'-msg to all host with ip '".$heap->{remote_ip}."' to cause a re-registering of the client if necessary", 5);
1078 my $sql_statement = "SELECT * FROM $main::known_clients_tn WHERE (hostname LIKE '".$heap->{'remote_ip'}."%')";
1079 my $query_res = $known_clients_db->select_dbentry( $sql_statement );
1080 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1081 my $host_name = $hit->{'hostname'};
1082 my $host_key = $hit->{'hostkey'};
1083 my $ping_msg = "<xml> <header>gosa_ping</header> <source>$server_address</source> <target>$host_name</target></xml>";
1084 my $error = &send_msg_to_target($ping_msg, $host_name, $host_key, "gosa_ping", $session_id);
1085 &update_jobdb_status_for_send_msgs($ping_msg, $error);
1086 }
1087 $error++;
1088 }
1090 ######################
1091 # process incoming msg
1092 if( $error == 0) {
1093 daemon_log("$session_id INFO: Incoming msg with header '".@{$msg_hash->{'header'}}[0].
1094 "' from '".$heap->{'remote_ip'}."'", 5);
1095 daemon_log("$session_id DEBUG: Processing module ".$module, 7);
1096 $answer_l = &{ $module."::process_incoming_msg" }($msg, $msg_hash, $session_id);
1098 if ( 0 < @{$answer_l} ) {
1099 my $answer_str = join("\n", @{$answer_l});
1100 daemon_log("$session_id DEBUG: $module: Got answer from module: \n".$answer_str,8);
1101 } else {
1102 daemon_log("$session_id DEBUG: $module: Got no answer from module!" ,8);
1103 }
1105 }
1106 if( !$answer_l ) { $error++ };
1108 ########
1109 # answer
1110 if( $error == 0 ) {
1112 foreach my $answer ( @{$answer_l} ) {
1113 # for each answer in answer list
1115 # check outgoing msg to xml validity
1116 my $answer_hash = &check_outgoing_xml_validity($answer);
1117 if( not defined $answer_hash ) {
1118 next;
1119 }
1121 $answer_header = @{$answer_hash->{'header'}}[0];
1122 @answer_target_l = @{$answer_hash->{'target'}};
1123 $answer_source = @{$answer_hash->{'source'}}[0];
1125 # deliver msg to all targets
1126 foreach my $answer_target ( @answer_target_l ) {
1128 # targets of msg are all gosa-si-clients in known_clients_db
1129 if( $answer_target eq "*" ) {
1130 # answer is for all clients
1131 my $sql_statement= "SELECT * FROM known_clients";
1132 my $query_res = $known_clients_db->select_dbentry( $sql_statement );
1133 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1134 my $host_name = $hit->{hostname};
1135 my $host_key = $hit->{hostkey};
1136 my $error = &send_msg_to_target($answer, $host_name, $host_key, $answer_header, $session_id);
1137 &update_jobdb_status_for_send_msgs($answer, $error);
1138 }
1139 }
1141 # targets of msg are all gosa-si-server in known_server_db
1142 elsif( $answer_target eq "KNOWN_SERVER" ) {
1143 # answer is for all server in known_server
1144 my $sql_statement= "SELECT * FROM known_server";
1145 my $query_res = $known_server_db->select_dbentry( $sql_statement );
1146 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1147 my $host_name = $hit->{hostname};
1148 my $host_key = $hit->{hostkey};
1149 $answer =~ s/KNOWN_SERVER/$host_name/g;
1150 my $error = &send_msg_to_target($answer, $host_name, $host_key, $answer_header, $session_id);
1151 &update_jobdb_status_for_send_msgs($answer, $error);
1152 }
1153 }
1155 # target of msg is GOsa
1156 elsif( $answer_target eq "GOSA" ) {
1157 my $session_id = ($1) if $answer =~ /<session_id>(\d+?)<\/session_id>/;
1158 my $add_on = "";
1159 if( defined $session_id ) {
1160 $add_on = ".session_id=$session_id";
1161 }
1162 # answer is for GOSA and has to returned to connected client
1163 my $gosa_answer = &encrypt_msg($answer, $GosaPackages_key);
1164 $client_answer = $gosa_answer.$add_on;
1165 }
1167 # target of msg is job queue at this host
1168 elsif( $answer_target eq "JOBDB") {
1169 $answer =~ /<header>(\S+)<\/header>/;
1170 my $header;
1171 if( defined $1 ) { $header = $1; }
1172 my $error = &send_msg_to_target($answer, $server_address, $GosaPackages_key, $header, $session_id);
1173 &update_jobdb_status_for_send_msgs($answer, $error);
1174 }
1176 # target of msg is a mac address
1177 elsif( $answer_target =~ /^([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})$/i ) {
1178 daemon_log("$session_id INFO: target is mac address '$answer_target', looking for host in known_clients", 5);
1179 my $sql_statement = "SELECT * FROM known_clients WHERE macaddress LIKE '$answer_target'";
1180 my $query_res = $known_clients_db->select_dbentry( $sql_statement );
1181 my $found_ip_flag = 0;
1182 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1183 my $host_name = $hit->{hostname};
1184 my $host_key = $hit->{hostkey};
1185 $answer =~ s/$answer_target/$host_name/g;
1186 daemon_log("$session_id INFO: found host '$host_name', associated to '$answer_target'", 5);
1187 my $error = &send_msg_to_target($answer, $host_name, $host_key, $answer_header, $session_id);
1188 &update_jobdb_status_for_send_msgs($answer, $error);
1189 $found_ip_flag++ ;
1190 }
1191 if( $found_ip_flag == 0) {
1192 daemon_log("$session_id WARNING: no host found in known_clients with mac address '$answer_target'", 3);
1193 if( $bus_activ eq "true" ) {
1194 daemon_log("$session_id INFO: try to forward msg '$answer_header' to bus '$bus_address'", 5);
1195 my $sql_statement = "SELECT * FROM known_server WHERE hostname='$bus_address'";
1196 my $query_res = $known_server_db->select_dbentry( $sql_statement );
1197 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1198 my $bus_address = $hit->{hostname};
1199 my $bus_key = $hit->{hostkey};
1200 my $error = &send_msg_to_target($answer, $bus_address, $bus_key, $answer_header, $session_id);
1201 &update_jobdb_status_for_send_msgs($answer, $error);
1202 last;
1203 }
1204 }
1206 }
1208 # answer is for one specific host
1209 } else {
1210 # get encrypt_key
1211 my $encrypt_key = &get_encrypt_key($answer_target);
1212 if( not defined $encrypt_key ) {
1213 # unknown target, forward msg to bus
1214 daemon_log("$session_id WARNING: unknown target '$answer_target'", 3);
1215 if( $bus_activ eq "true" ) {
1216 daemon_log("$session_id INFO: try to forward msg '$answer_header' to bus '$bus_address'", 5);
1217 my $sql_statement = "SELECT * FROM known_server WHERE hostname='$bus_address'";
1218 my $query_res = $known_server_db->select_dbentry( $sql_statement );
1219 my $res_length = keys( %{$query_res} );
1220 if( $res_length == 0 ){
1221 daemon_log("$session_id WARNING: send '$answer_header' to '$bus_address' failed, ".
1222 "no bus found in known_server", 3);
1223 }
1224 else {
1225 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1226 my $bus_key = $hit->{hostkey};
1227 my $error = &send_msg_to_target($answer, $bus_address, $bus_key, $answer_header,$session_id );
1228 &update_jobdb_status_for_send_msgs($answer, $error);
1229 }
1230 }
1231 }
1232 next;
1233 }
1234 my $error = &send_msg_to_target($answer, $answer_target, $encrypt_key, $answer_header,$session_id);
1235 &update_jobdb_status_for_send_msgs($answer, $error);
1236 }
1237 }
1238 }
1239 }
1241 my $filter = POE::Filter::Reference->new();
1242 my %result = (
1243 status => "seems ok to me",
1244 answer => $client_answer,
1245 );
1247 my $output = $filter->put( [ \%result ] );
1248 print @$output;
1251 }
1254 sub trigger_db_loop {
1255 my ($kernel) = @_ ;
1256 $kernel->delay_set('watch_for_new_jobs', $job_queue_loop_delay);
1257 $kernel->delay_set('watch_for_done_jobs', $job_queue_loop_delay);
1258 $kernel->delay_set('watch_for_new_messages', $messaging_db_loop_delay);
1259 $kernel->delay_set('watch_for_delivery_messages', $messaging_db_loop_delay);
1260 $kernel->delay_set('watch_for_done_messages', $messaging_db_loop_delay);
1261 }
1264 sub watch_for_done_jobs {
1265 my ($kernel,$heap) = @_[KERNEL, HEAP];
1267 my $sql_statement = "SELECT * FROM ".$job_queue_tn.
1268 " WHERE status='done'";
1269 my $res = $job_db->select_dbentry( $sql_statement );
1271 while( my ($id, $hit) = each %{$res} ) {
1272 my $jobdb_id = $hit->{id};
1273 my $sql_statement = "DELETE FROM $job_queue_tn WHERE id=$jobdb_id";
1274 my $res = $job_db->del_dbentry($sql_statement);
1275 }
1277 $kernel->delay_set('watch_for_done_jobs',$job_queue_loop_delay);
1278 }
1281 sub watch_for_new_jobs {
1282 if($watch_for_new_jobs_in_progress == 0) {
1283 $watch_for_new_jobs_in_progress = 1;
1284 my ($kernel,$heap) = @_[KERNEL, HEAP];
1286 # check gosa job queue for jobs with executable timestamp
1287 my $timestamp = &get_time();
1288 my $sql_statement = "SELECT * FROM $job_queue_tn WHERE status='waiting' AND (CAST (timestamp AS INTEGER)) < $timestamp ORDER BY timestamp";
1289 my $res = $job_db->exec_statement( $sql_statement );
1291 # Merge all new jobs that would do the same actions
1292 my @drops;
1293 my $hits;
1294 foreach my $hit (reverse @{$res} ) {
1295 my $macaddress= lc @{$hit}[8];
1296 my $headertag= @{$hit}[5];
1297 if(
1298 defined($hits->{$macaddress}) &&
1299 defined($hits->{$macaddress}->{$headertag}) &&
1300 defined($hits->{$macaddress}->{$headertag}[0])
1301 ) {
1302 push @drops, "DELETE FROM $job_queue_tn WHERE id = $hits->{$macaddress}->{$headertag}[0]";
1303 }
1304 $hits->{$macaddress}->{$headertag}= $hit;
1305 }
1307 # Delete new jobs with a matching job in state 'processing'
1308 foreach my $macaddress (keys %{$hits}) {
1309 foreach my $jobdb_headertag (keys %{$hits->{$macaddress}}) {
1310 my $jobdb_id = @{$hits->{$macaddress}->{$jobdb_headertag}}[0];
1311 if(defined($jobdb_id)) {
1312 my $sql_statement = "SELECT * FROM $job_queue_tn WHERE macaddress LIKE '$macaddress' AND headertag='$jobdb_headertag' AND status='processing'";
1313 my $res = $job_db->exec_statement( $sql_statement );
1314 foreach my $hit (@{$res}) {
1315 push @drops, "DELETE FROM $job_queue_tn WHERE id=$jobdb_id";
1316 }
1317 } else {
1318 daemon_log("J ERROR: Job without id exists for macaddress $macaddress!", 1);
1319 }
1320 }
1321 }
1323 # Commit deletion
1324 $job_db->exec_statementlist(\@drops);
1326 # Look for new jobs that could be executed
1327 foreach my $macaddress (keys %{$hits}) {
1329 # Look if there is an executing job
1330 my $sql_statement = "SELECT * FROM $job_queue_tn WHERE macaddress LIKE '$macaddress' AND status='processing'";
1331 my $res = $job_db->exec_statement( $sql_statement );
1333 # Skip new jobs for host if there is a processing job
1334 if(defined($res) and defined @{$res}[0]) {
1335 next;
1336 }
1338 foreach my $jobdb_headertag (keys %{$hits->{$macaddress}}) {
1339 my $jobdb_id = @{$hits->{$macaddress}->{$jobdb_headertag}}[0];
1340 if(defined($jobdb_id)) {
1341 my $job_msg = @{$hits->{$macaddress}->{$jobdb_headertag}}[7];
1343 daemon_log("J DEBUG: its time to execute $job_msg", 7);
1344 my $sql_statement = "SELECT * FROM known_clients WHERE macaddress LIKE '$macaddress'";
1345 my $res_hash = $known_clients_db->select_dbentry( $sql_statement );
1347 # expect macaddress is unique!!!!!!
1348 my $target = $res_hash->{1}->{hostname};
1350 # change header
1351 $job_msg =~ s/<header>job_/<header>gosa_/;
1353 # add sqlite_id
1354 $job_msg =~ s/<\/xml>$/<jobdb_id>$jobdb_id<\/jobdb_id><\/xml>/;
1356 $job_msg =~ /<header>(\S+)<\/header>/;
1357 my $header = $1 ;
1358 my $func_error = &send_msg_to_target($job_msg, $server_address, $GosaPackages_key, $header, "J");
1360 # update status in job queue to 'processing'
1361 $sql_statement = "UPDATE $job_queue_tn SET status='processing' WHERE id=$jobdb_id";
1362 my $res = $job_db->update_dbentry($sql_statement);
1363 # TODO: abfangen ob alles in ordnung ist oder nicht, wenn nicht error schmeißen
1365 # We don't want parallel processing
1366 last;
1367 }
1368 }
1369 }
1371 $watch_for_new_jobs_in_progress = 0;
1372 $kernel->delay_set('watch_for_new_jobs', $job_queue_loop_delay);
1373 }
1374 }
1377 sub watch_for_new_messages {
1378 my ($kernel,$heap) = @_[KERNEL, HEAP];
1379 my @coll_user_msg; # collection list of outgoing messages
1381 # check messaging_db for new incoming messages with executable timestamp
1382 my $timestamp = &get_time();
1383 my $sql_statement = "SELECT * FROM $messaging_tn WHERE ( (CAST(timestamp AS INTEGER))<$timestamp AND flag='n' AND direction='in' )";
1384 my $res = $messaging_db->exec_statement( $sql_statement );
1385 foreach my $hit (@{$res}) {
1387 # create outgoing messages
1388 my $message_to = @{$hit}[3];
1389 # translate message_to to plain login name
1390 my @message_to_l = split(/,/, $message_to);
1391 my %receiver_h;
1392 foreach my $receiver (@message_to_l) {
1393 if ($receiver =~ /^u_([\s\S]*)$/) {
1394 $receiver_h{$1} = 0;
1395 } elsif ($receiver =~ /^g_([\s\S]*)$/) {
1396 # TODO implement receiver translation
1397 } else {
1398 my $sbjct = &encode_base64(@{$hit}[1]);
1399 my $msg = &encode_base64(@{$hit}[7]);
1400 &daemon_log("M WARNING: unknown receiver '$receiver' for a user-message 'sbjct - msg'", 3);
1401 }
1402 }
1403 my @receiver_l = keys(%receiver_h);
1405 my $message_id = @{$hit}[0];
1407 #add each outgoing msg to messaging_db
1408 my $receiver;
1409 foreach $receiver (@receiver_l) {
1410 my $sql_statement = "INSERT INTO $messaging_tn (id, subject, message_from, message_to, flag, direction, delivery_time, message, timestamp) ".
1411 "VALUES ('".
1412 $message_id."', '". # id
1413 @{$hit}[1]."', '". # subject
1414 @{$hit}[2]."', '". # message_from
1415 $receiver."', '". # message_to
1416 "none"."', '". # flag
1417 "out"."', '". # direction
1418 @{$hit}[6]."', '". # delivery_time
1419 @{$hit}[7]."', '". # message
1420 $timestamp."'". # timestamp
1421 ")";
1422 &daemon_log("M DEBUG: $sql_statement", 1);
1423 my $res = $messaging_db->exec_statement($sql_statement);
1424 &daemon_log("M INFO: message '".@{$hit}[0]."' is prepared for delivery to receiver '$receiver'", 5);
1425 }
1427 # set incoming message to flag d=deliverd
1428 $sql_statement = "UPDATE $messaging_tn SET flag='p' WHERE id='$message_id'";
1429 &daemon_log("M DEBUG: $sql_statement", 7);
1430 $res = $messaging_db->update_dbentry($sql_statement);
1431 &daemon_log("M INFO: message '$message_id' is set to flag 'p' (processed)", 5);
1432 }
1434 $kernel->delay_set('watch_for_new_messages', $messaging_db_loop_delay);
1435 return;
1436 }
1438 sub watch_for_delivery_messages {
1439 my ($kernel, $heap) = @_[KERNEL, HEAP];
1441 # select outgoing messages
1442 my $sql_statement = "SELECT * FROM $messaging_tn WHERE ( flag='p' AND direction='out' )";
1443 #&daemon_log("0 DEBUG: $sql", 7);
1444 my $res = $messaging_db->exec_statement( $sql_statement );
1446 # build out msg for each usr
1447 foreach my $hit (@{$res}) {
1448 my $receiver = @{$hit}[3];
1449 my $msg_id = @{$hit}[0];
1450 my $subject = @{$hit}[1];
1451 my $message = @{$hit}[7];
1453 # resolve usr -> host where usr is logged in
1454 my $sql = "SELECT * FROM $login_users_tn WHERE (user='$receiver')";
1455 #&daemon_log("0 DEBUG: $sql", 7);
1456 my $res = $login_users_db->exec_statement($sql);
1458 # reciver is logged in nowhere
1459 if (not ref(@$res[0]) eq "ARRAY") { next; }
1461 my $send_succeed = 0;
1462 foreach my $hit (@$res) {
1463 my $receiver_host = @$hit[0];
1464 &daemon_log("M DEBUG: user '$receiver' is logged in at host '$receiver_host'", 7);
1466 # fetch key to encrypt msg propperly for usr/host
1467 my $sql = "SELECT * FROM $known_clients_tn WHERE (hostname='$receiver_host')";
1468 &daemon_log("0 DEBUG: $sql", 7);
1469 my $res = $known_clients_db->exec_statement($sql);
1471 # host is already down
1472 if (not ref(@$res[0]) eq "ARRAY") { next; }
1474 # host is on
1475 my $receiver_key = @{@{$res}[0]}[2];
1476 my %data = ('subject' => $subject, 'message' => $message, 'usr' => $receiver);
1477 my $out_msg = &build_msg("usr_msg", $server_address, $receiver_host, \%data );
1478 my $error = &send_msg_to_target($out_msg, $receiver_host, $receiver_key, "usr_msg", 0);
1479 if ($error == 0 ) {
1480 $send_succeed++ ;
1481 }
1482 }
1484 if ($send_succeed) {
1485 # set outgoing msg at db to deliverd
1486 my $sql = "UPDATE $messaging_tn SET flag='d' WHERE (id='$msg_id' AND direction='out' AND message_to='$receiver')";
1487 &daemon_log("0 DEBUG: $sql", 7);
1488 my $res = $messaging_db->exec_statement($sql);
1489 }
1490 }
1492 $kernel->delay_set('watch_for_delivery_messages', $messaging_db_loop_delay);
1493 return;
1494 }
1497 sub watch_for_done_messages {
1498 my ($kernel,$heap) = @_[KERNEL, HEAP];
1500 my $sql = "SELECT * FROM $messaging_tn WHERE (flag='p' AND direction='in')";
1501 #&daemon_log("0 DEBUG: $sql", 7);
1502 my $res = $messaging_db->exec_statement($sql);
1504 foreach my $hit (@{$res}) {
1505 my $msg_id = @{$hit}[0];
1507 my $sql = "SELECT * FROM $messaging_tn WHERE (id='$msg_id' AND direction='out' AND (NOT flag='s'))";
1508 #&daemon_log("0 DEBUG: $sql", 7);
1509 my $res = $messaging_db->exec_statement($sql);
1511 # not all usr msgs have been seen till now
1512 if ( ref(@$res[0]) eq "ARRAY") { next; }
1514 $sql = "DELETE FROM $messaging_tn WHERE (id='$msg_id')";
1515 #&daemon_log("0 DEBUG: $sql", 7);
1516 $res = $messaging_db->exec_statement($sql);
1518 }
1520 $kernel->delay_set('watch_for_done_messages', $messaging_db_loop_delay);
1521 return;
1522 }
1525 sub get_ldap_handle {
1526 my ($session_id) = @_;
1527 my $heap;
1528 my $ldap_handle;
1530 if (not defined $session_id ) { $session_id = 0 };
1531 if ($session_id =~ /[^0-9]*/) { $session_id = 0 };
1533 if ($session_id == 0) {
1534 daemon_log("$session_id DEBUG: get_ldap_handle invoked without a session_id, create a new ldap_handle", 7);
1535 $ldap_handle = Net::LDAP->new( $ldap_uri );
1536 $ldap_handle->bind($ldap_admin_dn, password => $ldap_admin_password);
1538 } else {
1539 my $session_reference = $global_kernel->ID_id_to_session($session_id);
1540 if( defined $session_reference ) {
1541 $heap = $session_reference->get_heap();
1542 }
1544 if (not defined $heap) {
1545 daemon_log("$session_id DEBUG: cannot get heap for session_id '$session_id'", 7);
1546 return;
1547 }
1549 # TODO: This "if" is nonsense, because it doesn't prove that the
1550 # used handle is still valid - or if we've to reconnect...
1551 #if (not exists $heap->{ldap_handle}) {
1552 $ldap_handle = Net::LDAP->new( $ldap_uri );
1553 $ldap_handle->bind($ldap_admin_dn, password => $ldap_admin_password);
1554 $heap->{ldap_handle} = $ldap_handle;
1555 #}
1556 }
1557 return $ldap_handle;
1558 }
1561 sub change_fai_state {
1562 my ($st, $targets, $session_id) = @_;
1563 $session_id = 0 if not defined $session_id;
1564 # Set FAI state to localboot
1565 my %mapActions= (
1566 reboot => '',
1567 update => 'softupdate',
1568 localboot => 'localboot',
1569 reinstall => 'install',
1570 rescan => '',
1571 wake => '',
1572 memcheck => 'memcheck',
1573 sysinfo => 'sysinfo',
1574 install => 'install',
1575 );
1577 # Return if this is unknown
1578 if (!exists $mapActions{ $st }){
1579 daemon_log("$session_id ERROR: unknown action '$st', can not translate ot FAIstate", 1);
1580 return;
1581 }
1583 my $state= $mapActions{ $st };
1585 my $ldap_handle = &get_ldap_handle($session_id);
1586 if( defined($ldap_handle) ) {
1588 # Build search filter for hosts
1589 my $search= "(&(objectClass=GOhard)";
1590 foreach (@{$targets}){
1591 $search.= "(macAddress=$_)";
1592 }
1593 $search.= ")";
1595 # If there's any host inside of the search string, procress them
1596 if (!($search =~ /macAddress/)){
1597 daemon_log("$session_id ERROR: no macAddress found in filter statement for LDAP search: '$search'", 1);
1598 return;
1599 }
1601 # Perform search for Unit Tag
1602 my $mesg = $ldap_handle->search(
1603 base => $ldap_base,
1604 scope => 'sub',
1605 attrs => ['dn', 'FAIstate', 'objectClass'],
1606 filter => "$search"
1607 );
1609 if ($mesg->count) {
1610 my @entries = $mesg->entries;
1611 foreach my $entry (@entries) {
1612 # Only modify entry if it is not set to '$state'
1613 if ($entry->get_value("FAIstate") ne "$state"){
1614 daemon_log("$session_id INFO: Setting FAIstate to '$state' for ".$entry->dn, 5);
1615 my $result;
1616 my %tmp = map { $_ => 1 } $entry->get_value("objectClass");
1617 if (exists $tmp{'FAIobject'}){
1618 if ($state eq ''){
1619 $result= $ldap_handle->modify($entry->dn, changes => [
1620 delete => [ FAIstate => [] ] ]);
1621 } else {
1622 $result= $ldap_handle->modify($entry->dn, changes => [
1623 replace => [ FAIstate => $state ] ]);
1624 }
1625 } elsif ($state ne ''){
1626 $result= $ldap_handle->modify($entry->dn, changes => [
1627 add => [ objectClass => 'FAIobject' ],
1628 add => [ FAIstate => $state ] ]);
1629 }
1631 # Errors?
1632 if ($result->code){
1633 daemon_log("$session_id Error: Setting FAIstate to '$state' for ".$entry->dn. "failed: ".$result->error, 1);
1634 }
1635 } else {
1636 daemon_log("$session_id DEBUG FAIstate at host '".$entry->dn."' already at state '$st'", 7);
1637 }
1638 }
1639 }
1640 # if no ldap handle defined
1641 } else {
1642 daemon_log("$session_id ERROR: no LDAP handle defined for update FAIstate", 1);
1643 }
1645 }
1648 sub change_goto_state {
1649 my ($st, $targets, $session_id) = @_;
1650 $session_id = 0 if not defined $session_id;
1652 # Switch on or off?
1653 my $state= $st eq 'active' ? 'active': 'locked';
1655 my $ldap_handle = &get_ldap_handle($session_id);
1656 if( defined($ldap_handle) ) {
1658 # Build search filter for hosts
1659 my $search= "(&(objectClass=GOhard)";
1660 foreach (@{$targets}){
1661 $search.= "(macAddress=$_)";
1662 }
1663 $search.= ")";
1665 # If there's any host inside of the search string, procress them
1666 if (!($search =~ /macAddress/)){
1667 return;
1668 }
1670 # Perform search for Unit Tag
1671 my $mesg = $ldap_handle->search(
1672 base => $ldap_base,
1673 scope => 'sub',
1674 attrs => ['dn', 'gotoMode'],
1675 filter => "$search"
1676 );
1678 if ($mesg->count) {
1679 my @entries = $mesg->entries;
1680 foreach my $entry (@entries) {
1682 # Only modify entry if it is not set to '$state'
1683 if ($entry->get_value("gotoMode") ne $state){
1685 daemon_log("$session_id INFO: Setting gotoMode to '$state' for ".$entry->dn, 5);
1686 my $result;
1687 $result= $ldap_handle->modify($entry->dn, changes => [
1688 replace => [ gotoMode => $state ] ]);
1690 # Errors?
1691 if ($result->code){
1692 &daemon_log("$session_id Error: Setting gotoMode to '$state' for ".$entry->dn. "failed: ".$result->error, 1);
1693 }
1695 }
1696 }
1697 }
1699 }
1700 }
1703 sub run_create_fai_server_db {
1704 my ($kernel, $session, $heap, $table_name) = @_[KERNEL, SESSION, HEAP, ARG0];
1705 my $session_id = $session->ID;
1706 my $task = POE::Wheel::Run->new(
1707 Program => sub { &create_fai_server_db($table_name,$kernel, undef, $session_id) },
1708 StdoutEvent => "session_run_result",
1709 StderrEvent => "session_run_debug",
1710 CloseEvent => "session_run_done",
1711 );
1713 $heap->{task}->{ $task->ID } = $task;
1714 return;
1715 }
1718 sub create_fai_server_db {
1719 my ($table_name, $kernel, $dont_create_packages_list, $session_id) = @_;
1720 my $result;
1722 if (not defined $session_id) { $session_id = 0; }
1723 my $ldap_handle = &get_ldap_handle();
1724 if(defined($ldap_handle)) {
1725 daemon_log("$session_id INFO: create_fai_server_db: start", 5);
1726 my $mesg= $ldap_handle->search(
1727 base => $ldap_base,
1728 scope => 'sub',
1729 attrs => ['FAIrepository', 'gosaUnitTag'],
1730 filter => "(&(FAIrepository=*)(objectClass=FAIrepositoryServer))",
1731 );
1732 if($mesg->{'resultCode'} == 0 &&
1733 $mesg->count != 0) {
1734 foreach my $entry (@{$mesg->{entries}}) {
1735 if($entry->exists('FAIrepository')) {
1736 # Add an entry for each Repository configured for server
1737 foreach my $repo(@{$entry->get_value('FAIrepository', asref => 1)}) {
1738 my($tmp_url,$tmp_server,$tmp_release,$tmp_sections) = split(/\|/, $repo);
1739 my $tmp_tag= $entry->get_value('gosaUnitTag') || "";
1740 $result= $fai_server_db->add_dbentry( {
1741 table => $table_name,
1742 primkey => ['server', 'release', 'tag'],
1743 server => $tmp_url,
1744 release => $tmp_release,
1745 sections => $tmp_sections,
1746 tag => (length($tmp_tag)>0)?$tmp_tag:"",
1747 } );
1748 }
1749 }
1750 }
1751 }
1752 daemon_log("$session_id INFO: create_fai_server_db: finished", 5);
1754 # TODO: Find a way to post the 'create_packages_list_db' event
1755 if(not defined($dont_create_packages_list)) {
1756 &create_packages_list_db(undef, undef, $session_id);
1757 }
1758 }
1760 $ldap_handle->disconnect;
1761 return $result;
1762 }
1765 sub run_create_fai_release_db {
1766 my ($session, $heap, $table_name) = @_[SESSION, HEAP, ARG0];
1767 my $session_id = $session->ID;
1768 my $task = POE::Wheel::Run->new(
1769 Program => sub { &create_fai_release_db($table_name, $session_id) },
1770 StdoutEvent => "session_run_result",
1771 StderrEvent => "session_run_debug",
1772 CloseEvent => "session_run_done",
1773 );
1775 $heap->{task}->{ $task->ID } = $task;
1776 return;
1777 }
1780 sub create_fai_release_db {
1781 my ($table_name, $session_id) = @_;
1782 my $result;
1784 # used for logging
1785 if (not defined $session_id) { $session_id = 0; }
1787 my $ldap_handle = &get_ldap_handle();
1788 if(defined($ldap_handle)) {
1789 daemon_log("$session_id INFO: create_fai_release_db: start",5);
1790 my $mesg= $ldap_handle->search(
1791 base => $ldap_base,
1792 scope => 'sub',
1793 attrs => [],
1794 filter => "(&(objectClass=organizationalUnit)(ou=fai))",
1795 );
1796 if($mesg->{'resultCode'} == 0 &&
1797 $mesg->count != 0) {
1798 # Walk through all possible FAI container ou's
1799 my @sql_list;
1800 my $timestamp= &get_time();
1801 foreach my $ou (@{$mesg->{entries}}) {
1802 my $tmp_classes= resolve_fai_classes($ou->dn, $ldap_handle, $session_id);
1803 if(defined($tmp_classes) && ref($tmp_classes) eq 'HASH') {
1804 my @tmp_array=get_fai_release_entries($tmp_classes);
1805 if(@tmp_array) {
1806 foreach my $entry (@tmp_array) {
1807 if(defined($entry) && ref($entry) eq 'HASH') {
1808 my $sql=
1809 "INSERT INTO $table_name "
1810 ."(timestamp, release, class, type, state) VALUES ("
1811 .$timestamp.","
1812 ."'".$entry->{'release'}."',"
1813 ."'".$entry->{'class'}."',"
1814 ."'".$entry->{'type'}."',"
1815 ."'".$entry->{'state'}."')";
1816 push @sql_list, $sql;
1817 }
1818 }
1819 }
1820 }
1821 }
1823 daemon_log("$session_id DEBUG: Inserting ".scalar @sql_list." entries to DB",8);
1824 if(@sql_list) {
1825 unshift @sql_list, "VACUUM";
1826 unshift @sql_list, "DELETE FROM $table_name";
1827 $fai_release_db->exec_statementlist(\@sql_list);
1828 }
1829 daemon_log("$session_id DEBUG: Done with inserting",7);
1830 }
1831 daemon_log("$session_id INFO: create_fai_release_db: finished",5);
1832 }
1833 $ldap_handle->disconnect;
1834 return $result;
1835 }
1837 sub get_fai_types {
1838 my $tmp_classes = shift || return undef;
1839 my @result;
1841 foreach my $type(keys %{$tmp_classes}) {
1842 if(defined($tmp_classes->{$type}[0]) && (!($tmp_classes->{$type}[0] =~ /^.*?removed.*?$/))) {
1843 my $entry = {
1844 type => $type,
1845 state => $tmp_classes->{$type}[0],
1846 };
1847 push @result, $entry;
1848 }
1849 }
1851 return @result;
1852 }
1854 sub get_fai_state {
1855 my $result = "";
1856 my $tmp_classes = shift || return $result;
1858 foreach my $type(keys %{$tmp_classes}) {
1859 if(defined($tmp_classes->{$type}[0])) {
1860 $result = $tmp_classes->{$type}[0];
1862 # State is equal for all types in class
1863 last;
1864 }
1865 }
1867 return $result;
1868 }
1870 sub resolve_fai_classes {
1871 my ($fai_base, $ldap_handle, $session_id) = @_;
1872 if (not defined $session_id) { $session_id = 0; }
1873 my $result;
1874 my @possible_fai_classes= ("FAIscript", "FAIhook", "FAIpartitionTable", "FAItemplate", "FAIvariable", "FAIprofile", "FAIpackageList");
1875 my $fai_filter= "(|(&(objectClass=FAIclass)(|(objectClass=".join(")(objectClass=", @possible_fai_classes).")))(objectClass=FAIbranch))";
1876 my $fai_classes;
1878 daemon_log("$session_id DEBUG: Searching for FAI entries in base $fai_base",7);
1879 my $mesg= $ldap_handle->search(
1880 base => $fai_base,
1881 scope => 'sub',
1882 attrs => ['cn','objectClass','FAIstate'],
1883 filter => $fai_filter,
1884 );
1885 daemon_log("$session_id DEBUG: Found ".$mesg->count()." FAI entries",7);
1887 if($mesg->{'resultCode'} == 0 &&
1888 $mesg->count != 0) {
1889 foreach my $entry (@{$mesg->{entries}}) {
1890 if($entry->exists('cn')) {
1891 my $tmp_dn= $entry->dn();
1893 # Skip classname and ou dn parts for class
1894 my $tmp_release = ($1) if $tmp_dn =~ /^[^,]+,[^,]+,(.*?),$fai_base$/;
1896 # Skip classes without releases
1897 if((!defined($tmp_release)) || length($tmp_release)==0) {
1898 next;
1899 }
1901 my $tmp_cn= $entry->get_value('cn');
1902 my $tmp_state= $entry->get_value('FAIstate');
1904 my $tmp_type;
1905 # Get FAI type
1906 for my $oclass(@{$entry->get_value('objectClass', asref => 1)}) {
1907 if(grep $_ eq $oclass, @possible_fai_classes) {
1908 $tmp_type= $oclass;
1909 last;
1910 }
1911 }
1913 if($tmp_release =~ /^.*?,.*?$/ && (!($tmp_release =~ /^.*?\\,.*?$/))) {
1914 # A Subrelease
1915 my @sub_releases = split(/,/, $tmp_release);
1917 # Walk through subreleases and build hash tree
1918 my $hash;
1919 while(my $tmp_sub_release = pop @sub_releases) {
1920 $hash .= "\{'$tmp_sub_release'\}->";
1921 }
1922 eval('push @{$fai_classes->'.$hash.'{$tmp_cn}->{$tmp_type}}, (defined($tmp_state) && length($tmp_state)>0)?$tmp_state:"";');
1923 } else {
1924 # A branch, no subrelease
1925 push @{$fai_classes->{$tmp_release}->{$tmp_cn}->{$tmp_type}}, (defined($tmp_state) && length($tmp_state)>0)?$tmp_state:"";
1926 }
1927 } elsif (!$entry->exists('cn')) {
1928 my $tmp_dn= $entry->dn();
1929 my $tmp_release = ($1) if $tmp_dn =~ /^(.*?),$fai_base$/;
1931 # Skip classes without releases
1932 if((!defined($tmp_release)) || length($tmp_release)==0) {
1933 next;
1934 }
1936 if($tmp_release =~ /^.*?,.*?$/ && (!($tmp_release =~ /^.*?\\,.*?$/))) {
1937 # A Subrelease
1938 my @sub_releases= split(/,/, $tmp_release);
1940 # Walk through subreleases and build hash tree
1941 my $hash;
1942 while(my $tmp_sub_release = pop @sub_releases) {
1943 $hash .= "\{'$tmp_sub_release'\}->";
1944 }
1945 # Remove the last two characters
1946 chop($hash);
1947 chop($hash);
1949 eval('$fai_classes->'.$hash.'= {}');
1950 } else {
1951 # A branch, no subrelease
1952 if(!exists($fai_classes->{$tmp_release})) {
1953 $fai_classes->{$tmp_release} = {};
1954 }
1955 }
1956 }
1957 }
1959 # The hash is complete, now we can honor the copy-on-write based missing entries
1960 foreach my $release (keys %$fai_classes) {
1961 $result->{$release}= deep_copy(apply_fai_inheritance($fai_classes->{$release}));
1962 }
1963 }
1964 return $result;
1965 }
1967 sub apply_fai_inheritance {
1968 my $fai_classes = shift || return {};
1969 my $tmp_classes;
1971 # Get the classes from the branch
1972 foreach my $class (keys %{$fai_classes}) {
1973 # Skip subreleases
1974 if($class =~ /^ou=.*$/) {
1975 next;
1976 } else {
1977 $tmp_classes->{$class}= deep_copy($fai_classes->{$class});
1978 }
1979 }
1981 # Apply to each subrelease
1982 foreach my $subrelease (keys %{$fai_classes}) {
1983 if($subrelease =~ /ou=/) {
1984 foreach my $tmp_class (keys %{$tmp_classes}) {
1985 if(!exists($fai_classes->{$subrelease}->{$tmp_class})) {
1986 $fai_classes->{$subrelease}->{$tmp_class} =
1987 deep_copy($tmp_classes->{$tmp_class});
1988 } else {
1989 foreach my $type (keys %{$tmp_classes->{$tmp_class}}) {
1990 if(!exists($fai_classes->{$subrelease}->{$tmp_class}->{$type})) {
1991 $fai_classes->{$subrelease}->{$tmp_class}->{$type}=
1992 deep_copy($tmp_classes->{$tmp_class}->{$type});
1993 }
1994 }
1995 }
1996 }
1997 }
1998 }
2000 # Find subreleases in deeper levels
2001 foreach my $subrelease (keys %{$fai_classes}) {
2002 if($subrelease =~ /ou=/) {
2003 foreach my $subsubrelease (keys %{$fai_classes->{$subrelease}}) {
2004 if($subsubrelease =~ /ou=/) {
2005 apply_fai_inheritance($fai_classes->{$subrelease});
2006 }
2007 }
2008 }
2009 }
2011 return $fai_classes;
2012 }
2014 sub get_fai_release_entries {
2015 my $tmp_classes = shift || return;
2016 my $parent = shift || "";
2017 my @result = shift || ();
2019 foreach my $entry (keys %{$tmp_classes}) {
2020 if(defined($entry)) {
2021 if($entry =~ /^ou=.*$/) {
2022 my $release_name = $entry;
2023 $release_name =~ s/ou=//g;
2024 if(length($parent)>0) {
2025 $release_name = $parent."/".$release_name;
2026 }
2027 my @bufentries = get_fai_release_entries($tmp_classes->{$entry}, $release_name, @result);
2028 foreach my $bufentry(@bufentries) {
2029 push @result, $bufentry;
2030 }
2031 } else {
2032 my @types = get_fai_types($tmp_classes->{$entry});
2033 foreach my $type (@types) {
2034 push @result,
2035 {
2036 'class' => $entry,
2037 'type' => $type->{'type'},
2038 'release' => $parent,
2039 'state' => $type->{'state'},
2040 };
2041 }
2042 }
2043 }
2044 }
2046 return @result;
2047 }
2049 sub deep_copy {
2050 my $this = shift;
2051 if (not ref $this) {
2052 $this;
2053 } elsif (ref $this eq "ARRAY") {
2054 [map deep_copy($_), @$this];
2055 } elsif (ref $this eq "HASH") {
2056 +{map { $_ => deep_copy($this->{$_}) } keys %$this};
2057 } else { die "what type is $_?" }
2058 }
2061 sub session_run_result {
2062 my ($kernel, $heap, $client_answer) = @_[KERNEL, HEAP, ARG0];
2063 $kernel->sig(CHLD => "child_reap");
2064 }
2066 sub session_run_debug {
2067 my $result = $_[ARG0];
2068 print STDERR "$result\n";
2069 }
2071 sub session_run_done {
2072 my ( $kernel, $heap, $task_id ) = @_[ KERNEL, HEAP, ARG0 ];
2073 delete $heap->{task}->{$task_id};
2074 }
2077 sub create_sources_list {
2078 my $session_id = shift;
2079 my $ldap_handle = &main::get_ldap_handle;
2080 my $result="/tmp/gosa_si_tmp_sources_list";
2082 # Remove old file
2083 if(stat($result)) {
2084 unlink($result);
2085 &main::daemon_log("$session_id DEBUG: remove an old version of '$result'", 7);
2086 }
2088 my $fh;
2089 open($fh, ">$result");
2090 if (not defined $fh) {
2091 &main::daemon_log("$session_id DEBUG: cannot open '$result' for writing", 7);
2092 return undef;
2093 }
2094 if(defined($main::ldap_server_dn) and length($main::ldap_server_dn) > 0) {
2095 my $mesg=$ldap_handle->search(
2096 base => $main::ldap_server_dn,
2097 scope => 'base',
2098 attrs => 'FAIrepository',
2099 filter => 'objectClass=FAIrepositoryServer'
2100 );
2101 if($mesg->count) {
2102 foreach my $entry(@{$mesg->{'entries'}}) {
2103 foreach my $value(@{$entry->get_value('FAIrepository', asref => 1)}) {
2104 my ($server, $tag, $release, $sections)= split /\|/, $value;
2105 my $line = "deb $server $release";
2106 $sections =~ s/,/ /g;
2107 $line.= " $sections";
2108 print $fh $line."\n";
2109 }
2110 }
2111 }
2112 } else {
2113 if (defined $main::ldap_server_dn){
2114 &main::daemon_log("$session_id ERROR: something wrong with ldap_server_dn '$main::ldap_server_dn', abort create_sources_list", 1);
2115 } else {
2116 &main::daemon_log("$session_id ERROR: no ldap_server_dn found, abort create_sources_list", 1);
2117 }
2118 }
2119 close($fh);
2121 return $result;
2122 }
2125 sub run_create_packages_list_db {
2126 my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
2127 my $session_id = $session->ID;
2129 my $task = POE::Wheel::Run->new(
2130 Priority => +20,
2131 Program => sub {&create_packages_list_db(undef, undef, $session_id)},
2132 StdoutEvent => "session_run_result",
2133 StderrEvent => "session_run_debug",
2134 CloseEvent => "session_run_done",
2135 );
2136 $heap->{task}->{ $task->ID } = $task;
2137 }
2140 sub create_packages_list_db {
2141 my ($ldap_handle, $sources_file, $session_id) = @_;
2143 # it should not be possible to trigger a recreation of packages_list_db
2144 # while packages_list_db is under construction, so set flag packages_list_under_construction
2145 # which is tested befor recreation can be started
2146 if (-r $packages_list_under_construction) {
2147 daemon_log("$session_id WARNING: packages_list_db is right now under construction, please wait until this process is finished", 3);
2148 return;
2149 } else {
2150 daemon_log("$session_id INFO: create_packages_list_db: start", 5);
2151 # set packages_list_under_construction to true
2152 system("touch $packages_list_under_construction");
2153 @packages_list_statements=();
2154 }
2156 if (not defined $session_id) { $session_id = 0; }
2157 if (not defined $ldap_handle) {
2158 $ldap_handle= &get_ldap_handle();
2160 if (not defined $ldap_handle) {
2161 daemon_log("$session_id ERROR: no ldap_handle available to create_packages_list_db", 1);
2162 unlink($packages_list_under_construction);
2163 return;
2164 }
2165 }
2166 if (not defined $sources_file) {
2167 &main::daemon_log("$session_id INFO: no sources_file given for creating packages list so trigger creation of it", 5);
2168 $sources_file = &create_sources_list($session_id);
2169 }
2171 if (not defined $sources_file) {
2172 &main::daemon_log("$session_id ERROR: no sources_file given under '$sources_file', skip create_packages_list_db", 1);
2173 unlink($packages_list_under_construction);
2174 return;
2175 }
2177 my $line;
2179 open(CONFIG, "<$sources_file") or do {
2180 daemon_log( "$session_id ERROR: create_packages_list_db: Failed to open '$sources_file'", 1);
2181 unlink($packages_list_under_construction);
2182 return;
2183 };
2185 # Read lines
2186 while ($line = <CONFIG>){
2187 # Unify
2188 chop($line);
2189 $line =~ s/^\s+//;
2190 $line =~ s/^\s+/ /;
2192 # Strip comments
2193 $line =~ s/#.*$//g;
2195 # Skip empty lines
2196 if ($line =~ /^\s*$/){
2197 next;
2198 }
2200 # Interpret deb line
2201 if ($line =~ /^deb [^\s]+\s[^\s]+\s[^\s]+/){
2202 my( $baseurl, $dist, $sections ) = ($line =~ /^deb\s([^\s]+)\s+([^\s]+)\s+(.*)$/);
2203 my $section;
2204 foreach $section (split(' ', $sections)){
2205 &parse_package_info( $baseurl, $dist, $section, $session_id );
2206 }
2207 }
2208 }
2210 close (CONFIG);
2212 find(\&cleanup_and_extract, keys( %repo_dirs ));
2213 eval {
2214 &main::strip_packages_list_statements();
2215 };
2216 if($@) {
2217 daemon_log("$session_id ERROR: Preparation of statement list failed with '$@'!", 1);
2218 }
2219 unshift @packages_list_statements, "VACUUM";
2220 eval {
2221 $packages_list_db->exec_statementlist(\@packages_list_statements);
2222 };
2223 if($@) {
2224 daemon_log("$session_id ERROR: Updating package_list_db failed with '$@'!", 1);
2225 }
2226 unlink($packages_list_under_construction);
2227 daemon_log("$session_id INFO: create_packages_list_db: finished", 5);
2228 return;
2229 }
2232 # This function should do some intensive task to minimize the db-traffic
2233 sub strip_packages_list_statements {
2234 my @existing_entries= @{$packages_list_db->exec_statement("SELECT * FROM $main::packages_list_tn")};
2235 my @new_statement_list=();
2236 my $hash;
2237 my $insert_hash;
2238 my $update_hash;
2239 my $delete_hash;
2240 my $local_timestamp=get_time();
2242 foreach my $existing_entry (@existing_entries) {
2243 $hash->{@{$existing_entry}[0]}->{@{$existing_entry}[1]}->{@{$existing_entry}[2]}= $existing_entry;
2244 }
2246 foreach my $statement (@packages_list_statements) {
2247 if($statement =~ /^INSERT/i) {
2248 # Assign the values from the insert statement
2249 my ($distribution,$package,$version,$section,$description,$template,$timestamp) = ($1,$2,$3,$4,$5,$6,$7) if $statement =~
2250 /^INSERT\s+?INTO\s+?$main::packages_list_tn\s+?VALUES\s*?\('(.*?)',\s*?'(.*?)',\s*?'(.*?)',\s*?'(.*?)',\s*?'(.*?)',\s*?'(.*?)',\s*?'(.*?)'\s*?\)$/si;
2251 if(exists($hash->{$distribution}->{$package}->{$version})) {
2252 # If section or description has changed, update the DB
2253 if(
2254 (! (@{$hash->{$distribution}->{$package}->{$version}}[3] eq $section)) or
2255 (! (@{$hash->{$distribution}->{$package}->{$version}}[4] eq $description))
2256 ) {
2257 @{$update_hash->{$distribution}->{$package}->{$version}} = ($distribution,$package,$version,$section,$description,undef);
2258 }
2259 } else {
2260 # Insert a non-existing entry to db
2261 @{$insert_hash->{$distribution}->{$package}->{$version}} = ($distribution,$package,$version,$section,$description,$template);
2262 }
2263 } elsif ($statement =~ /^UPDATE/i) {
2264 my ($template,$package,$version) = ($1,$2,$3) if $statement =~
2265 /^update\s+?$main::packages_list_tn\s+?set\s+?template\s*?=\s*?'(.*?)'\s+?where\s+?package\s*?=\s*?'(.*?)'\s+?and\s+?version\s*?=\s*?'(.*?)'\s*?;$/si;
2266 foreach my $distribution (keys %{$hash}) {
2267 if(exists($insert_hash->{$distribution}->{$package}->{$version})) {
2268 # update the insertion hash to execute only one query per package (insert instead insert+update)
2269 @{$insert_hash->{$distribution}->{$package}->{$version}}[5]= $template;
2270 } elsif(exists($hash->{$distribution}->{$package}->{$version})) {
2271 if( ! (@{$hash->{$distribution}->{$package}->{$version}}[5] eq $template)) {
2272 my $section;
2273 my $description;
2274 if(defined(@{$update_hash->{$distribution}->{$package}->{$version}}[3]) and
2275 length(@{$update_hash->{$distribution}->{$package}->{$version}}[3]) > 0 ) {
2276 $section= @{$update_hash->{$distribution}->{$package}->{$version}}[3];
2277 }
2278 if(defined(@{$update_hash->{$distribution}->{$package}->{$version}}[4])) {
2279 $description= @{$update_hash->{$distribution}->{$package}->{$version}}[4];
2280 }
2281 @{$update_hash->{$distribution}->{$package}->{$version}} = ($distribution,$package,$version,$section,$description,$template);
2282 }
2283 }
2284 }
2285 }
2286 }
2288 # TODO: Check for orphaned entries
2290 # unroll the insert_hash
2291 foreach my $distribution (keys %{$insert_hash}) {
2292 foreach my $package (keys %{$insert_hash->{$distribution}}) {
2293 foreach my $version (keys %{$insert_hash->{$distribution}->{$package}}) {
2294 push @new_statement_list, "INSERT INTO $main::packages_list_tn VALUES ('$distribution','$package','$version',"
2295 ."'@{$insert_hash->{$distribution}->{$package}->{$version}}[3]',"
2296 ."'@{$insert_hash->{$distribution}->{$package}->{$version}}[4]',"
2297 ."'@{$insert_hash->{$distribution}->{$package}->{$version}}[5]',"
2298 ."'$local_timestamp')";
2299 }
2300 }
2301 }
2303 # unroll the update hash
2304 foreach my $distribution (keys %{$update_hash}) {
2305 foreach my $package (keys %{$update_hash->{$distribution}}) {
2306 foreach my $version (keys %{$update_hash->{$distribution}->{$package}}) {
2307 my $set = "";
2308 if(defined(@{$update_hash->{$distribution}->{$package}->{$version}}[3])) {
2309 $set .= "section = '@{$update_hash->{$distribution}->{$package}->{$version}}[3]', ";
2310 }
2311 if(defined(@{$update_hash->{$distribution}->{$package}->{$version}}[4])) {
2312 $set .= "description = '@{$update_hash->{$distribution}->{$package}->{$version}}[4]', ";
2313 }
2314 if(defined(@{$update_hash->{$distribution}->{$package}->{$version}}[5])) {
2315 $set .= "template = '@{$update_hash->{$distribution}->{$package}->{$version}}[5]', ";
2316 }
2317 if(defined($set) and length($set) > 0) {
2318 $set .= "timestamp = '$local_timestamp'";
2319 } else {
2320 next;
2321 }
2322 push @new_statement_list,
2323 "UPDATE $main::packages_list_tn SET $set WHERE"
2324 ." distribution = '$distribution'"
2325 ." AND package = '$package'"
2326 ." AND version = '$version'";
2327 }
2328 }
2329 }
2331 @packages_list_statements = @new_statement_list;
2332 }
2335 sub parse_package_info {
2336 my ($baseurl, $dist, $section, $session_id)= @_;
2337 my ($package);
2338 if (not defined $session_id) { $session_id = 0; }
2339 my ($path) = ($baseurl =~ m%://[^/]*(.*)$%);
2340 $repo_dirs{ "${repo_path}/pool" } = 1;
2342 foreach $package ("Packages.gz"){
2343 daemon_log("$session_id DEBUG: create_packages_list: fetch $baseurl, $dist, $section", 7);
2344 get_package( "$baseurl/dists/$dist/$section/binary-$arch/$package", "$outdir/$dist/$section", $session_id );
2345 parse_package( "$outdir/$dist/$section", $dist, $path, $session_id );
2346 }
2348 }
2351 sub get_package {
2352 my ($url, $dest, $session_id)= @_;
2353 if (not defined $session_id) { $session_id = 0; }
2355 my $tpath = dirname($dest);
2356 -d "$tpath" || mkpath "$tpath";
2358 # This is ugly, but I've no time to take a look at "how it works in perl"
2359 if(0 == system("wget '$url' -O '$dest' 2>/dev/null") ) {
2360 system("gunzip -cd '$dest' > '$dest.in'");
2361 daemon_log("$session_id DEBUG: run command: gunzip -cd '$dest' > '$dest.in'", 5);
2362 unlink($dest);
2363 daemon_log("$session_id DEBUG: delete file '$dest'", 5);
2364 } else {
2365 daemon_log("$session_id ERROR: create_packages_list_db: get_packages: fetching '$url' failed!", 1);
2366 }
2367 return 0;
2368 }
2371 sub parse_package {
2372 my ($path, $dist, $srv_path, $session_id)= @_;
2373 if (not defined $session_id) { $session_id = 0;}
2374 my ($package, $version, $section, $description);
2375 my $PACKAGES;
2376 my $timestamp = &get_time();
2378 if(not stat("$path.in")) {
2379 daemon_log("$session_id ERROR: create_packages_list: parse_package: file '$path.in' is not readable",1);
2380 return;
2381 }
2383 open($PACKAGES, "<$path.in");
2384 if(not defined($PACKAGES)) {
2385 daemon_log("$session_id ERROR: create_packages_list_db: parse_package: cannot open '$path.in'",1);
2386 return;
2387 }
2389 # Read lines
2390 while (<$PACKAGES>){
2391 my $line = $_;
2392 # Unify
2393 chop($line);
2395 # Use empty lines as a trigger
2396 if ($line =~ /^\s*$/){
2397 my $sql = "INSERT INTO packages_list VALUES ('$dist', '$package', '$version', '$section', '$description', '', '$timestamp')";
2398 push(@packages_list_statements, $sql);
2399 $package = "none";
2400 $version = "none";
2401 $section = "none";
2402 $description = "none";
2403 next;
2404 }
2406 # Trigger for package name
2407 if ($line =~ /^Package:\s/){
2408 ($package)= ($line =~ /^Package: (.*)$/);
2409 next;
2410 }
2412 # Trigger for version
2413 if ($line =~ /^Version:\s/){
2414 ($version)= ($line =~ /^Version: (.*)$/);
2415 next;
2416 }
2418 # Trigger for description
2419 if ($line =~ /^Description:\s/){
2420 ($description)= &encode_base64(($line =~ /^Description: (.*)$/));
2421 next;
2422 }
2424 # Trigger for section
2425 if ($line =~ /^Section:\s/){
2426 ($section)= ($line =~ /^Section: (.*)$/);
2427 next;
2428 }
2430 # Trigger for filename
2431 if ($line =~ /^Filename:\s/){
2432 my ($filename) = ($line =~ /^Filename: (.*)$/);
2433 store_fileinfo( $package, $filename, $dist, $srv_path, $version, $repo_path );
2434 next;
2435 }
2436 }
2438 close( $PACKAGES );
2439 unlink( "$path.in" );
2440 &main::daemon_log("$session_id DEBUG: unlink '$path.in'", 1);
2441 }
2444 sub store_fileinfo {
2445 my( $package, $file, $dist, $path, $vers, $srvdir) = @_;
2447 my %fileinfo = (
2448 'package' => $package,
2449 'dist' => $dist,
2450 'version' => $vers,
2451 );
2453 $repo_files{ "${srvdir}/$file" } = \%fileinfo;
2454 }
2457 sub cleanup_and_extract {
2458 my $fileinfo = $repo_files{ $File::Find::name };
2460 if( defined $fileinfo ) {
2462 my $dir = "$outdir/$fileinfo->{ 'dist' }/debconf.d";
2463 my $sql;
2464 my $package = $fileinfo->{ 'package' };
2465 my $newver = $fileinfo->{ 'version' };
2467 mkpath($dir);
2468 system( "dpkg -e '$File::Find::name' '$dir/DEBIAN'" );
2470 if( -f "$dir/DEBIAN/templates" ) {
2472 daemon_log("DEBUG: Found debconf templates in '$package' - $newver", 5);
2474 my $tmpl= "";
2475 {
2476 local $/=undef;
2477 open FILE, "$dir/DEBIAN/templates";
2478 $tmpl = &encode_base64(<FILE>);
2479 close FILE;
2480 }
2481 rmtree("$dir/DEBIAN/templates");
2483 $sql= "update $main::packages_list_tn set template = '$tmpl' where package = '$package' and version = '$newver';";
2484 push @packages_list_statements, $sql;
2485 }
2486 }
2488 return;
2489 }
2492 #==== MAIN = main ==============================================================
2493 # parse commandline options
2494 Getopt::Long::Configure( "bundling" );
2495 GetOptions("h|help" => \&usage,
2496 "c|config=s" => \$cfg_file,
2497 "f|foreground" => \$foreground,
2498 "v|verbose+" => \$verbose,
2499 "no-bus+" => \$no_bus,
2500 "no-arp+" => \$no_arp,
2501 );
2503 # read and set config parameters
2504 &check_cmdline_param ;
2505 &read_configfile;
2506 &check_pid;
2508 $SIG{CHLD} = 'IGNORE';
2510 # forward error messages to logfile
2511 if( ! $foreground ) {
2512 open( STDIN, '+>/dev/null' );
2513 open( STDOUT, '+>&STDIN' );
2514 open( STDERR, '+>&STDIN' );
2515 }
2517 # Just fork, if we are not in foreground mode
2518 if( ! $foreground ) {
2519 chdir '/' or die "Can't chdir to /: $!";
2520 $pid = fork;
2521 setsid or die "Can't start a new session: $!";
2522 umask 0;
2523 } else {
2524 $pid = $$;
2525 }
2527 # Do something useful - put our PID into the pid_file
2528 if( 0 != $pid ) {
2529 open( LOCK_FILE, ">$pid_file" );
2530 print LOCK_FILE "$pid\n";
2531 close( LOCK_FILE );
2532 if( !$foreground ) {
2533 exit( 0 )
2534 };
2535 }
2537 # parse head url and revision from svn
2538 my $server_status_hash = { 'developmental'=>'revision', 'stable'=>'release'};
2539 $server_version =~ /^\$HeadURL: (\S+) \$:\$Rev: (\d+) \$$/;
2540 $server_headURL = defined $1 ? $1 : 'unknown' ;
2541 $server_revision = defined $2 ? $2 : 'unknown' ;
2542 if ($server_headURL =~ /\/tag\// ||
2543 $server_headURL =~ /\/branches\// ) {
2544 $server_status = "stable";
2545 } else {
2546 $server_status = "developmental" ;
2547 }
2550 daemon_log(" ", 1);
2551 daemon_log("$0 started!", 1);
2552 daemon_log("status: $server_status", 1);
2553 daemon_log($server_status_hash->{$server_status}.": $server_revision", 1);
2555 if ($no_bus > 0) {
2556 $bus_activ = "false"
2557 }
2559 # connect to gosa-si job queue
2560 $job_db = GOSA::DBsqlite->new($job_queue_file_name);
2561 $job_db->create_table($job_queue_tn, \@job_queue_col_names);
2563 # connect to known_clients_db
2564 $known_clients_db = GOSA::DBsqlite->new($known_clients_file_name);
2565 $known_clients_db->create_table($known_clients_tn, \@known_clients_col_names);
2567 # connect to known_server_db
2568 $known_server_db = GOSA::DBsqlite->new($known_server_file_name);
2569 $known_server_db->create_table($known_server_tn, \@known_server_col_names);
2571 # connect to login_usr_db
2572 $login_users_db = GOSA::DBsqlite->new($login_users_file_name);
2573 $login_users_db->create_table($login_users_tn, \@login_users_col_names);
2575 # connect to fai_server_db and fai_release_db
2576 unlink($fai_server_file_name);
2577 $fai_server_db = GOSA::DBsqlite->new($fai_server_file_name);
2578 $fai_server_db->create_table($fai_server_tn, \@fai_server_col_names);
2580 unlink($fai_release_file_name);
2581 $fai_release_db = GOSA::DBsqlite->new($fai_release_file_name);
2582 $fai_release_db->create_table($fai_release_tn, \@fai_release_col_names);
2584 # connect to packages_list_db
2585 #unlink($packages_list_file_name);
2586 unlink($packages_list_under_construction);
2587 $packages_list_db = GOSA::DBsqlite->new($packages_list_file_name);
2588 $packages_list_db->create_table($packages_list_tn, \@packages_list_col_names);
2590 # connect to messaging_db
2591 $messaging_db = GOSA::DBsqlite->new($messaging_file_name);
2592 $messaging_db->create_table($messaging_tn, \@messaging_col_names);
2595 # create xml object used for en/decrypting
2596 $xml = new XML::Simple();
2598 # create socket for incoming xml messages
2600 POE::Component::Server::TCP->new(
2601 Port => $server_port,
2602 ClientInput => sub {
2603 my ($kernel, $input) = @_[KERNEL, ARG0];
2604 push(@tasks, $input);
2605 $kernel->yield("next_task");
2606 },
2607 InlineStates => {
2608 next_task => \&next_task,
2609 task_result => \&handle_task_result,
2610 task_done => \&handle_task_done,
2611 task_debug => \&handle_task_debug,
2612 child_reap => sub { "Do nothing special. I'm just a comment, but i'm necessary!" },
2613 }
2614 );
2616 daemon_log("start socket for incoming xml messages at port '$server_port' ", 1);
2618 # create session for repeatedly checking the job queue for jobs
2619 POE::Session->create(
2620 inline_states => {
2621 _start => \&_start,
2622 sig_handler => \&sig_handler,
2623 watch_for_new_messages => \&watch_for_new_messages,
2624 watch_for_delivery_messages => \&watch_for_delivery_messages,
2625 watch_for_done_messages => \&watch_for_done_messages,
2626 watch_for_new_jobs => \&watch_for_new_jobs,
2627 watch_for_done_jobs => \&watch_for_done_jobs,
2628 create_packages_list_db => \&run_create_packages_list_db,
2629 create_fai_server_db => \&run_create_fai_server_db,
2630 create_fai_release_db => \&run_create_fai_release_db,
2631 session_run_result => \&session_run_result,
2632 session_run_debug => \&session_run_debug,
2633 session_run_done => \&session_run_done,
2634 child_reap => sub { "Do nothing special. I'm just a comment, but i'm necessary!" },
2635 }
2636 );
2639 # import all modules
2640 &import_modules;
2642 # check wether all modules are gosa-si valid passwd check
2644 POE::Kernel->run();
2645 exit;