7c689a3229ff41ae765363bc48b7bde0cb41f375
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 if(not defined open( LOG_HANDLE, ">>$log_file" )) {
293 print STDERR "cannot open $log_file: $!";
294 return }
295 chomp($msg);
296 $msg =~s/\n//g; # no newlines are allowed in log messages, this is important for later log parsing
297 if($level <= $verbose){
298 my ($seconds, $minutes, $hours, $monthday, $month,
299 $year, $weekday, $yearday, $sommertime) = localtime(time);
300 $hours = $hours < 10 ? $hours = "0".$hours : $hours;
301 $minutes = $minutes < 10 ? $minutes = "0".$minutes : $minutes;
302 $seconds = $seconds < 10 ? $seconds = "0".$seconds : $seconds;
303 my @monthnames = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
304 $month = $monthnames[$month];
305 $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday;
306 $year+=1900;
307 my $name = $prg;
309 my $log_msg = "$month $monthday $hours:$minutes:$seconds $name $msg\n";
310 print LOG_HANDLE $log_msg;
311 if( $foreground ) {
312 print STDERR $log_msg;
313 }
314 }
315 close( LOG_HANDLE );
316 }
317 }
320 #=== FUNCTION ================================================================
321 # NAME: check_cmdline_param
322 # PARAMETERS: nothing
323 # RETURNS: nothing
324 # DESCRIPTION: validates commandline parameter
325 #===============================================================================
326 sub check_cmdline_param () {
327 my $err_config;
328 my $err_counter = 0;
329 if(not defined($cfg_file)) {
330 $cfg_file = "/etc/gosa-si/server.conf";
331 if(! -r $cfg_file) {
332 $err_config = "please specify a config file";
333 $err_counter += 1;
334 }
335 }
336 if( $err_counter > 0 ) {
337 &usage( "", 1 );
338 if( defined( $err_config)) { print STDERR "$err_config\n"}
339 print STDERR "\n";
340 exit( -1 );
341 }
342 }
345 #=== FUNCTION ================================================================
346 # NAME: check_pid
347 # PARAMETERS: nothing
348 # RETURNS: nothing
349 # DESCRIPTION: handels pid processing
350 #===============================================================================
351 sub check_pid {
352 $pid = -1;
353 # Check, if we are already running
354 if( open(LOCK_FILE, "<$pid_file") ) {
355 $pid = <LOCK_FILE>;
356 if( defined $pid ) {
357 chomp( $pid );
358 if( -f "/proc/$pid/stat" ) {
359 my($stat) = `cat /proc/$pid/stat` =~ m/$pid \((.+)\).*/;
360 if( $stat ) {
361 daemon_log("ERROR: Already running",1);
362 close( LOCK_FILE );
363 exit -1;
364 }
365 }
366 }
367 close( LOCK_FILE );
368 unlink( $pid_file );
369 }
371 # create a syslog msg if it is not to possible to open PID file
372 if (not sysopen(LOCK_FILE, $pid_file, O_WRONLY|O_CREAT|O_EXCL, 0644)) {
373 my($msg) = "Couldn't obtain lockfile '$pid_file' ";
374 if (open(LOCK_FILE, '<', $pid_file)
375 && ($pid = <LOCK_FILE>))
376 {
377 chomp($pid);
378 $msg .= "(PID $pid)\n";
379 } else {
380 $msg .= "(unable to read PID)\n";
381 }
382 if( ! ($foreground) ) {
383 openlog( $0, "cons,pid", "daemon" );
384 syslog( "warning", $msg );
385 closelog();
386 }
387 else {
388 print( STDERR " $msg " );
389 }
390 exit( -1 );
391 }
392 }
394 #=== FUNCTION ================================================================
395 # NAME: import_modules
396 # PARAMETERS: module_path - string - abs. path to the directory the modules
397 # are stored
398 # RETURNS: nothing
399 # DESCRIPTION: each file in module_path which ends with '.pm' and activation
400 # state is on is imported by "require 'file';"
401 #===============================================================================
402 sub import_modules {
403 daemon_log(" ", 1);
405 if (not -e $modules_path) {
406 daemon_log("ERROR: cannot find directory or directory is not readable: $modules_path", 1);
407 }
409 opendir (DIR, $modules_path) or die "ERROR while loading modules from directory $modules_path : $!\n";
410 while (defined (my $file = readdir (DIR))) {
411 if (not $file =~ /(\S*?).pm$/) {
412 next;
413 }
414 my $mod_name = $1;
416 if( $file =~ /ArpHandler.pm/ ) {
417 if( $no_arp > 0 ) {
418 next;
419 }
420 }
422 eval { require $file; };
423 if ($@) {
424 daemon_log("ERROR: gosa-si-server could not load module $file", 1);
425 daemon_log("$@", 5);
426 } else {
427 my $info = eval($mod_name.'::get_module_info()');
428 # Only load module if get_module_info() returns a non-null object
429 if( $info ) {
430 my ($input_address, $input_key, $input, $input_active, $input_type) = @{$info};
431 $known_modules->{$mod_name} = $info;
432 daemon_log("INFO: module $mod_name loaded", 5);
433 }
434 }
435 }
436 close (DIR);
437 }
440 #=== FUNCTION ================================================================
441 # NAME: sig_int_handler
442 # PARAMETERS: signal - string - signal arose from system
443 # RETURNS: noting
444 # DESCRIPTION: handels tasks to be done befor signal becomes active
445 #===============================================================================
446 sub sig_int_handler {
447 my ($signal) = @_;
449 # if (defined($ldap_handle)) {
450 # $ldap_handle->disconnect;
451 # }
452 # TODO alle verbliebenden ldap verbindungen aus allen heaps beenden
455 daemon_log("shutting down gosa-si-server", 1);
456 system("kill `ps -C gosa-si-server -o pid=`");
457 }
458 $SIG{INT} = \&sig_int_handler;
461 sub check_key_and_xml_validity {
462 my ($crypted_msg, $module_key, $session_id) = @_;
463 my $msg;
464 my $msg_hash;
465 my $error_string;
466 eval{
467 $msg = &decrypt_msg($crypted_msg, $module_key);
469 if ($msg =~ /<xml>/i){
470 $msg =~ s/\s+/ /g; # just for better daemon_log
471 daemon_log("$session_id DEBUG: decrypted_msg: \n$msg", 8);
472 $msg_hash = $xml->XMLin($msg, ForceArray=>1);
474 ##############
475 # check header
476 if( not exists $msg_hash->{'header'} ) { die "no header specified"; }
477 my $header_l = $msg_hash->{'header'};
478 if( 1 > @{$header_l} ) { die 'empty header tag'; }
479 if( 1 < @{$header_l} ) { die 'more than one header specified'; }
480 my $header = @{$header_l}[0];
481 if( 0 == length $header) { die 'empty string in header tag'; }
483 ##############
484 # check source
485 if( not exists $msg_hash->{'source'} ) { die "no source specified"; }
486 my $source_l = $msg_hash->{'source'};
487 if( 1 > @{$source_l} ) { die 'empty source tag'; }
488 if( 1 < @{$source_l} ) { die 'more than one source specified'; }
489 my $source = @{$source_l}[0];
490 if( 0 == length $source) { die 'source error'; }
492 ##############
493 # check target
494 if( not exists $msg_hash->{'target'} ) { die "no target specified"; }
495 my $target_l = $msg_hash->{'target'};
496 if( 1 > @{$target_l} ) { die 'empty target tag'; }
497 }
498 };
499 if($@) {
500 daemon_log("$session_id DEBUG: do not understand the message: $@", 7);
501 $msg = undef;
502 $msg_hash = undef;
503 }
505 return ($msg, $msg_hash);
506 }
509 sub check_outgoing_xml_validity {
510 my ($msg) = @_;
512 my $msg_hash;
513 eval{
514 $msg_hash = $xml->XMLin($msg, ForceArray=>1);
516 ##############
517 # check header
518 my $header_l = $msg_hash->{'header'};
519 if( 1 != @{$header_l} ) {
520 die 'no or more than one headers specified';
521 }
522 my $header = @{$header_l}[0];
523 if( 0 == length $header) {
524 die 'header has length 0';
525 }
527 ##############
528 # check source
529 my $source_l = $msg_hash->{'source'};
530 if( 1 != @{$source_l} ) {
531 die 'no or more than 1 sources specified';
532 }
533 my $source = @{$source_l}[0];
534 if( 0 == length $source) {
535 die 'source has length 0';
536 }
537 unless( $source =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$/ ||
538 $source =~ /^GOSA$/i ) {
539 die "source '$source' is neither a complete ip-address with port nor 'GOSA'";
540 }
542 ##############
543 # check target
544 my $target_l = $msg_hash->{'target'};
545 if( 0 == @{$target_l} ) {
546 die "no targets specified";
547 }
548 foreach my $target (@$target_l) {
549 if( 0 == length $target) {
550 die "target has length 0";
551 }
552 unless( $target =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$/ ||
553 $target =~ /^GOSA$/i ||
554 $target =~ /^\*$/ ||
555 $target =~ /KNOWN_SERVER/i ||
556 $target =~ /JOBDB/i ||
557 $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 ){
558 die "target '$target' is not a complete ip-address with port or a valid target name or a mac-address";
559 }
560 }
561 };
562 if($@) {
563 daemon_log("WARNING: outgoing msg is not gosa-si envelope conform", 5);
564 daemon_log("$@ ".(defined($msg) && length($msg)>0)?$msg:"Empty Message", 8);
565 $msg_hash = undef;
566 }
568 return ($msg_hash);
569 }
572 sub input_from_known_server {
573 my ($input, $remote_ip, $session_id) = @_ ;
574 my ($msg, $msg_hash, $module);
576 my $sql_statement= "SELECT * FROM known_server";
577 my $query_res = $known_server_db->select_dbentry( $sql_statement );
579 while( my ($hit_num, $hit) = each %{ $query_res } ) {
580 my $host_name = $hit->{hostname};
581 if( not $host_name =~ "^$remote_ip") {
582 next;
583 }
584 my $host_key = $hit->{hostkey};
585 daemon_log("$session_id DEBUG: input_from_known_server: host_name: $host_name", 7);
586 daemon_log("DEBUG: input_from_known_server: host_key: $host_key", 7);
588 # check if module can open msg envelope with module key
589 my ($tmp_msg, $tmp_msg_hash) = &check_key_and_xml_validity($input, $host_key, $session_id);
590 if( (!$tmp_msg) || (!$tmp_msg_hash) ) {
591 daemon_log("$session_id DEBUG: input_from_known_server: deciphering raise error", 7);
592 daemon_log("$@", 8);
593 next;
594 }
595 else {
596 $msg = $tmp_msg;
597 $msg_hash = $tmp_msg_hash;
598 $module = "SIPackages";
599 last;
600 }
601 }
603 if( (!$msg) || (!$msg_hash) || (!$module) ) {
604 daemon_log("$session_id DEBUG: Incoming message is not from a known server", 7);
605 }
607 return ($msg, $msg_hash, $module);
608 }
611 sub input_from_known_client {
612 my ($input, $remote_ip, $session_id) = @_ ;
613 my ($msg, $msg_hash, $module);
615 my $sql_statement= "SELECT * FROM known_clients";
616 my $query_res = $known_clients_db->select_dbentry( $sql_statement );
617 while( my ($hit_num, $hit) = each %{ $query_res } ) {
618 my $host_name = $hit->{hostname};
619 if( not $host_name =~ /^$remote_ip:\d*$/) {
620 next;
621 }
622 my $host_key = $hit->{hostkey};
623 &daemon_log("$session_id DEBUG: input_from_known_client: host_name: $host_name", 7);
624 &daemon_log("$session_id DEBUG: input_from_known_client: host_key: $host_key", 7);
626 # check if module can open msg envelope with module key
627 ($msg, $msg_hash) = &check_key_and_xml_validity($input, $host_key, $session_id);
629 if( (!$msg) || (!$msg_hash) ) {
630 &daemon_log("$session_id DEGUG: input_from_known_client: deciphering raise error", 7);
631 &daemon_log("$@", 8);
632 next;
633 }
634 else {
635 $module = "SIPackages";
636 last;
637 }
638 }
640 if( (!$msg) || (!$msg_hash) || (!$module) ) {
641 &daemon_log("$session_id DEBUG: Incoming message is not from a known client", 7);
642 }
644 return ($msg, $msg_hash, $module);
645 }
648 sub input_from_unknown_host {
649 no strict "refs";
650 my ($input, $session_id) = @_ ;
651 my ($msg, $msg_hash, $module);
652 my $error_string;
654 my %act_modules = %$known_modules;
656 while( my ($mod, $info) = each(%act_modules)) {
658 # check a key exists for this module
659 my $module_key = ${$mod."_key"};
660 if( not defined $module_key ) {
661 if( $mod eq 'ArpHandler' ) {
662 next;
663 }
664 daemon_log("$session_id ERROR: no key specified in config file for $mod", 1);
665 next;
666 }
667 daemon_log("$session_id DEBUG: $mod: $module_key", 7);
669 # check if module can open msg envelope with module key
670 ($msg, $msg_hash) = &check_key_and_xml_validity($input, $module_key, $session_id);
671 if( (not defined $msg) || (not defined $msg_hash) ) {
672 next;
673 }
674 else {
675 $module = $mod;
676 last;
677 }
678 }
680 if( (!$msg) || (!$msg_hash) || (!$module)) {
681 daemon_log("$session_id DEBUG: Incoming message is not from an unknown host", 7);
682 }
684 return ($msg, $msg_hash, $module);
685 }
688 sub create_ciphering {
689 my ($passwd) = @_;
690 if((!defined($passwd)) || length($passwd)==0) {
691 $passwd = "";
692 }
693 $passwd = substr(md5_hex("$passwd") x 32, 0, 32);
694 my $iv = substr(md5_hex('GONICUS GmbH'),0, 16);
695 my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC());
696 $my_cipher->set_iv($iv);
697 return $my_cipher;
698 }
701 sub encrypt_msg {
702 my ($msg, $key) = @_;
703 my $my_cipher = &create_ciphering($key);
704 my $len;
705 {
706 use bytes;
707 $len= 16-length($msg)%16;
708 }
709 $msg = "\0"x($len).$msg;
710 $msg = $my_cipher->encrypt($msg);
711 chomp($msg = &encode_base64($msg));
712 # there are no newlines allowed inside msg
713 $msg=~ s/\n//g;
714 return $msg;
715 }
718 sub decrypt_msg {
720 my ($msg, $key) = @_ ;
721 $msg = &decode_base64($msg);
722 my $my_cipher = &create_ciphering($key);
723 $msg = $my_cipher->decrypt($msg);
724 $msg =~ s/\0*//g;
725 return $msg;
726 }
729 sub get_encrypt_key {
730 my ($target) = @_ ;
731 my $encrypt_key;
732 my $error = 0;
734 # target can be in known_server
735 if( not defined $encrypt_key ) {
736 my $sql_statement= "SELECT * FROM known_server WHERE hostname='$target'";
737 my $query_res = $known_server_db->select_dbentry( $sql_statement );
738 while( my ($hit_num, $hit) = each %{ $query_res } ) {
739 my $host_name = $hit->{hostname};
740 if( $host_name ne $target ) {
741 next;
742 }
743 $encrypt_key = $hit->{hostkey};
744 last;
745 }
746 }
748 # target can be in known_client
749 if( not defined $encrypt_key ) {
750 my $sql_statement= "SELECT * FROM known_clients WHERE hostname='$target'";
751 my $query_res = $known_clients_db->select_dbentry( $sql_statement );
752 while( my ($hit_num, $hit) = each %{ $query_res } ) {
753 my $host_name = $hit->{hostname};
754 if( $host_name ne $target ) {
755 next;
756 }
757 $encrypt_key = $hit->{hostkey};
758 last;
759 }
760 }
762 return $encrypt_key;
763 }
766 #=== FUNCTION ================================================================
767 # NAME: open_socket
768 # PARAMETERS: PeerAddr string something like 192.168.1.1 or 192.168.1.1:10000
769 # [PeerPort] string necessary if port not appended by PeerAddr
770 # RETURNS: socket IO::Socket::INET
771 # DESCRIPTION: open a socket to PeerAddr
772 #===============================================================================
773 sub open_socket {
774 my ($PeerAddr, $PeerPort) = @_ ;
775 if(defined($PeerPort)){
776 $PeerAddr = $PeerAddr.":".$PeerPort;
777 }
778 my $socket;
779 $socket = new IO::Socket::INET(PeerAddr => $PeerAddr,
780 Porto => "tcp",
781 Type => SOCK_STREAM,
782 Timeout => 5,
783 );
784 if(not defined $socket) {
785 return;
786 }
787 # &daemon_log("DEBUG: open_socket: $PeerAddr", 7);
788 return $socket;
789 }
792 #=== FUNCTION ================================================================
793 # NAME: get_ip
794 # PARAMETERS: interface name (i.e. eth0)
795 # RETURNS: (ip address)
796 # DESCRIPTION: Uses ioctl to get ip address directly from system.
797 #===============================================================================
798 sub get_ip {
799 my $ifreq= shift;
800 my $result= "";
801 my $SIOCGIFADDR= 0x8915; # man 2 ioctl_list
802 my $proto= getprotobyname('ip');
804 socket SOCKET, PF_INET, SOCK_DGRAM, $proto
805 or die "socket: $!";
807 if(ioctl SOCKET, $SIOCGIFADDR, $ifreq) {
808 my ($if, $sin) = unpack 'a16 a16', $ifreq;
809 my ($port, $addr) = sockaddr_in $sin;
810 my $ip = inet_ntoa $addr;
812 if ($ip && length($ip) > 0) {
813 $result = $ip;
814 }
815 }
817 return $result;
818 }
821 sub get_local_ip_for_remote_ip {
822 my $remote_ip= shift;
823 my $result="0.0.0.0";
825 if($remote_ip =~ /^(\d\d?\d?\.){3}\d\d?\d?$/) {
826 if($remote_ip eq "127.0.0.1") {
827 $result = "127.0.0.1";
828 } else {
829 my $PROC_NET_ROUTE= ('/proc/net/route');
831 open(PROC_NET_ROUTE, "<$PROC_NET_ROUTE")
832 or die "Could not open $PROC_NET_ROUTE";
834 my @ifs = <PROC_NET_ROUTE>;
836 close(PROC_NET_ROUTE);
838 # Eat header line
839 shift @ifs;
840 chomp @ifs;
841 foreach my $line(@ifs) {
842 my ($Iface,$Destination,$Gateway,$Flags,$RefCnt,$Use,$Metric,$Mask,$MTU,$Window,$IRTT)=split(/\s/, $line);
843 my $destination;
844 my $mask;
845 my ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Destination);
846 $destination= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d));
847 ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Mask);
848 $mask= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d));
849 if(new NetAddr::IP($remote_ip)->within(new NetAddr::IP($destination, $mask))) {
850 # destination matches route, save mac and exit
851 $result= &get_ip($Iface);
852 last;
853 }
854 }
855 }
856 } else {
857 daemon_log("get_local_ip_for_remote_ip was called with a non-ip parameter: $remote_ip", 1);
858 }
859 return $result;
860 }
863 sub send_msg_to_target {
864 my ($msg, $address, $encrypt_key, $msg_header, $session_id) = @_ ;
865 my $error = 0;
866 my $header;
867 my $new_status;
868 my $act_status;
869 my ($sql_statement, $res);
871 if( $msg_header ) {
872 $header = "'$msg_header'-";
873 } else {
874 $header = "";
875 }
877 # Patch the source ip
878 if($msg =~ /<source>0\.0\.0\.0:\d*?<\/source>/) {
879 my $remote_ip = &get_local_ip_for_remote_ip(sprintf("%s", $address =~ /^([0-9\.]*?):.*$/));
880 $msg =~ s/<source>(0\.0\.0\.0):(\d*?)<\/source>/<source>$remote_ip:$2<\/source>/s;
881 }
883 # encrypt xml msg
884 my $crypted_msg = &encrypt_msg($msg, $encrypt_key);
886 # opensocket
887 my $socket = &open_socket($address);
888 if( !$socket ) {
889 daemon_log("$session_id ERROR: cannot send ".$header."msg to $address , host not reachable", 1);
890 $error++;
891 }
893 if( $error == 0 ) {
894 # send xml msg
895 print $socket $crypted_msg."\n";
897 daemon_log("$session_id INFO: send ".$header."msg to $address", 5);
898 #daemon_log("DEBUG: message:\n$msg", 9);
900 }
902 # close socket in any case
903 if( $socket ) {
904 close $socket;
905 }
907 if( $error > 0 ) { $new_status = "down"; }
908 else { $new_status = $msg_header; }
911 # known_clients
912 $sql_statement = "SELECT * FROM known_clients WHERE hostname='$address'";
913 $res = $known_clients_db->select_dbentry($sql_statement);
914 if( keys(%$res) > 0) {
915 $act_status = $res->{1}->{'status'};
916 if( $act_status eq "down" ) {
917 $sql_statement = "DELETE FROM known_clients WHERE hostname='$address'";
918 $res = $known_clients_db->del_dbentry($sql_statement);
919 daemon_log("$session_id WARNING: failed 2x to send msg to host '$address', delete host from known_clients", 3);
920 } else {
921 $sql_statement = "UPDATE known_clients SET status='$new_status' WHERE hostname='$address'";
922 $res = $known_clients_db->update_dbentry($sql_statement);
923 if($new_status eq "down"){
924 daemon_log("$session_id WARNING: set '$address' from status '$act_status' to '$new_status'", 3);
925 } else {
926 daemon_log("$session_id INFO: set '$address' from status '$act_status' to '$new_status'", 5);
927 }
928 }
929 }
931 # known_server
932 $sql_statement = "SELECT * FROM known_server WHERE hostname='$address'";
933 $res = $known_server_db->select_dbentry($sql_statement);
934 if( keys(%$res) > 0 ) {
935 $act_status = $res->{1}->{'status'};
936 if( $act_status eq "down" ) {
937 $sql_statement = "DELETE FROM known_server WHERE hostname='$address'";
938 $res = $known_server_db->del_dbentry($sql_statement);
939 daemon_log("$session_id WARNING: failed 2x to a send msg to host '$address', delete host from known_server", 3);
940 }
941 else {
942 $sql_statement = "UPDATE known_server SET status='$new_status' WHERE hostname='$address'";
943 $res = $known_server_db->update_dbentry($sql_statement);
944 if($new_status eq "down"){
945 daemon_log("$session_id WARNING: set '$address' from status '$act_status' to '$new_status'", 3);
946 }
947 else {
948 daemon_log("$session_id INFO: set '$address' from status '$act_status' to '$new_status'", 5);
949 }
950 }
951 }
952 return $error;
953 }
956 sub update_jobdb_status_for_send_msgs {
957 my ($answer, $error) = @_;
958 if( $answer =~ /<jobdb_id>(\d+)<\/jobdb_id>/ ) {
959 my $jobdb_id = $1;
961 # sending msg faild
962 if( $error ) {
963 if (not $answer =~ /<header>trigger_action_reinstall<\/header>/) {
964 my $sql_statement = "UPDATE $job_queue_tn ".
965 "SET status='error', result='can not deliver msg, please consult log file' ".
966 "WHERE id=$jobdb_id";
967 my $res = $job_db->update_dbentry($sql_statement);
968 }
970 # sending msg was successful
971 } else {
972 my $sql_statement = "UPDATE $job_queue_tn ".
973 "SET status='done' ".
974 "WHERE id=$jobdb_id AND status='processed'";
975 my $res = $job_db->update_dbentry($sql_statement);
976 }
977 }
978 }
980 sub _start {
981 my ($kernel) = $_[KERNEL];
982 &trigger_db_loop($kernel);
983 $global_kernel = $kernel;
984 $kernel->yield('create_fai_server_db', $fai_server_tn );
985 $kernel->yield('create_fai_release_db', $fai_release_tn );
986 $kernel->sig(USR1 => "sig_handler");
987 $kernel->sig(USR2 => "create_packages_list_db");
988 }
990 sub sig_handler {
991 my ($kernel, $signal) = @_[KERNEL, ARG0] ;
992 daemon_log("0 INFO got signal '$signal'", 1);
993 $kernel->sig_handled();
994 return;
995 }
997 sub next_task {
998 my ($session, $heap) = @_[SESSION, HEAP];
1000 while ( keys( %{ $heap->{task} } ) < $max_children ) {
1001 my $next_task = shift @tasks;
1002 last unless defined $next_task;
1004 my $task = POE::Wheel::Run->new(
1005 Program => sub { process_task($session, $heap, $next_task) },
1006 StdioFilter => POE::Filter::Reference->new(),
1007 StdoutEvent => "task_result",
1008 StderrEvent => "task_debug",
1009 CloseEvent => "task_done",
1010 );
1012 $heap->{task}->{ $task->ID } = $task;
1013 }
1014 }
1016 sub handle_task_result {
1017 my ($kernel, $heap, $result) = @_[KERNEL, HEAP, ARG0];
1018 my $client_answer = $result->{'answer'};
1019 if( $client_answer =~ s/session_id=(\d+)$// ) {
1020 my $session_id = $1;
1021 if( defined $session_id ) {
1022 my $session_reference = $kernel->ID_id_to_session($session_id);
1023 if( defined $session_reference ) {
1024 $heap = $session_reference->get_heap();
1025 }
1026 }
1028 if(exists $heap->{'client'}) {
1029 $heap->{'client'}->put($client_answer);
1030 }
1031 }
1032 $kernel->sig(CHLD => "child_reap");
1033 }
1035 sub handle_task_debug {
1036 my $result = $_[ARG0];
1037 print STDERR "$result\n";
1038 }
1040 sub handle_task_done {
1041 my ( $kernel, $heap, $task_id ) = @_[ KERNEL, HEAP, ARG0 ];
1042 delete $heap->{task}->{$task_id};
1043 $kernel->yield("next_task");
1044 }
1046 sub process_task {
1047 no strict "refs";
1048 my ($session, $heap, $input) = @_;
1049 my $session_id = $session->ID;
1050 my ($msg, $msg_hash, $module);
1051 my $error = 0;
1052 my $answer_l;
1053 my ($answer_header, @answer_target_l, $answer_source);
1054 my $client_answer = "";
1056 daemon_log("", 5);
1057 daemon_log("$session_id INFO: Incoming msg with session ID $session_id from '".$heap->{'remote_ip'}."'", 5);
1058 #daemon_log("$session_id DEBUG: Incoming msg:\n$input", 9);
1060 ####################
1061 # check incoming msg
1062 # msg is from a new client or gosa
1063 ($msg, $msg_hash, $module) = &input_from_unknown_host($input, $session_id);
1064 # msg is from a gosa-si-server or gosa-si-bus
1065 if(( !$msg ) || ( !$msg_hash ) || ( !$module )){
1066 ($msg, $msg_hash, $module) = &input_from_known_server($input, $heap->{'remote_ip'}, $session_id);
1067 }
1068 # msg is from a gosa-si-client
1069 if(( !$msg ) || ( !$msg_hash ) || ( !$module )){
1070 ($msg, $msg_hash, $module) = &input_from_known_client($input, $heap->{'remote_ip'}, $session_id);
1071 }
1072 # an error occurred
1073 if(( !$msg ) || ( !$msg_hash ) || ( !$module )){
1074 # if an incoming msg could not be decrypted (maybe a wrong key), send client a ping. If the client
1075 # could not understand a msg from its server the client cause a re-registering process
1076 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);
1077 my $sql_statement = "SELECT * FROM $main::known_clients_tn WHERE (hostname LIKE '".$heap->{'remote_ip'}."%')";
1078 my $query_res = $known_clients_db->select_dbentry( $sql_statement );
1079 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1080 my $host_name = $hit->{'hostname'};
1081 my $host_key = $hit->{'hostkey'};
1082 my $ping_msg = "<xml> <header>gosa_ping</header> <source>$server_address</source> <target>$host_name</target></xml>";
1083 my $error = &send_msg_to_target($ping_msg, $host_name, $host_key, "gosa_ping", $session_id);
1084 &update_jobdb_status_for_send_msgs($ping_msg, $error);
1085 }
1086 $error++;
1087 }
1089 ######################
1090 # process incoming msg
1091 if( $error == 0) {
1092 daemon_log("$session_id INFO: Incoming msg with header '".@{$msg_hash->{'header'}}[0].
1093 "' from '".$heap->{'remote_ip'}."'", 5);
1094 daemon_log("$session_id DEBUG: Processing module ".$module, 7);
1095 $answer_l = &{ $module."::process_incoming_msg" }($msg, $msg_hash, $session_id);
1097 if ( 0 < @{$answer_l} ) {
1098 my $answer_str = join("\n", @{$answer_l});
1099 daemon_log("$session_id DEBUG: $module: Got answer from module: \n".$answer_str,8);
1100 } else {
1101 daemon_log("$session_id DEBUG: $module: Got no answer from module!" ,8);
1102 }
1104 }
1105 if( !$answer_l ) { $error++ };
1107 ########
1108 # answer
1109 if( $error == 0 ) {
1111 foreach my $answer ( @{$answer_l} ) {
1112 # for each answer in answer list
1114 # check outgoing msg to xml validity
1115 my $answer_hash = &check_outgoing_xml_validity($answer);
1116 if( not defined $answer_hash ) {
1117 next;
1118 }
1120 $answer_header = @{$answer_hash->{'header'}}[0];
1121 @answer_target_l = @{$answer_hash->{'target'}};
1122 $answer_source = @{$answer_hash->{'source'}}[0];
1124 # deliver msg to all targets
1125 foreach my $answer_target ( @answer_target_l ) {
1127 # targets of msg are all gosa-si-clients in known_clients_db
1128 if( $answer_target eq "*" ) {
1129 # answer is for all clients
1130 my $sql_statement= "SELECT * FROM known_clients";
1131 my $query_res = $known_clients_db->select_dbentry( $sql_statement );
1132 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1133 my $host_name = $hit->{hostname};
1134 my $host_key = $hit->{hostkey};
1135 my $error = &send_msg_to_target($answer, $host_name, $host_key, $answer_header, $session_id);
1136 &update_jobdb_status_for_send_msgs($answer, $error);
1137 }
1138 }
1140 # targets of msg are all gosa-si-server in known_server_db
1141 elsif( $answer_target eq "KNOWN_SERVER" ) {
1142 # answer is for all server in known_server
1143 my $sql_statement= "SELECT * FROM known_server";
1144 my $query_res = $known_server_db->select_dbentry( $sql_statement );
1145 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1146 my $host_name = $hit->{hostname};
1147 my $host_key = $hit->{hostkey};
1148 $answer =~ s/KNOWN_SERVER/$host_name/g;
1149 my $error = &send_msg_to_target($answer, $host_name, $host_key, $answer_header, $session_id);
1150 &update_jobdb_status_for_send_msgs($answer, $error);
1151 }
1152 }
1154 # target of msg is GOsa
1155 elsif( $answer_target eq "GOSA" ) {
1156 my $session_id = ($1) if $answer =~ /<session_id>(\d+?)<\/session_id>/;
1157 my $add_on = "";
1158 if( defined $session_id ) {
1159 $add_on = ".session_id=$session_id";
1160 }
1161 # answer is for GOSA and has to returned to connected client
1162 my $gosa_answer = &encrypt_msg($answer, $GosaPackages_key);
1163 $client_answer = $gosa_answer.$add_on;
1164 }
1166 # target of msg is job queue at this host
1167 elsif( $answer_target eq "JOBDB") {
1168 $answer =~ /<header>(\S+)<\/header>/;
1169 my $header;
1170 if( defined $1 ) { $header = $1; }
1171 my $error = &send_msg_to_target($answer, $server_address, $GosaPackages_key, $header, $session_id);
1172 &update_jobdb_status_for_send_msgs($answer, $error);
1173 }
1175 # target of msg is a mac address
1176 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 ) {
1177 daemon_log("$session_id INFO: target is mac address '$answer_target', looking for host in known_clients", 5);
1178 my $sql_statement = "SELECT * FROM known_clients WHERE macaddress LIKE '$answer_target'";
1179 my $query_res = $known_clients_db->select_dbentry( $sql_statement );
1180 my $found_ip_flag = 0;
1181 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1182 my $host_name = $hit->{hostname};
1183 my $host_key = $hit->{hostkey};
1184 $answer =~ s/$answer_target/$host_name/g;
1185 daemon_log("$session_id INFO: found host '$host_name', associated to '$answer_target'", 5);
1186 my $error = &send_msg_to_target($answer, $host_name, $host_key, $answer_header, $session_id);
1187 &update_jobdb_status_for_send_msgs($answer, $error);
1188 $found_ip_flag++ ;
1189 }
1190 if( $found_ip_flag == 0) {
1191 daemon_log("$session_id WARNING: no host found in known_clients with mac address '$answer_target'", 3);
1192 if( $bus_activ eq "true" ) {
1193 daemon_log("$session_id INFO: try to forward msg '$answer_header' to bus '$bus_address'", 5);
1194 my $sql_statement = "SELECT * FROM known_server WHERE hostname='$bus_address'";
1195 my $query_res = $known_server_db->select_dbentry( $sql_statement );
1196 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1197 my $bus_address = $hit->{hostname};
1198 my $bus_key = $hit->{hostkey};
1199 my $error = &send_msg_to_target($answer, $bus_address, $bus_key, $answer_header, $session_id);
1200 &update_jobdb_status_for_send_msgs($answer, $error);
1201 last;
1202 }
1203 }
1205 }
1207 # answer is for one specific host
1208 } else {
1209 # get encrypt_key
1210 my $encrypt_key = &get_encrypt_key($answer_target);
1211 if( not defined $encrypt_key ) {
1212 # unknown target, forward msg to bus
1213 daemon_log("$session_id WARNING: unknown target '$answer_target'", 3);
1214 if( $bus_activ eq "true" ) {
1215 daemon_log("$session_id INFO: try to forward msg '$answer_header' to bus '$bus_address'", 5);
1216 my $sql_statement = "SELECT * FROM known_server WHERE hostname='$bus_address'";
1217 my $query_res = $known_server_db->select_dbentry( $sql_statement );
1218 my $res_length = keys( %{$query_res} );
1219 if( $res_length == 0 ){
1220 daemon_log("$session_id WARNING: send '$answer_header' to '$bus_address' failed, ".
1221 "no bus found in known_server", 3);
1222 }
1223 else {
1224 while( my ($hit_num, $hit) = each %{ $query_res } ) {
1225 my $bus_key = $hit->{hostkey};
1226 my $error = &send_msg_to_target($answer, $bus_address, $bus_key, $answer_header,$session_id );
1227 &update_jobdb_status_for_send_msgs($answer, $error);
1228 }
1229 }
1230 }
1231 next;
1232 }
1233 my $error = &send_msg_to_target($answer, $answer_target, $encrypt_key, $answer_header,$session_id);
1234 &update_jobdb_status_for_send_msgs($answer, $error);
1235 }
1236 }
1237 }
1238 }
1240 my $filter = POE::Filter::Reference->new();
1241 my %result = (
1242 status => "seems ok to me",
1243 answer => $client_answer,
1244 );
1246 my $output = $filter->put( [ \%result ] );
1247 print @$output;
1250 }
1253 sub trigger_db_loop {
1254 my ($kernel) = @_ ;
1255 $kernel->delay_set('watch_for_new_jobs', $job_queue_loop_delay);
1256 $kernel->delay_set('watch_for_done_jobs', $job_queue_loop_delay);
1257 $kernel->delay_set('watch_for_new_messages', $messaging_db_loop_delay);
1258 $kernel->delay_set('watch_for_delivery_messages', $messaging_db_loop_delay);
1259 $kernel->delay_set('watch_for_done_messages', $messaging_db_loop_delay);
1260 }
1263 sub watch_for_done_jobs {
1264 my ($kernel,$heap) = @_[KERNEL, HEAP];
1266 my $sql_statement = "SELECT * FROM ".$job_queue_tn.
1267 " WHERE status='done'";
1268 my $res = $job_db->select_dbentry( $sql_statement );
1270 while( my ($id, $hit) = each %{$res} ) {
1271 my $jobdb_id = $hit->{id};
1272 my $sql_statement = "DELETE FROM $job_queue_tn WHERE id=$jobdb_id";
1273 my $res = $job_db->del_dbentry($sql_statement);
1274 }
1276 $kernel->delay_set('watch_for_done_jobs',$job_queue_loop_delay);
1277 }
1280 sub watch_for_new_jobs {
1281 if($watch_for_new_jobs_in_progress == 0) {
1282 $watch_for_new_jobs_in_progress = 1;
1283 my ($kernel,$heap) = @_[KERNEL, HEAP];
1285 # check gosa job queue for jobs with executable timestamp
1286 my $timestamp = &get_time();
1287 my $sql_statement = "SELECT * FROM $job_queue_tn WHERE status='waiting' AND (CAST (timestamp AS INTEGER)) < $timestamp ORDER BY timestamp";
1288 my $res = $job_db->exec_statement( $sql_statement );
1290 # Merge all new jobs that would do the same actions
1291 my @drops;
1292 my $hits;
1293 foreach my $hit (reverse @{$res} ) {
1294 my $macaddress= lc @{$hit}[8];
1295 my $headertag= @{$hit}[5];
1296 if(
1297 defined($hits->{$macaddress}) &&
1298 defined($hits->{$macaddress}->{$headertag}) &&
1299 defined($hits->{$macaddress}->{$headertag}[0])
1300 ) {
1301 push @drops, "DELETE FROM $job_queue_tn WHERE id = $hits->{$macaddress}->{$headertag}[0]";
1302 }
1303 $hits->{$macaddress}->{$headertag}= $hit;
1304 }
1306 # Delete new jobs with a matching job in state 'processing'
1307 foreach my $macaddress (keys %{$hits}) {
1308 foreach my $jobdb_headertag (keys %{$hits->{$macaddress}}) {
1309 my $jobdb_id = @{$hits->{$macaddress}->{$jobdb_headertag}}[0];
1310 if(defined($jobdb_id)) {
1311 my $sql_statement = "SELECT * FROM $job_queue_tn WHERE macaddress LIKE '$macaddress' AND headertag='$jobdb_headertag' AND status='processing'";
1312 my $res = $job_db->exec_statement( $sql_statement );
1313 foreach my $hit (@{$res}) {
1314 push @drops, "DELETE FROM $job_queue_tn WHERE id=$jobdb_id";
1315 }
1316 } else {
1317 daemon_log("J ERROR: Job without id exists for macaddress $macaddress!", 1);
1318 }
1319 }
1320 }
1322 # Commit deletion
1323 $job_db->exec_statementlist(\@drops);
1325 # Look for new jobs that could be executed
1326 foreach my $macaddress (keys %{$hits}) {
1328 # Look if there is an executing job
1329 my $sql_statement = "SELECT * FROM $job_queue_tn WHERE macaddress LIKE '$macaddress' AND status='processing'";
1330 my $res = $job_db->exec_statement( $sql_statement );
1332 # Skip new jobs for host if there is a processing job
1333 if(defined($res) and defined @{$res}[0]) {
1334 next;
1335 }
1337 foreach my $jobdb_headertag (keys %{$hits->{$macaddress}}) {
1338 my $jobdb_id = @{$hits->{$macaddress}->{$jobdb_headertag}}[0];
1339 if(defined($jobdb_id)) {
1340 my $job_msg = @{$hits->{$macaddress}->{$jobdb_headertag}}[7];
1342 daemon_log("J DEBUG: its time to execute $job_msg", 7);
1343 my $sql_statement = "SELECT * FROM known_clients WHERE macaddress LIKE '$macaddress'";
1344 my $res_hash = $known_clients_db->select_dbentry( $sql_statement );
1346 # expect macaddress is unique!!!!!!
1347 my $target = $res_hash->{1}->{hostname};
1349 # change header
1350 $job_msg =~ s/<header>job_/<header>gosa_/;
1352 # add sqlite_id
1353 $job_msg =~ s/<\/xml>$/<jobdb_id>$jobdb_id<\/jobdb_id><\/xml>/;
1355 $job_msg =~ /<header>(\S+)<\/header>/;
1356 my $header = $1 ;
1357 my $func_error = &send_msg_to_target($job_msg, $server_address, $GosaPackages_key, $header, "J");
1359 # update status in job queue to 'processing'
1360 $sql_statement = "UPDATE $job_queue_tn SET status='processing' WHERE id=$jobdb_id";
1361 my $res = $job_db->update_dbentry($sql_statement);
1362 # TODO: abfangen ob alles in ordnung ist oder nicht, wenn nicht error schmeißen
1364 # We don't want parallel processing
1365 last;
1366 }
1367 }
1368 }
1370 $watch_for_new_jobs_in_progress = 0;
1371 $kernel->delay_set('watch_for_new_jobs', $job_queue_loop_delay);
1372 }
1373 }
1376 sub watch_for_new_messages {
1377 my ($kernel,$heap) = @_[KERNEL, HEAP];
1378 my @coll_user_msg; # collection list of outgoing messages
1380 # check messaging_db for new incoming messages with executable timestamp
1381 my $timestamp = &get_time();
1382 my $sql_statement = "SELECT * FROM $messaging_tn WHERE ( (CAST(timestamp AS INTEGER))<$timestamp AND flag='n' AND direction='in' )";
1383 my $res = $messaging_db->exec_statement( $sql_statement );
1384 foreach my $hit (@{$res}) {
1386 # create outgoing messages
1387 my $message_to = @{$hit}[3];
1388 # translate message_to to plain login name
1389 my @message_to_l = split(/,/, $message_to);
1390 my %receiver_h;
1391 foreach my $receiver (@message_to_l) {
1392 if ($receiver =~ /^u_([\s\S]*)$/) {
1393 $receiver_h{$1} = 0;
1394 } elsif ($receiver =~ /^g_([\s\S]*)$/) {
1395 # TODO implement receiver translation
1396 } else {
1397 my $sbjct = &encode_base64(@{$hit}[1]);
1398 my $msg = &encode_base64(@{$hit}[7]);
1399 &daemon_log("M WARNING: unknown receiver '$receiver' for a user-message 'sbjct - msg'", 3);
1400 }
1401 }
1402 my @receiver_l = keys(%receiver_h);
1404 my $message_id = @{$hit}[0];
1406 #add each outgoing msg to messaging_db
1407 my $receiver;
1408 foreach $receiver (@receiver_l) {
1409 my $sql_statement = "INSERT INTO $messaging_tn (id, subject, message_from, message_to, flag, direction, delivery_time, message, timestamp) ".
1410 "VALUES ('".
1411 $message_id."', '". # id
1412 @{$hit}[1]."', '". # subject
1413 @{$hit}[2]."', '". # message_from
1414 $receiver."', '". # message_to
1415 "none"."', '". # flag
1416 "out"."', '". # direction
1417 @{$hit}[6]."', '". # delivery_time
1418 @{$hit}[7]."', '". # message
1419 $timestamp."'". # timestamp
1420 ")";
1421 &daemon_log("M DEBUG: $sql_statement", 1);
1422 my $res = $messaging_db->exec_statement($sql_statement);
1423 &daemon_log("M INFO: message '".@{$hit}[0]."' is prepared for delivery to receiver '$receiver'", 5);
1424 }
1426 # set incoming message to flag d=deliverd
1427 $sql_statement = "UPDATE $messaging_tn SET flag='p' WHERE id='$message_id'";
1428 &daemon_log("M DEBUG: $sql_statement", 7);
1429 $res = $messaging_db->update_dbentry($sql_statement);
1430 &daemon_log("M INFO: message '$message_id' is set to flag 'p' (processed)", 5);
1431 }
1433 $kernel->delay_set('watch_for_new_messages', $messaging_db_loop_delay);
1434 return;
1435 }
1437 sub watch_for_delivery_messages {
1438 my ($kernel, $heap) = @_[KERNEL, HEAP];
1440 # select outgoing messages
1441 my $sql_statement = "SELECT * FROM $messaging_tn WHERE ( flag='p' AND direction='out' )";
1442 #&daemon_log("0 DEBUG: $sql", 7);
1443 my $res = $messaging_db->exec_statement( $sql_statement );
1445 # build out msg for each usr
1446 foreach my $hit (@{$res}) {
1447 my $receiver = @{$hit}[3];
1448 my $msg_id = @{$hit}[0];
1449 my $subject = @{$hit}[1];
1450 my $message = @{$hit}[7];
1452 # resolve usr -> host where usr is logged in
1453 my $sql = "SELECT * FROM $login_users_tn WHERE (user='$receiver')";
1454 #&daemon_log("0 DEBUG: $sql", 7);
1455 my $res = $login_users_db->exec_statement($sql);
1457 # reciver is logged in nowhere
1458 if (not ref(@$res[0]) eq "ARRAY") { next; }
1460 my $send_succeed = 0;
1461 foreach my $hit (@$res) {
1462 my $receiver_host = @$hit[0];
1463 &daemon_log("M DEBUG: user '$receiver' is logged in at host '$receiver_host'", 7);
1465 # fetch key to encrypt msg propperly for usr/host
1466 my $sql = "SELECT * FROM $known_clients_tn WHERE (hostname='$receiver_host')";
1467 &daemon_log("0 DEBUG: $sql", 7);
1468 my $res = $known_clients_db->exec_statement($sql);
1470 # host is already down
1471 if (not ref(@$res[0]) eq "ARRAY") { next; }
1473 # host is on
1474 my $receiver_key = @{@{$res}[0]}[2];
1475 my %data = ('subject' => $subject, 'message' => $message, 'usr' => $receiver);
1476 my $out_msg = &build_msg("usr_msg", $server_address, $receiver_host, \%data );
1477 my $error = &send_msg_to_target($out_msg, $receiver_host, $receiver_key, "usr_msg", 0);
1478 if ($error == 0 ) {
1479 $send_succeed++ ;
1480 }
1481 }
1483 if ($send_succeed) {
1484 # set outgoing msg at db to deliverd
1485 my $sql = "UPDATE $messaging_tn SET flag='d' WHERE (id='$msg_id' AND direction='out' AND message_to='$receiver')";
1486 &daemon_log("0 DEBUG: $sql", 7);
1487 my $res = $messaging_db->exec_statement($sql);
1488 }
1489 }
1491 $kernel->delay_set('watch_for_delivery_messages', $messaging_db_loop_delay);
1492 return;
1493 }
1496 sub watch_for_done_messages {
1497 my ($kernel,$heap) = @_[KERNEL, HEAP];
1499 my $sql = "SELECT * FROM $messaging_tn WHERE (flag='p' AND direction='in')";
1500 #&daemon_log("0 DEBUG: $sql", 7);
1501 my $res = $messaging_db->exec_statement($sql);
1503 foreach my $hit (@{$res}) {
1504 my $msg_id = @{$hit}[0];
1506 my $sql = "SELECT * FROM $messaging_tn WHERE (id='$msg_id' AND direction='out' AND (NOT flag='s'))";
1507 #&daemon_log("0 DEBUG: $sql", 7);
1508 my $res = $messaging_db->exec_statement($sql);
1510 # not all usr msgs have been seen till now
1511 if ( ref(@$res[0]) eq "ARRAY") { next; }
1513 $sql = "DELETE FROM $messaging_tn WHERE (id='$msg_id')";
1514 #&daemon_log("0 DEBUG: $sql", 7);
1515 $res = $messaging_db->exec_statement($sql);
1517 }
1519 $kernel->delay_set('watch_for_done_messages', $messaging_db_loop_delay);
1520 return;
1521 }
1524 sub get_ldap_handle {
1525 my ($session_id) = @_;
1526 my $heap;
1527 my $ldap_handle;
1529 if (not defined $session_id ) { $session_id = 0 };
1530 if ($session_id =~ /[^0-9]*/) { $session_id = 0 };
1532 if ($session_id == 0) {
1533 daemon_log("$session_id DEBUG: get_ldap_handle invoked without a session_id, create a new ldap_handle", 7);
1534 $ldap_handle = Net::LDAP->new( $ldap_uri );
1535 $ldap_handle->bind($ldap_admin_dn, password => $ldap_admin_password);
1537 } else {
1538 my $session_reference = $global_kernel->ID_id_to_session($session_id);
1539 if( defined $session_reference ) {
1540 $heap = $session_reference->get_heap();
1541 }
1543 if (not defined $heap) {
1544 daemon_log("$session_id DEBUG: cannot get heap for session_id '$session_id'", 7);
1545 return;
1546 }
1548 # TODO: This "if" is nonsense, because it doesn't prove that the
1549 # used handle is still valid - or if we've to reconnect...
1550 #if (not exists $heap->{ldap_handle}) {
1551 $ldap_handle = Net::LDAP->new( $ldap_uri );
1552 $ldap_handle->bind($ldap_admin_dn, password => $ldap_admin_password);
1553 $heap->{ldap_handle} = $ldap_handle;
1554 #}
1555 }
1556 return $ldap_handle;
1557 }
1560 sub change_fai_state {
1561 my ($st, $targets, $session_id) = @_;
1562 $session_id = 0 if not defined $session_id;
1563 # Set FAI state to localboot
1564 my %mapActions= (
1565 reboot => '',
1566 update => 'softupdate',
1567 localboot => 'localboot',
1568 reinstall => 'install',
1569 rescan => '',
1570 wake => '',
1571 memcheck => 'memcheck',
1572 sysinfo => 'sysinfo',
1573 install => 'install',
1574 );
1576 # Return if this is unknown
1577 if (!exists $mapActions{ $st }){
1578 daemon_log("$session_id ERROR: unknown action '$st', can not translate ot FAIstate", 1);
1579 return;
1580 }
1582 my $state= $mapActions{ $st };
1584 my $ldap_handle = &get_ldap_handle($session_id);
1585 if( defined($ldap_handle) ) {
1587 # Build search filter for hosts
1588 my $search= "(&(objectClass=GOhard)";
1589 foreach (@{$targets}){
1590 $search.= "(macAddress=$_)";
1591 }
1592 $search.= ")";
1594 # If there's any host inside of the search string, procress them
1595 if (!($search =~ /macAddress/)){
1596 daemon_log("$session_id ERROR: no macAddress found in filter statement for LDAP search: '$search'", 1);
1597 return;
1598 }
1600 # Perform search for Unit Tag
1601 my $mesg = $ldap_handle->search(
1602 base => $ldap_base,
1603 scope => 'sub',
1604 attrs => ['dn', 'FAIstate', 'objectClass'],
1605 filter => "$search"
1606 );
1608 if ($mesg->count) {
1609 my @entries = $mesg->entries;
1610 foreach my $entry (@entries) {
1611 # Only modify entry if it is not set to '$state'
1612 if ($entry->get_value("FAIstate") ne "$state"){
1613 daemon_log("$session_id INFO: Setting FAIstate to '$state' for ".$entry->dn, 5);
1614 my $result;
1615 my %tmp = map { $_ => 1 } $entry->get_value("objectClass");
1616 if (exists $tmp{'FAIobject'}){
1617 if ($state eq ''){
1618 $result= $ldap_handle->modify($entry->dn, changes => [
1619 delete => [ FAIstate => [] ] ]);
1620 } else {
1621 $result= $ldap_handle->modify($entry->dn, changes => [
1622 replace => [ FAIstate => $state ] ]);
1623 }
1624 } elsif ($state ne ''){
1625 $result= $ldap_handle->modify($entry->dn, changes => [
1626 add => [ objectClass => 'FAIobject' ],
1627 add => [ FAIstate => $state ] ]);
1628 }
1630 # Errors?
1631 if ($result->code){
1632 daemon_log("$session_id Error: Setting FAIstate to '$state' for ".$entry->dn. "failed: ".$result->error, 1);
1633 }
1634 } else {
1635 daemon_log("$session_id DEBUG FAIstate at host '".$entry->dn."' already at state '$st'", 7);
1636 }
1637 }
1638 }
1639 # if no ldap handle defined
1640 } else {
1641 daemon_log("$session_id ERROR: no LDAP handle defined for update FAIstate", 1);
1642 }
1644 }
1647 sub change_goto_state {
1648 my ($st, $targets, $session_id) = @_;
1649 $session_id = 0 if not defined $session_id;
1651 # Switch on or off?
1652 my $state= $st eq 'active' ? 'active': 'locked';
1654 my $ldap_handle = &get_ldap_handle($session_id);
1655 if( defined($ldap_handle) ) {
1657 # Build search filter for hosts
1658 my $search= "(&(objectClass=GOhard)";
1659 foreach (@{$targets}){
1660 $search.= "(macAddress=$_)";
1661 }
1662 $search.= ")";
1664 # If there's any host inside of the search string, procress them
1665 if (!($search =~ /macAddress/)){
1666 return;
1667 }
1669 # Perform search for Unit Tag
1670 my $mesg = $ldap_handle->search(
1671 base => $ldap_base,
1672 scope => 'sub',
1673 attrs => ['dn', 'gotoMode'],
1674 filter => "$search"
1675 );
1677 if ($mesg->count) {
1678 my @entries = $mesg->entries;
1679 foreach my $entry (@entries) {
1681 # Only modify entry if it is not set to '$state'
1682 if ($entry->get_value("gotoMode") ne $state){
1684 daemon_log("$session_id INFO: Setting gotoMode to '$state' for ".$entry->dn, 5);
1685 my $result;
1686 $result= $ldap_handle->modify($entry->dn, changes => [
1687 replace => [ gotoMode => $state ] ]);
1689 # Errors?
1690 if ($result->code){
1691 &daemon_log("$session_id Error: Setting gotoMode to '$state' for ".$entry->dn. "failed: ".$result->error, 1);
1692 }
1694 }
1695 }
1696 }
1698 }
1699 }
1702 sub run_create_fai_server_db {
1703 my ($kernel, $session, $heap, $table_name) = @_[KERNEL, SESSION, HEAP, ARG0];
1704 my $session_id = $session->ID;
1705 my $task = POE::Wheel::Run->new(
1706 Program => sub { &create_fai_server_db($table_name,$kernel, undef, $session_id) },
1707 StdoutEvent => "session_run_result",
1708 StderrEvent => "session_run_debug",
1709 CloseEvent => "session_run_done",
1710 );
1712 $heap->{task}->{ $task->ID } = $task;
1713 return;
1714 }
1717 sub create_fai_server_db {
1718 my ($table_name, $kernel, $dont_create_packages_list, $session_id) = @_;
1719 my $result;
1721 if (not defined $session_id) { $session_id = 0; }
1722 my $ldap_handle = &get_ldap_handle();
1723 if(defined($ldap_handle)) {
1724 daemon_log("$session_id INFO: create_fai_server_db: start", 5);
1725 my $mesg= $ldap_handle->search(
1726 base => $ldap_base,
1727 scope => 'sub',
1728 attrs => ['FAIrepository', 'gosaUnitTag'],
1729 filter => "(&(FAIrepository=*)(objectClass=FAIrepositoryServer))",
1730 );
1731 if($mesg->{'resultCode'} == 0 &&
1732 $mesg->count != 0) {
1733 foreach my $entry (@{$mesg->{entries}}) {
1734 if($entry->exists('FAIrepository')) {
1735 # Add an entry for each Repository configured for server
1736 foreach my $repo(@{$entry->get_value('FAIrepository', asref => 1)}) {
1737 my($tmp_url,$tmp_server,$tmp_release,$tmp_sections) = split(/\|/, $repo);
1738 my $tmp_tag= $entry->get_value('gosaUnitTag') || "";
1739 $result= $fai_server_db->add_dbentry( {
1740 table => $table_name,
1741 primkey => ['server', 'release', 'tag'],
1742 server => $tmp_url,
1743 release => $tmp_release,
1744 sections => $tmp_sections,
1745 tag => (length($tmp_tag)>0)?$tmp_tag:"",
1746 } );
1747 }
1748 }
1749 }
1750 }
1751 daemon_log("$session_id INFO: create_fai_server_db: finished", 5);
1753 # TODO: Find a way to post the 'create_packages_list_db' event
1754 if(not defined($dont_create_packages_list)) {
1755 &create_packages_list_db(undef, undef, $session_id);
1756 }
1757 }
1759 $ldap_handle->disconnect;
1760 return $result;
1761 }
1764 sub run_create_fai_release_db {
1765 my ($session, $heap, $table_name) = @_[SESSION, HEAP, ARG0];
1766 my $session_id = $session->ID;
1767 my $task = POE::Wheel::Run->new(
1768 Program => sub { &create_fai_release_db($table_name, $session_id) },
1769 StdoutEvent => "session_run_result",
1770 StderrEvent => "session_run_debug",
1771 CloseEvent => "session_run_done",
1772 );
1774 $heap->{task}->{ $task->ID } = $task;
1775 return;
1776 }
1779 sub create_fai_release_db {
1780 my ($table_name, $session_id) = @_;
1781 my $result;
1783 # used for logging
1784 if (not defined $session_id) { $session_id = 0; }
1786 my $ldap_handle = &get_ldap_handle();
1787 if(defined($ldap_handle)) {
1788 daemon_log("$session_id INFO: create_fai_release_db: start",5);
1789 my $mesg= $ldap_handle->search(
1790 base => $ldap_base,
1791 scope => 'sub',
1792 attrs => [],
1793 filter => "(&(objectClass=organizationalUnit)(ou=fai))",
1794 );
1795 if($mesg->{'resultCode'} == 0 &&
1796 $mesg->count != 0) {
1797 # Walk through all possible FAI container ou's
1798 my @sql_list;
1799 my $timestamp= &get_time();
1800 foreach my $ou (@{$mesg->{entries}}) {
1801 my $tmp_classes= resolve_fai_classes($ou->dn, $ldap_handle, $session_id);
1802 if(defined($tmp_classes) && ref($tmp_classes) eq 'HASH') {
1803 my @tmp_array=get_fai_release_entries($tmp_classes);
1804 if(@tmp_array) {
1805 foreach my $entry (@tmp_array) {
1806 if(defined($entry) && ref($entry) eq 'HASH') {
1807 my $sql=
1808 "INSERT INTO $table_name "
1809 ."(timestamp, release, class, type, state) VALUES ("
1810 .$timestamp.","
1811 ."'".$entry->{'release'}."',"
1812 ."'".$entry->{'class'}."',"
1813 ."'".$entry->{'type'}."',"
1814 ."'".$entry->{'state'}."')";
1815 push @sql_list, $sql;
1816 }
1817 }
1818 }
1819 }
1820 }
1822 daemon_log("$session_id DEBUG: Inserting ".scalar @sql_list." entries to DB",8);
1823 if(@sql_list) {
1824 unshift @sql_list, "VACUUM";
1825 unshift @sql_list, "DELETE FROM $table_name";
1826 $fai_release_db->exec_statementlist(\@sql_list);
1827 }
1828 daemon_log("$session_id DEBUG: Done with inserting",7);
1829 }
1830 daemon_log("$session_id INFO: create_fai_release_db: finished",5);
1831 }
1832 $ldap_handle->disconnect;
1833 return $result;
1834 }
1836 sub get_fai_types {
1837 my $tmp_classes = shift || return undef;
1838 my @result;
1840 foreach my $type(keys %{$tmp_classes}) {
1841 if(defined($tmp_classes->{$type}[0]) && (!($tmp_classes->{$type}[0] =~ /^.*?removed.*?$/))) {
1842 my $entry = {
1843 type => $type,
1844 state => $tmp_classes->{$type}[0],
1845 };
1846 push @result, $entry;
1847 }
1848 }
1850 return @result;
1851 }
1853 sub get_fai_state {
1854 my $result = "";
1855 my $tmp_classes = shift || return $result;
1857 foreach my $type(keys %{$tmp_classes}) {
1858 if(defined($tmp_classes->{$type}[0])) {
1859 $result = $tmp_classes->{$type}[0];
1861 # State is equal for all types in class
1862 last;
1863 }
1864 }
1866 return $result;
1867 }
1869 sub resolve_fai_classes {
1870 my ($fai_base, $ldap_handle, $session_id) = @_;
1871 if (not defined $session_id) { $session_id = 0; }
1872 my $result;
1873 my @possible_fai_classes= ("FAIscript", "FAIhook", "FAIpartitionTable", "FAItemplate", "FAIvariable", "FAIprofile", "FAIpackageList");
1874 my $fai_filter= "(|(&(objectClass=FAIclass)(|(objectClass=".join(")(objectClass=", @possible_fai_classes).")))(objectClass=FAIbranch))";
1875 my $fai_classes;
1877 daemon_log("$session_id DEBUG: Searching for FAI entries in base $fai_base",7);
1878 my $mesg= $ldap_handle->search(
1879 base => $fai_base,
1880 scope => 'sub',
1881 attrs => ['cn','objectClass','FAIstate'],
1882 filter => $fai_filter,
1883 );
1884 daemon_log("$session_id DEBUG: Found ".$mesg->count()." FAI entries",7);
1886 if($mesg->{'resultCode'} == 0 &&
1887 $mesg->count != 0) {
1888 foreach my $entry (@{$mesg->{entries}}) {
1889 if($entry->exists('cn')) {
1890 my $tmp_dn= $entry->dn();
1892 # Skip classname and ou dn parts for class
1893 my $tmp_release = ($1) if $tmp_dn =~ /^[^,]+,[^,]+,(.*?),$fai_base$/;
1895 # Skip classes without releases
1896 if((!defined($tmp_release)) || length($tmp_release)==0) {
1897 next;
1898 }
1900 my $tmp_cn= $entry->get_value('cn');
1901 my $tmp_state= $entry->get_value('FAIstate');
1903 my $tmp_type;
1904 # Get FAI type
1905 for my $oclass(@{$entry->get_value('objectClass', asref => 1)}) {
1906 if(grep $_ eq $oclass, @possible_fai_classes) {
1907 $tmp_type= $oclass;
1908 last;
1909 }
1910 }
1912 if($tmp_release =~ /^.*?,.*?$/ && (!($tmp_release =~ /^.*?\\,.*?$/))) {
1913 # A Subrelease
1914 my @sub_releases = split(/,/, $tmp_release);
1916 # Walk through subreleases and build hash tree
1917 my $hash;
1918 while(my $tmp_sub_release = pop @sub_releases) {
1919 $hash .= "\{'$tmp_sub_release'\}->";
1920 }
1921 eval('push @{$fai_classes->'.$hash.'{$tmp_cn}->{$tmp_type}}, (defined($tmp_state) && length($tmp_state)>0)?$tmp_state:"";');
1922 } else {
1923 # A branch, no subrelease
1924 push @{$fai_classes->{$tmp_release}->{$tmp_cn}->{$tmp_type}}, (defined($tmp_state) && length($tmp_state)>0)?$tmp_state:"";
1925 }
1926 } elsif (!$entry->exists('cn')) {
1927 my $tmp_dn= $entry->dn();
1928 my $tmp_release = ($1) if $tmp_dn =~ /^(.*?),$fai_base$/;
1930 # Skip classes without releases
1931 if((!defined($tmp_release)) || length($tmp_release)==0) {
1932 next;
1933 }
1935 if($tmp_release =~ /^.*?,.*?$/ && (!($tmp_release =~ /^.*?\\,.*?$/))) {
1936 # A Subrelease
1937 my @sub_releases= split(/,/, $tmp_release);
1939 # Walk through subreleases and build hash tree
1940 my $hash;
1941 while(my $tmp_sub_release = pop @sub_releases) {
1942 $hash .= "\{'$tmp_sub_release'\}->";
1943 }
1944 # Remove the last two characters
1945 chop($hash);
1946 chop($hash);
1948 eval('$fai_classes->'.$hash.'= {}');
1949 } else {
1950 # A branch, no subrelease
1951 if(!exists($fai_classes->{$tmp_release})) {
1952 $fai_classes->{$tmp_release} = {};
1953 }
1954 }
1955 }
1956 }
1958 # The hash is complete, now we can honor the copy-on-write based missing entries
1959 foreach my $release (keys %$fai_classes) {
1960 $result->{$release}= deep_copy(apply_fai_inheritance($fai_classes->{$release}));
1961 }
1962 }
1963 return $result;
1964 }
1966 sub apply_fai_inheritance {
1967 my $fai_classes = shift || return {};
1968 my $tmp_classes;
1970 # Get the classes from the branch
1971 foreach my $class (keys %{$fai_classes}) {
1972 # Skip subreleases
1973 if($class =~ /^ou=.*$/) {
1974 next;
1975 } else {
1976 $tmp_classes->{$class}= deep_copy($fai_classes->{$class});
1977 }
1978 }
1980 # Apply to each subrelease
1981 foreach my $subrelease (keys %{$fai_classes}) {
1982 if($subrelease =~ /ou=/) {
1983 foreach my $tmp_class (keys %{$tmp_classes}) {
1984 if(!exists($fai_classes->{$subrelease}->{$tmp_class})) {
1985 $fai_classes->{$subrelease}->{$tmp_class} =
1986 deep_copy($tmp_classes->{$tmp_class});
1987 } else {
1988 foreach my $type (keys %{$tmp_classes->{$tmp_class}}) {
1989 if(!exists($fai_classes->{$subrelease}->{$tmp_class}->{$type})) {
1990 $fai_classes->{$subrelease}->{$tmp_class}->{$type}=
1991 deep_copy($tmp_classes->{$tmp_class}->{$type});
1992 }
1993 }
1994 }
1995 }
1996 }
1997 }
1999 # Find subreleases in deeper levels
2000 foreach my $subrelease (keys %{$fai_classes}) {
2001 if($subrelease =~ /ou=/) {
2002 foreach my $subsubrelease (keys %{$fai_classes->{$subrelease}}) {
2003 if($subsubrelease =~ /ou=/) {
2004 apply_fai_inheritance($fai_classes->{$subrelease});
2005 }
2006 }
2007 }
2008 }
2010 return $fai_classes;
2011 }
2013 sub get_fai_release_entries {
2014 my $tmp_classes = shift || return;
2015 my $parent = shift || "";
2016 my @result = shift || ();
2018 foreach my $entry (keys %{$tmp_classes}) {
2019 if(defined($entry)) {
2020 if($entry =~ /^ou=.*$/) {
2021 my $release_name = $entry;
2022 $release_name =~ s/ou=//g;
2023 if(length($parent)>0) {
2024 $release_name = $parent."/".$release_name;
2025 }
2026 my @bufentries = get_fai_release_entries($tmp_classes->{$entry}, $release_name, @result);
2027 foreach my $bufentry(@bufentries) {
2028 push @result, $bufentry;
2029 }
2030 } else {
2031 my @types = get_fai_types($tmp_classes->{$entry});
2032 foreach my $type (@types) {
2033 push @result,
2034 {
2035 'class' => $entry,
2036 'type' => $type->{'type'},
2037 'release' => $parent,
2038 'state' => $type->{'state'},
2039 };
2040 }
2041 }
2042 }
2043 }
2045 return @result;
2046 }
2048 sub deep_copy {
2049 my $this = shift;
2050 if (not ref $this) {
2051 $this;
2052 } elsif (ref $this eq "ARRAY") {
2053 [map deep_copy($_), @$this];
2054 } elsif (ref $this eq "HASH") {
2055 +{map { $_ => deep_copy($this->{$_}) } keys %$this};
2056 } else { die "what type is $_?" }
2057 }
2060 sub session_run_result {
2061 my ($kernel, $heap, $client_answer) = @_[KERNEL, HEAP, ARG0];
2062 $kernel->sig(CHLD => "child_reap");
2063 }
2065 sub session_run_debug {
2066 my $result = $_[ARG0];
2067 print STDERR "$result\n";
2068 }
2070 sub session_run_done {
2071 my ( $kernel, $heap, $task_id ) = @_[ KERNEL, HEAP, ARG0 ];
2072 delete $heap->{task}->{$task_id};
2073 }
2076 sub create_sources_list {
2077 my $session_id = shift;
2078 my $ldap_handle = &main::get_ldap_handle;
2079 my $result="/tmp/gosa_si_tmp_sources_list";
2081 # Remove old file
2082 if(stat($result)) {
2083 unlink($result);
2084 &main::daemon_log("$session_id DEBUG: remove an old version of '$result'", 7);
2085 }
2087 my $fh;
2088 open($fh, ">$result");
2089 if (not defined $fh) {
2090 &main::daemon_log("$session_id DEBUG: cannot open '$result' for writing", 7);
2091 return undef;
2092 }
2093 if(defined($main::ldap_server_dn) and length($main::ldap_server_dn) > 0) {
2094 my $mesg=$ldap_handle->search(
2095 base => $main::ldap_server_dn,
2096 scope => 'base',
2097 attrs => 'FAIrepository',
2098 filter => 'objectClass=FAIrepositoryServer'
2099 );
2100 if($mesg->count) {
2101 foreach my $entry(@{$mesg->{'entries'}}) {
2102 foreach my $value(@{$entry->get_value('FAIrepository', asref => 1)}) {
2103 my ($server, $tag, $release, $sections)= split /\|/, $value;
2104 my $line = "deb $server $release";
2105 $sections =~ s/,/ /g;
2106 $line.= " $sections";
2107 print $fh $line."\n";
2108 }
2109 }
2110 }
2111 } else {
2112 if (defined $main::ldap_server_dn){
2113 &main::daemon_log("$session_id ERROR: something wrong with ldap_server_dn '$main::ldap_server_dn', abort create_sources_list", 1);
2114 } else {
2115 &main::daemon_log("$session_id ERROR: no ldap_server_dn found, abort create_sources_list", 1);
2116 }
2117 }
2118 close($fh);
2120 return $result;
2121 }
2124 sub run_create_packages_list_db {
2125 my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
2126 my $session_id = $session->ID;
2128 my $task = POE::Wheel::Run->new(
2129 Priority => +20,
2130 Program => sub {&create_packages_list_db(undef, undef, $session_id)},
2131 StdoutEvent => "session_run_result",
2132 StderrEvent => "session_run_debug",
2133 CloseEvent => "session_run_done",
2134 );
2135 $heap->{task}->{ $task->ID } = $task;
2136 }
2139 sub create_packages_list_db {
2140 my ($ldap_handle, $sources_file, $session_id) = @_;
2142 # it should not be possible to trigger a recreation of packages_list_db
2143 # while packages_list_db is under construction, so set flag packages_list_under_construction
2144 # which is tested befor recreation can be started
2145 if (-r $packages_list_under_construction) {
2146 daemon_log("$session_id WARNING: packages_list_db is right now under construction, please wait until this process is finished", 3);
2147 return;
2148 } else {
2149 daemon_log("$session_id INFO: create_packages_list_db: start", 5);
2150 # set packages_list_under_construction to true
2151 system("touch $packages_list_under_construction");
2152 @packages_list_statements=();
2153 }
2155 if (not defined $session_id) { $session_id = 0; }
2156 if (not defined $ldap_handle) {
2157 $ldap_handle= &get_ldap_handle();
2159 if (not defined $ldap_handle) {
2160 daemon_log("$session_id ERROR: no ldap_handle available to create_packages_list_db", 1);
2161 unlink($packages_list_under_construction);
2162 return;
2163 }
2164 }
2165 if (not defined $sources_file) {
2166 &main::daemon_log("$session_id INFO: no sources_file given for creating packages list so trigger creation of it", 5);
2167 $sources_file = &create_sources_list($session_id);
2168 }
2170 if (not defined $sources_file) {
2171 &main::daemon_log("$session_id ERROR: no sources_file given under '$sources_file', skip create_packages_list_db", 1);
2172 unlink($packages_list_under_construction);
2173 return;
2174 }
2176 my $line;
2178 open(CONFIG, "<$sources_file") or do {
2179 daemon_log( "$session_id ERROR: create_packages_list_db: Failed to open '$sources_file'", 1);
2180 unlink($packages_list_under_construction);
2181 return;
2182 };
2184 # Read lines
2185 while ($line = <CONFIG>){
2186 # Unify
2187 chop($line);
2188 $line =~ s/^\s+//;
2189 $line =~ s/^\s+/ /;
2191 # Strip comments
2192 $line =~ s/#.*$//g;
2194 # Skip empty lines
2195 if ($line =~ /^\s*$/){
2196 next;
2197 }
2199 # Interpret deb line
2200 if ($line =~ /^deb [^\s]+\s[^\s]+\s[^\s]+/){
2201 my( $baseurl, $dist, $sections ) = ($line =~ /^deb\s([^\s]+)\s+([^\s]+)\s+(.*)$/);
2202 my $section;
2203 foreach $section (split(' ', $sections)){
2204 &parse_package_info( $baseurl, $dist, $section, $session_id );
2205 }
2206 }
2207 }
2209 close (CONFIG);
2211 find(\&cleanup_and_extract, keys( %repo_dirs ));
2212 &main::strip_packages_list_statements();
2213 unshift @packages_list_statements, "VACUUM";
2214 $packages_list_db->exec_statementlist(\@packages_list_statements);
2215 unlink($packages_list_under_construction);
2216 daemon_log("$session_id INFO: create_packages_list_db: finished", 5);
2217 return;
2218 }
2220 # This function should do some intensive task to minimize the db-traffic
2221 sub strip_packages_list_statements {
2222 my @existing_entries= @{$packages_list_db->exec_statement("SELECT * FROM $main::packages_list_tn")};
2223 my @new_statement_list=();
2224 my $hash;
2225 my $insert_hash;
2226 my $update_hash;
2227 my $delete_hash;
2228 my $local_timestamp=get_time();
2230 foreach my $existing_entry (@existing_entries) {
2231 $hash->{@{$existing_entry}[0]}->{@{$existing_entry}[1]}->{@{$existing_entry}[2]}= $existing_entry;
2232 }
2234 foreach my $statement (@packages_list_statements) {
2235 if($statement =~ /^INSERT/i) {
2236 # Assign the values from the insert statement
2237 my ($distribution,$package,$version,$section,$description,$template,$timestamp) = ($1,$2,$3,$4,$5,$6,$7) if $statement =~
2238 /^INSERT\s+?INTO\s+?$main::packages_list_tn\s+?VALUES\s*?\('(.*?)',\s*?'(.*?)',\s*?'(.*?)',\s*?'(.*?)',\s*?'(.*?)',\s*?'(.*?)',\s*?'(.*?)'\s*?\)$/si;
2239 if(exists($hash->{$distribution}->{$package}->{$version})) {
2240 # If section or description has changed, update the DB
2241 if(
2242 (! (@{$hash->{$distribution}->{$package}->{$version}}[3] eq $section)) or
2243 (! (@{$hash->{$distribution}->{$package}->{$version}}[4] eq $description))
2244 ) {
2245 @{$update_hash->{$distribution}->{$package}->{$version}} = ($distribution,$package,$version,$section,$description,undef);
2246 }
2247 } else {
2248 # Insert a non-existing entry to db
2249 @{$insert_hash->{$distribution}->{$package}->{$version}} = ($distribution,$package,$version,$section,$description,$template);
2250 }
2251 } elsif ($statement =~ /^UPDATE/i) {
2252 my ($template,$package,$version) = ($1,$2,$3) if $statement =~
2253 /^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;
2254 foreach my $distribution (keys %{$hash}) {
2255 if(exists($insert_hash->{$distribution}->{$package}->{$version})) {
2256 # update the insertion hash to execute only one query per package (insert instead insert+update)
2257 @{$insert_hash->{$distribution}->{$package}->{$version}}[5]= $template;
2258 } elsif(exists($hash->{$distribution}->{$package}->{$version})) {
2259 if( ! (@{$hash->{$distribution}->{$package}->{$version}}[5] eq $template)) {
2260 my $section;
2261 my $description;
2262 if(defined(@{$update_hash->{$distribution}->{$package}->{$version}}[3]) and
2263 length(@{$update_hash->{$distribution}->{$package}->{$version}}[3]) > 0 ) {
2264 $section= @{$update_hash->{$distribution}->{$package}->{$version}}[3];
2265 }
2266 if(defined(@{$update_hash->{$distribution}->{$package}->{$version}}[4])) {
2267 $description= @{$update_hash->{$distribution}->{$package}->{$version}}[4];
2268 }
2269 @{$update_hash->{$distribution}->{$package}->{$version}} = ($distribution,$package,$version,$section,$description,$template);
2270 }
2271 }
2272 }
2273 }
2274 }
2276 # TODO: Check for orphaned entries
2278 # unroll the insert_hash
2279 foreach my $distribution (keys %{$insert_hash}) {
2280 foreach my $package (keys %{$insert_hash->{$distribution}}) {
2281 foreach my $version (keys %{$insert_hash->{$distribution}->{$package}}) {
2282 push @new_statement_list, "INSERT INTO $main::packages_list_tn VALUES ('$distribution','$package','$version',"
2283 ."'@{$insert_hash->{$distribution}->{$package}->{$version}}[3]',"
2284 ."'@{$insert_hash->{$distribution}->{$package}->{$version}}[4]',"
2285 ."'@{$insert_hash->{$distribution}->{$package}->{$version}}[5]',"
2286 ."'$local_timestamp')";
2287 }
2288 }
2289 }
2291 # unroll the update hash
2292 foreach my $distribution (keys %{$update_hash}) {
2293 foreach my $package (keys %{$update_hash->{$distribution}}) {
2294 foreach my $version (keys %{$update_hash->{$distribution}->{$package}}) {
2295 my $set = "";
2296 if(defined(@{$update_hash->{$distribution}->{$package}->{$version}}[3])) {
2297 $set .= "section = '@{$update_hash->{$distribution}->{$package}->{$version}}[3]', ";
2298 }
2299 if(defined(@{$update_hash->{$distribution}->{$package}->{$version}}[4])) {
2300 $set .= "description = '@{$update_hash->{$distribution}->{$package}->{$version}}[4]', ";
2301 }
2302 if(defined(@{$update_hash->{$distribution}->{$package}->{$version}}[5])) {
2303 $set .= "template = '@{$update_hash->{$distribution}->{$package}->{$version}}[5]', ";
2304 }
2305 if(defined($set) and length($set) > 0) {
2306 $set .= "timestamp = '$local_timestamp'";
2307 } else {
2308 next;
2309 }
2310 push @new_statement_list,
2311 "UPDATE $main::packages_list_tn SET $set WHERE"
2312 ." distribution = '$distribution'"
2313 ." AND package = '$package'"
2314 ." AND version = '$version'";
2315 }
2316 }
2317 }
2319 @packages_list_statements = @new_statement_list;
2320 }
2323 sub parse_package_info {
2324 my ($baseurl, $dist, $section, $session_id)= @_;
2325 my ($package);
2326 if (not defined $session_id) { $session_id = 0; }
2327 my ($path) = ($baseurl =~ m%://[^/]*(.*)$%);
2328 $repo_dirs{ "${repo_path}/pool" } = 1;
2330 foreach $package ("Packages.gz"){
2331 daemon_log("$session_id DEBUG: create_packages_list: fetch $baseurl, $dist, $section", 7);
2332 get_package( "$baseurl/dists/$dist/$section/binary-$arch/$package", "$outdir/$dist/$section", $session_id );
2333 parse_package( "$outdir/$dist/$section", $dist, $path, $session_id );
2334 }
2336 }
2339 sub get_package {
2340 my ($url, $dest, $session_id)= @_;
2341 if (not defined $session_id) { $session_id = 0; }
2343 my $tpath = dirname($dest);
2344 -d "$tpath" || mkpath "$tpath";
2346 # This is ugly, but I've no time to take a look at "how it works in perl"
2347 if(0 == system("wget '$url' -O '$dest' 2>/dev/null") ) {
2348 system("gunzip -cd '$dest' > '$dest.in'");
2349 daemon_log("$session_id DEBUG: run command: gunzip -cd '$dest' > '$dest.in'", 5);
2350 unlink($dest);
2351 daemon_log("$session_id DEBUG: delete file '$dest'", 5);
2352 } else {
2353 daemon_log("$session_id ERROR: create_packages_list_db: get_packages: fetching '$url' failed!", 1);
2354 }
2355 return 0;
2356 }
2359 sub parse_package {
2360 my ($path, $dist, $srv_path, $session_id)= @_;
2361 if (not defined $session_id) { $session_id = 0;}
2362 my ($package, $version, $section, $description);
2363 my $PACKAGES;
2364 my $timestamp = &get_time();
2366 if(not stat("$path.in")) {
2367 daemon_log("$session_id ERROR: create_packages_list: parse_package: file '$path.in' is not readable",1);
2368 return;
2369 }
2371 open($PACKAGES, "<$path.in");
2372 if(not defined($PACKAGES)) {
2373 daemon_log("$session_id ERROR: create_packages_list_db: parse_package: cannot open '$path.in'",1);
2374 return;
2375 }
2377 # Read lines
2378 while (<$PACKAGES>){
2379 my $line = $_;
2380 # Unify
2381 chop($line);
2383 # Use empty lines as a trigger
2384 if ($line =~ /^\s*$/){
2385 my $sql = "INSERT INTO packages_list VALUES ('$dist', '$package', '$version', '$section', '$description', '', '$timestamp')";
2386 push(@packages_list_statements, $sql);
2387 $package = "none";
2388 $version = "none";
2389 $section = "none";
2390 $description = "none";
2391 next;
2392 }
2394 # Trigger for package name
2395 if ($line =~ /^Package:\s/){
2396 ($package)= ($line =~ /^Package: (.*)$/);
2397 next;
2398 }
2400 # Trigger for version
2401 if ($line =~ /^Version:\s/){
2402 ($version)= ($line =~ /^Version: (.*)$/);
2403 next;
2404 }
2406 # Trigger for description
2407 if ($line =~ /^Description:\s/){
2408 ($description)= &encode_base64(($line =~ /^Description: (.*)$/));
2409 next;
2410 }
2412 # Trigger for section
2413 if ($line =~ /^Section:\s/){
2414 ($section)= ($line =~ /^Section: (.*)$/);
2415 next;
2416 }
2418 # Trigger for filename
2419 if ($line =~ /^Filename:\s/){
2420 my ($filename) = ($line =~ /^Filename: (.*)$/);
2421 store_fileinfo( $package, $filename, $dist, $srv_path, $version, $repo_path );
2422 next;
2423 }
2424 }
2426 close( $PACKAGES );
2427 unlink( "$path.in" );
2428 &main::daemon_log("$session_id DEBUG: unlink '$path.in'", 1);
2429 }
2432 sub store_fileinfo {
2433 my( $package, $file, $dist, $path, $vers, $srvdir) = @_;
2435 my %fileinfo = (
2436 'package' => $package,
2437 'dist' => $dist,
2438 'version' => $vers,
2439 );
2441 $repo_files{ "${srvdir}/$file" } = \%fileinfo;
2442 }
2445 sub cleanup_and_extract {
2446 my $fileinfo = $repo_files{ $File::Find::name };
2448 if( defined $fileinfo ) {
2450 my $dir = "$outdir/$fileinfo->{ 'dist' }/debconf.d";
2451 my $sql;
2452 my $package = $fileinfo->{ 'package' };
2453 my $newver = $fileinfo->{ 'version' };
2455 mkpath($dir);
2456 system( "dpkg -e '$File::Find::name' '$dir/DEBIAN'" );
2458 if( -f "$dir/DEBIAN/templates" ) {
2460 daemon_log("DEBUG: Found debconf templates in '$package' - $newver", 5);
2462 my $tmpl= "";
2463 {
2464 local $/=undef;
2465 open FILE, "$dir/DEBIAN/templates";
2466 $tmpl = &encode_base64(<FILE>);
2467 close FILE;
2468 }
2469 rmtree("$dir/DEBIAN/templates");
2471 $sql= "update $main::packages_list_tn set template = '$tmpl' where package = '$package' and version = '$newver';";
2472 push @packages_list_statements, $sql;
2473 }
2474 }
2476 return;
2477 }
2480 #==== MAIN = main ==============================================================
2481 # parse commandline options
2482 Getopt::Long::Configure( "bundling" );
2483 GetOptions("h|help" => \&usage,
2484 "c|config=s" => \$cfg_file,
2485 "f|foreground" => \$foreground,
2486 "v|verbose+" => \$verbose,
2487 "no-bus+" => \$no_bus,
2488 "no-arp+" => \$no_arp,
2489 );
2491 # read and set config parameters
2492 &check_cmdline_param ;
2493 &read_configfile;
2494 &check_pid;
2496 $SIG{CHLD} = 'IGNORE';
2498 # forward error messages to logfile
2499 if( ! $foreground ) {
2500 open( STDIN, '+>/dev/null' );
2501 open( STDOUT, '+>&STDIN' );
2502 open( STDERR, '+>&STDIN' );
2503 }
2505 # Just fork, if we are not in foreground mode
2506 if( ! $foreground ) {
2507 chdir '/' or die "Can't chdir to /: $!";
2508 $pid = fork;
2509 setsid or die "Can't start a new session: $!";
2510 umask 0;
2511 } else {
2512 $pid = $$;
2513 }
2515 # Do something useful - put our PID into the pid_file
2516 if( 0 != $pid ) {
2517 open( LOCK_FILE, ">$pid_file" );
2518 print LOCK_FILE "$pid\n";
2519 close( LOCK_FILE );
2520 if( !$foreground ) {
2521 exit( 0 )
2522 };
2523 }
2525 # parse head url and revision from svn
2526 my $server_status_hash = { 'developmental'=>'revision', 'stable'=>'release'};
2527 $server_version =~ /^\$HeadURL: (\S+) \$:\$Rev: (\d+) \$$/;
2528 $server_headURL = defined $1 ? $1 : 'unknown' ;
2529 $server_revision = defined $2 ? $2 : 'unknown' ;
2530 if ($server_headURL =~ /\/tag\// ||
2531 $server_headURL =~ /\/branches\// ) {
2532 $server_status = "stable";
2533 } else {
2534 $server_status = "developmental" ;
2535 }
2538 daemon_log(" ", 1);
2539 daemon_log("$0 started!", 1);
2540 daemon_log("status: $server_status", 1);
2541 daemon_log($server_status_hash->{$server_status}.": $server_revision", 1);
2543 if ($no_bus > 0) {
2544 $bus_activ = "false"
2545 }
2547 # connect to gosa-si job queue
2548 $job_db = GOSA::DBsqlite->new($job_queue_file_name);
2549 $job_db->create_table($job_queue_tn, \@job_queue_col_names);
2551 # connect to known_clients_db
2552 $known_clients_db = GOSA::DBsqlite->new($known_clients_file_name);
2553 $known_clients_db->create_table($known_clients_tn, \@known_clients_col_names);
2555 # connect to known_server_db
2556 $known_server_db = GOSA::DBsqlite->new($known_server_file_name);
2557 $known_server_db->create_table($known_server_tn, \@known_server_col_names);
2559 # connect to login_usr_db
2560 $login_users_db = GOSA::DBsqlite->new($login_users_file_name);
2561 $login_users_db->create_table($login_users_tn, \@login_users_col_names);
2563 # connect to fai_server_db and fai_release_db
2564 unlink($fai_server_file_name);
2565 $fai_server_db = GOSA::DBsqlite->new($fai_server_file_name);
2566 $fai_server_db->create_table($fai_server_tn, \@fai_server_col_names);
2568 unlink($fai_release_file_name);
2569 $fai_release_db = GOSA::DBsqlite->new($fai_release_file_name);
2570 $fai_release_db->create_table($fai_release_tn, \@fai_release_col_names);
2572 # connect to packages_list_db
2573 #unlink($packages_list_file_name);
2574 unlink($packages_list_under_construction);
2575 $packages_list_db = GOSA::DBsqlite->new($packages_list_file_name);
2576 $packages_list_db->create_table($packages_list_tn, \@packages_list_col_names);
2578 # connect to messaging_db
2579 $messaging_db = GOSA::DBsqlite->new($messaging_file_name);
2580 $messaging_db->create_table($messaging_tn, \@messaging_col_names);
2583 # create xml object used for en/decrypting
2584 $xml = new XML::Simple();
2586 # create socket for incoming xml messages
2588 POE::Component::Server::TCP->new(
2589 Port => $server_port,
2590 ClientInput => sub {
2591 my ($kernel, $input) = @_[KERNEL, ARG0];
2592 push(@tasks, $input);
2593 $kernel->yield("next_task");
2594 },
2595 InlineStates => {
2596 next_task => \&next_task,
2597 task_result => \&handle_task_result,
2598 task_done => \&handle_task_done,
2599 task_debug => \&handle_task_debug,
2600 child_reap => sub { "Do nothing special. I'm just a comment, but i'm necessary!" },
2601 }
2602 );
2604 daemon_log("start socket for incoming xml messages at port '$server_port' ", 1);
2606 # create session for repeatedly checking the job queue for jobs
2607 POE::Session->create(
2608 inline_states => {
2609 _start => \&_start,
2610 sig_handler => \&sig_handler,
2611 watch_for_new_messages => \&watch_for_new_messages,
2612 watch_for_delivery_messages => \&watch_for_delivery_messages,
2613 watch_for_done_messages => \&watch_for_done_messages,
2614 watch_for_new_jobs => \&watch_for_new_jobs,
2615 watch_for_done_jobs => \&watch_for_done_jobs,
2616 create_packages_list_db => \&run_create_packages_list_db,
2617 create_fai_server_db => \&run_create_fai_server_db,
2618 create_fai_release_db => \&run_create_fai_release_db,
2619 session_run_result => \&session_run_result,
2620 session_run_debug => \&session_run_debug,
2621 session_run_done => \&session_run_done,
2622 child_reap => sub { "Do nothing special. I'm just a comment, but i'm necessary!" },
2623 }
2624 );
2627 # import all modules
2628 &import_modules;
2630 # check wether all modules are gosa-si valid passwd check
2632 POE::Kernel->run();
2633 exit;