From 706eb68e0982d0805024d220893bba575ddadd59 Mon Sep 17 00:00:00 2001 From: rettenbe Date: Thu, 7 Feb 2008 17:01:44 +0000 Subject: [PATCH] --- incomplete --- bus mac address handling git-svn-id: https://oss.gonicus.de/repositories/gosa/trunk@8771 594d385d-05f5-0310-b6e9-bd551577e9d8 --- gosa-si/bus.conf | 9 +- gosa-si/gosa-si-bus | 1182 ++++++++++++++------------------- gosa-si/gosa-si-client | 6 +- gosa-si/tests/client.php | 3 +- gosa-si/tests/sqlite-check.pl | 15 +- 5 files changed, 522 insertions(+), 693 deletions(-) diff --git a/gosa-si/bus.conf b/gosa-si/bus.conf index c6ba710a7..55eae72eb 100644 --- a/gosa-si/bus.conf +++ b/gosa-si/bus.conf @@ -5,9 +5,6 @@ child_max = 10 child_min = 2 child_timeout = 10 -[bus] -bus_activ = on -bus_passwd = secret-bus-password -bus_ip = 10.89.1.31 -bus_port = 20080 - +[GOsa-si-bus] +ip = 10.89.1.31 +key = secret-bus-password diff --git a/gosa-si/gosa-si-bus b/gosa-si/gosa-si-bus index f07bf9e6a..c37d14b7e 100755 --- a/gosa-si/gosa-si-bus +++ b/gosa-si/gosa-si-bus @@ -1,9 +1,9 @@ #!/usr/bin/perl #=============================================================================== # -# FILE: gosa-server +# FILE: gosa-si-bus # -# USAGE: ./gosa-server +# USAGE: ./gosa-si-bus # # DESCRIPTION: # @@ -25,43 +25,70 @@ use Config::IniFiles; use POSIX; use Time::HiRes qw( gettimeofday ); -use IO::Socket::INET; +use POE qw(Component::Server::TCP); +use Data::Dumper; use Crypt::Rijndael; +use GOSA::DBsqlite; +use GOSA::GosaSupportDaemon; +use IO::Socket::INET; +use NetAddr::IP; +use XML::Simple; use MIME::Base64; use Digest::MD5 qw(md5 md5_hex md5_base64); -use XML::Simple; -use Data::Dumper; -use Sys::Syslog qw( :DEFAULT setlogsock); -use Cwd; -use File::Spec; -use GOSA::GosaSupportDaemon; -use GOSA::DBsqlite; -my ($cfg_file, $default_cfg_file, %cfg_defaults, $foreground, $verbose); -my ($bus_activ, $bus_key, $bus_ip, $bus_port, $bus_address, $bus, $bus_mac_address, $network_interface); -my ($pid_file, $procid, $pid, $log_file, $my_own_address); -my (%free_child, %busy_child, $child_max, $child_min, %child_alive_time, $child_timeout); -my ($bus_known_server_db, $bus_known_server_file_name); -my ($xml, $bus_cipher); -$foreground = 0 ; +my ($cfg_file, $default_cfg_file, %cfg_defaults, $foreground, $verbose, $pid_file, $procid, $pid, $log_file,); +my ($bus_address, $bus_key, $bus_ip, $bus_port, $bus_mac_address); +my ($bus_known_server_db, $bus_known_server_file_name, $bus_known_clients_db, $bus_known_clients_file_name); +my $xml; -%cfg_defaults = -("general" => - {"log_file" => [\$log_file, "/var/run/".$0.".log"], +$foreground = 0 ; +%cfg_defaults = ( +"general" => { + "log_file" => [\$log_file, "/var/run/".$0.".log"], "pid_file" => [\$pid_file, "/var/run/".$0.".pid"], - "child_max" => [\$child_max, 10], - "child_min" => [\$child_min, 3], - "child_timeout" => [\$child_timeout, 180], - "bus_known_server_file_name" => [\$bus_known_server_file_name, "/var/lib/gosa-si/gosa-si-bus_known_server.db"] + "bus_known_server_file_name" => [\$bus_known_server_file_name, "/var/lib/gosa-si/gosa-si-bus_known_server.db"], + "bus_known_clients_file_name" => [\$bus_known_clients_file_name, "/var/lib/gosa-si/gosa-si-bus_known_clients.db"], }, -"bus" => - {"bus_activ" => [\$bus_activ, "on"], - "bus_passwd" => [\$bus_key, ""], - "bus_ip" => [\$bus_ip, "0.0.0.0"], - "bus_port" => [\$bus_port, "20080"], +"GOsa-si-bus" => { + "key" => [\$bus_key, "secret-bus-password"], + "ip" => [\$bus_ip, "0.0.0.0"], + "port" => [\$bus_port, "20080"], + }, +); + +#=== FUNCTIONS = functions ===================================================== + +#=== FUNCTION ================================================================ +# NAME: check_cmdline_param +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub check_cmdline_param () { + my @error_l; + my $error = 0; + + if( !$cfg_file ) { + $cfg_file = "/etc/gosa-si/bus.conf"; + } + if( not -f $cfg_file ) { + push(@error_l, "can not find file '$cfg_file'"); + $error++; + } + if( not -r $cfg_file) { + push(@error_l, "can not read file '$cfg_file'"); + $error++; } - ); + + if( $error > 0 ) { + &usage( "", 1 ); + print STDERR join("\n", @error_l); + print STDERR "\n"; + exit( -1 ); + } +} + #=== FUNCTION ================================================================ # NAME: read_configfile @@ -88,61 +115,6 @@ sub read_configfile { } } -#=== FUNCTION ================================================================ -# NAME: logging -# PARAMETERS: level - string - default 'info' -# msg - string - -# facility - string - default 'LOG_DAEMON' -# RETURNS: nothing -# DESCRIPTION: function for logging -#=============================================================================== -sub daemon_log { - my( $msg, $level ) = @_; - if(not defined $msg) { return } - if(not defined $level) { $level = 1 } - if(defined $log_file){ - open(LOG_HANDLE, ">>$log_file"); - if(not defined open( LOG_HANDLE, ">>$log_file" )) { - print STDERR "cannot open $log_file: $!"; - return } - chomp($msg); - if($level && $verbose && $level <= $verbose){ - print LOG_HANDLE $msg."\n"; - if(defined $foreground) { print STDERR $msg."\n" } - } - } - close( LOG_HANDLE ); -# my ($msg, $level, $facility) = @_; -# if(not defined $msg) {return} -# if(not defined $level) {$level = "info"} -# if(not defined $facility) {$facility = "LOG_DAEMON"} -# openlog($0, "pid,cons,", $facility); -# syslog($level, $msg); -# closelog; -# return; -} - -#=== FUNCTION ================================================================ -# NAME: check_cmdline_param -# PARAMETERS: nothing -# RETURNS: nothing -# DESCRIPTION: validates commandline parameter -#=============================================================================== -sub check_cmdline_param () { - my $err_config; - my $err_counter = 0; - if( not defined( $cfg_file)) { - my $cwd = getcwd; - my $name = "/etc/gosa-si/bus.conf"; - $cfg_file = File::Spec->catfile( $cwd, $name ); - } - if( $err_counter > 0 ) { - &usage( "", 1 ); - if( defined( $err_config)) { print STDERR "$err_config\n"} - print STDERR "\n"; - exit( -1 ); - } -} #=== FUNCTION ================================================================ # NAME: check_pid @@ -213,21 +185,76 @@ EOF #=== FUNCTION ================================================================ -# NAME: sig_int_handler -# PARAMETERS: signal - string - signal arose from system -# RETURNS: noting -# DESCRIPTION: handels tasks to be done befor signal becomes active +# NAME: logging +# PARAMETERS: level - string - default 'info' +# msg - string - +# facility - string - default 'LOG_DAEMON' +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub daemon_log { + # log into log_file + my( $msg, $level ) = @_; + if(not defined $msg) { return } + if(not defined $level) { $level = 1 } + if(defined $log_file){ + open(LOG_HANDLE, ">>$log_file"); + if(not defined open( LOG_HANDLE, ">>$log_file" )) { + print STDERR "cannot open $log_file: $!"; + return } + chomp($msg); + if($level <= $verbose){ + my ($seconds, $minutes, $hours, $monthday, $month, + $year, $weekday, $yearday, $sommertime) = localtime(time); + $hours = $hours < 10 ? $hours = "0".$hours : $hours; + $minutes = $minutes < 10 ? $minutes = "0".$minutes : $minutes; + $seconds = $seconds < 10 ? $seconds = "0".$seconds : $seconds; + my @monthnames = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); + $month = $monthnames[$month]; + $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; + $year+=1900; + my $name = $0; + $name =~ s/\.\///; + + my $log_msg = "$month $monthday $hours:$minutes:$seconds $name $msg\n"; + print LOG_HANDLE $log_msg; + if( $foreground ) { + print STDERR $log_msg; + } + } + close( LOG_HANDLE ); + } +} + + +#=== FUNCTION ================================================================ +# NAME: get_ip +# PARAMETERS: interface name (i.e. eth0) +# RETURNS: (ip address) +# DESCRIPTION: Uses ioctl to get ip address directly from system. #=============================================================================== -sub sig_int_handler { - my ($signal) = @_; - if($bus){ - close($bus); - print "$bus closed\n"; +sub get_ip { + my $ifreq= shift; + my $result= ""; + my $SIOCGIFADDR= 0x8915; # man 2 ioctl_list + my $proto= getprotobyname('ip'); + + socket SOCKET, PF_INET, SOCK_DGRAM, $proto + or die "socket: $!"; + + if(ioctl SOCKET, $SIOCGIFADDR, $ifreq) { + my ($if, $sin) = unpack 'a16 a16', $ifreq; + my ($port, $addr) = sockaddr_in $sin; + my $ip = inet_ntoa $addr; + + if ($ip && length($ip) > 0) { + $result = $ip; + } } - print "$signal\n"; - exit(1); + + return $result; } -$SIG{INT} = \&sig_int_handler; + #=== FUNCTION ================================================================ # NAME: get_interface_for_ip @@ -236,24 +263,26 @@ $SIG{INT} = \&sig_int_handler; # DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. #=============================================================================== sub get_interface_for_ip { - my $result; - my $ip= shift; - if ($ip && length($ip) > 0) { - my @ifs= &get_interfaces(); - if($ip eq "0.0.0.0") { - $result = "all"; - } else { - foreach (@ifs) { - my $if=$_; - if(get_ip($if) eq $ip) { - $result = $if; - } - } + my $result; + my $ip= shift; + if ($ip && length($ip) > 0) { + my @ifs= &get_interfaces(); + if($ip eq "0.0.0.0") { + $result = "all"; + } else { + foreach (@ifs) { + my $if=$_; + if(get_ip($if) eq $ip) { + $result = $if; + last; } + } } - return $result; + } + return $result; } + #=== FUNCTION ================================================================ # NAME: get_interfaces # PARAMETERS: none @@ -261,30 +290,31 @@ sub get_interface_for_ip { # DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. #=============================================================================== sub get_interfaces { - my @result; - my $PROC_NET_DEV= ('/proc/net/dev'); + my @result; + my $PROC_NET_DEV= ('/proc/net/dev'); - open(PROC_NET_DEV, "<$PROC_NET_DEV") - or die "Could not open $PROC_NET_DEV"; + open(PROC_NET_DEV, "<$PROC_NET_DEV") + or die "Could not open $PROC_NET_DEV"; - my @ifs = ; + my @ifs = ; - close(PROC_NET_DEV); + close(PROC_NET_DEV); - # Eat first two line - shift @ifs; - shift @ifs; + # Eat first two line + shift @ifs; + shift @ifs; - chomp @ifs; - foreach my $line(@ifs) { - my $if= (split /:/, $line)[0]; - $if =~ s/^\s+//; - push @result, $if; - } + chomp @ifs; + foreach my $line(@ifs) { + my $if= (split /:/, $line)[0]; + $if =~ s/^\s+//; + push @result, $if; + } - return @result; + return @result; } + #=== FUNCTION ================================================================ # NAME: get_mac # PARAMETERS: interface name (i.e. eth0) @@ -294,242 +324,136 @@ sub get_interfaces { sub get_mac { my $ifreq= shift; my $result; - if ($ifreq && length($ifreq) > 0) { + if ($ifreq && length($ifreq) > 0) { if($ifreq eq "all") { - $result = "00:00:00:00:00:00"; + if(defined($bus_ip)) { + $result = &get_local_mac_for_remote_ip($bus_ip); + } + elsif ($bus_mac_address && length($bus_mac_address) > 0 && !($bus_mac_address eq "00:00:00:00:00:00")){ + $result = &client_mac_address; + } + else { + $result = "00:00:00:00:00:00"; + } } else { my $SIOCGIFHWADDR= 0x8927; # man 2 ioctl_list # A configured MAC Address should always override a guessed value - if ($bus_mac_address and length($bus_mac_address) > 0) { - return $bus_mac_address; + if ($bus_mac_address and length($bus_mac_address) > 0 and not($bus_mac_address eq "00:00:00:00:00:00")) { + $result= $bus_mac_address; } + else { + socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip') + or die "socket: $!"; - socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip') - or die "socket: $!"; - - if(ioctl SOCKET, $SIOCGIFHWADDR, $ifreq) { - my ($if, $mac)= unpack 'h36 H12', $ifreq; + if(ioctl SOCKET, $SIOCGIFHWADDR, $ifreq) { + my ($if, $mac)= unpack 'h36 H12', $ifreq; - if (length($mac) > 0) { - $mac=~ m/^([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])$/; - $mac= sprintf("%s:%s:%s:%s:%s:%s", $1, $2, $3, $4, $5, $6); - $result = $mac; + if (length($mac) > 0) { + $mac=~ m/^([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])$/; + $mac= sprintf("%s:%s:%s:%s:%s:%s", $1, $2, $3, $4, $5, $6); + $result = $mac; + } + } } - } } } return $result; } -#=== FUNCTION ================================================================ -# NAME: get_ip -# PARAMETERS: interface name (i.e. eth0) -# RETURNS: (ip address) -# DESCRIPTION: Uses ioctl to get ip address directly from system. -#=============================================================================== -sub get_ip { - my $ifreq= shift; - my $result= ""; - my $SIOCGIFADDR= 0x8915; # man 2 ioctl_list - my $proto= getprotobyname('ip'); - - socket SOCKET, PF_INET, SOCK_DGRAM, $proto - or die "socket: $!"; - - if(ioctl SOCKET, $SIOCGIFADDR, $ifreq) { - my ($if, $sin) = unpack 'a16 a16', $ifreq; - my ($port, $addr) = sockaddr_in $sin; - my $ip = inet_ntoa $addr; - - if ($ip && length($ip) > 0) { - $result = $ip; - } - } - - return $result; -} #=== FUNCTION ================================================================ -# NAME: activating_child -# PARAMETERS: msg - string - incoming message -# host - string - host from which the incomming message comes -# RETURNS: nothing -# DESCRIPTION: handels the distribution of incoming messages to working childs +# NAME: get_local_mac_for_remote_ip +# PARAMETERS: none (takes server_ip from global variable) +# RETURNS: (ip address from interface that is used for communication) +# DESCRIPTION: Uses ioctl to get routing table from system, checks which entry +# matches (defaultroute last). #=============================================================================== -sub activating_child { - my ($msg, $host) = @_; - my $child = &get_processing_child(); - my $pipe_wr = $$child{'pipe_wr'}; - daemon_log("activating: childpid: $$child{'pid'}", 5); - print $pipe_wr $msg.".".$host."\n"; - return; +sub get_local_mac_for_remote_ip { + my $server_ip= shift; + my $result= "00:00:00:00:00:00"; + + if($server_ip =~ /^(\d\d?\d?\.){3}\d\d?\d?$/) { + my $PROC_NET_ROUTE= ('/proc/net/route'); + + open(PROC_NET_ROUTE, "<$PROC_NET_ROUTE") + or die "Could not open $PROC_NET_ROUTE"; + + my @ifs = ; + + close(PROC_NET_ROUTE); + + # Eat header line + shift @ifs; + chomp @ifs; + foreach my $line(@ifs) { + my ($Iface,$Destination,$Gateway,$Flags,$RefCnt,$Use,$Metric,$Mask,$MTU,$Window,$IRTT)=split(/\s/, $line); + my $destination; + my $mask; + my ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Destination); + $destination= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d)); + ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Mask); + $mask= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d)); + if(new NetAddr::IP($server_ip)->within(new NetAddr::IP($destination, $mask))) { + # destination matches route, save mac and exit + $result= &get_mac($Iface); + last; + } + } + } else { + daemon_log("get_local_mac_for_remote_ip was called with a non-ip parameter: $server_ip", 1); + } + return $result; } #=== FUNCTION ================================================================ -# NAME: get_processing_child +# NAME: create_passwd # PARAMETERS: nothing -# RETURNS: child - hash - holding the process id and the references to the pipe -# handles pipe_wr and pipe_rd -# DESCRIPTION: handels the forking, reactivating and keeping alive tasks +# RETURNS: new_passwd - string +# DESCRIPTION: creates a 32 bit long random passwd out of "a".."z","A".."Z",0..9 #=============================================================================== -sub get_processing_child { - my $child; - # checking %busy_child{pipe_wr} if msg is 'done', then set child from busy to free - while(my ($key, $val) = each(%busy_child)) { - # check wether process still exists - my $exitus_pid = waitpid($key, WNOHANG); - if($exitus_pid != 0) { - delete $busy_child{$key}; - daemon_log( "prozess:$key wurde aus busy_child entfernt\n", 5); - next; - } - - # check wether process sitll works - my $fh = $$val{'pipe_rd'}; - $fh->blocking(0); - my $child_answer; - if(not $child_answer = <$fh>) { next } - chomp($child_answer); - if($child_answer eq "done") { - delete $busy_child{$key}; - $free_child{$key} = $val; - } +sub create_passwd { + my $new_passwd = ""; + for(my $i=0; $i<31; $i++) { + $new_passwd .= ("a".."z","A".."Z",0..9)[int(rand(62))] } + return $new_passwd; +} - while(my ($key, $val) = each(%free_child)) { - my $exitus_pid = waitpid($key, WNOHANG); - if($exitus_pid != 0) { - delete $free_child{$key}; - daemon_log( "prozess:$key wurde aus free_child entfernt\n", 5); - } - daemon_log("free child:$key\n", 5); - } - # check @free_child and @busy_child - my $free_len = scalar(keys(%free_child)); - my $busy_len = scalar(keys(%busy_child)); - daemon_log("free children $free_len, busy children $busy_len\n",5); - - # if there is a free child, let the child work - if($free_len > 0){ - my @keys = keys(%free_child); - $child = $free_child{$keys[0]}; - if(defined $child) { - $busy_child{$$child{'pid'}} = $child ; - delete $free_child{$$child{'pid'}}; - } - return $child; - } - - # no free child, try to fork another one - if($free_len + $busy_len < $child_max) { - - daemon_log("not enough children, create a new one\n",5); - - # New pipes for communication - my( $PARENT_wr, $PARENT_rd ); - my( $CHILD_wr, $CHILD_rd ); - pipe( $CHILD_rd, $PARENT_wr ); - pipe( $PARENT_rd, $CHILD_wr ); - $PARENT_wr->autoflush(1); - $CHILD_wr->autoflush(1); - - ############ - # fork child - ############ - my $child_pid = fork(); - - #CHILD - if($child_pid == 0) { - # Close unused pipes - close( $CHILD_rd ); - close( $CHILD_wr ); - while( 1 ) { - my $rbits = ""; - vec( $rbits, fileno $PARENT_rd , 1 ) = 1; - - # waiting child_timeout for jobs to do - my $nf = select($rbits, undef, undef, $child_timeout); - if($nf < 0 ) { - # if $nf < 1, error handling - die "select(): $!\n"; - } elsif (! $nf) { - # if already child_min childs are alive, then leave loop - $free_len = scalar(keys(%free_child)); - $busy_len = scalar(keys(%busy_child)); - if($free_len + $busy_len >= $child_min) { - last; - } else { - redo; - } - } - - # a job for a child arise - if ( vec $rbits, fileno $PARENT_rd, 1 ) { - # read everything from pipe - my $msg = ""; - $PARENT_rd->blocking(0); - while(1) { - my $read = <$PARENT_rd>; - if(not defined $read) { last} - $msg .= $read; - } - # forward the job msg to another function - &process_incoming_msg($msg); - daemon_log("processing of msg finished", 5); +sub create_ciphering { + my ($passwd) = @_; + $passwd = substr(md5_hex("$passwd") x 32, 0, 32); + my $iv = substr(md5_hex('GONICUS GmbH'),0, 16); + my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC()); + $my_cipher->set_iv($iv); + return $my_cipher; +} - # important!!! wait until child says 'done', until then child is set from busy to free - print $PARENT_wr "done"; - redo; - } - } - # childs leaving the loop are allowed to die - exit(0); - #PARENT - } else { - # Close unused pipes - close( $PARENT_rd ); - close( $PARENT_wr ); - # add child to child alive hash - my %child_hash = ( - 'pid' => $child_pid, - 'pipe_wr' => $CHILD_wr, - 'pipe_rd' => $CHILD_rd, - ); - - $child = \%child_hash; - $busy_child{$$child{'pid'}} = $child; - return $child; - } +sub encrypt_msg { + my ($msg, $key) = @_; + my $my_cipher = &create_ciphering($key); + { + use bytes; + $msg = "\0"x(16-length($msg)%16).$msg; } + $msg = $my_cipher->encrypt($msg); + chomp($msg = &encode_base64($msg)); + # there are no newlines allowed inside msg + $msg=~ s/\n//g; + return $msg; } -#=== FUNCTION ================================================================ -# NAME: open_socket -# PARAMETERS: PeerAddr string something like 192.168.1.1 or 192.168.1.1:10000 -# [PeerPort] string necessary if port not appended by PeerAddr -# RETURNS: socket IO::Socket::INET -# DESCRIPTION: open a socket to PeerAddr -#=============================================================================== -sub open_socket { - my ($PeerAddr, $PeerPort) = @_ ; - if(defined($PeerPort)){ - $PeerAddr = $PeerAddr.":".$PeerPort; - } - my $socket; - $socket = new IO::Socket::INET(PeerAddr => $PeerAddr, - Porto => "tcp", - Type => SOCK_STREAM, - Timeout => 5, - ); - if(not defined $socket) { - return; - } - &daemon_log("open_socket: $PeerAddr", 7); - return $socket; + +sub decrypt_msg { + my ($msg, $key) = @_ ; + $msg = &decode_base64($msg); + my $my_cipher = &create_ciphering($key); + $msg = $my_cipher->decrypt($msg); + $msg =~ s/\0*//g; + return $msg; } @@ -583,220 +507,215 @@ sub send_msg_to_target { #=== FUNCTION ================================================================ -# NAME: process_incoming_msg -# PARAMETERS: crypted_msg - string - incoming crypted message -# RETURNS: nothing -# DESCRIPTION: handels the proceeded distribution to the appropriated functions +# NAME: open_socket +# PARAMETERS: PeerAddr string something like 192.168.1.1 or 192.168.1.1:10000 +# [PeerPort] string necessary if port not appended by PeerAddr +# RETURNS: socket IO::Socket::INET +# DESCRIPTION: open a socket to PeerAddr #=============================================================================== -sub process_incoming_msg { - my ($crypted_msg) = @_; - if(not defined $crypted_msg) { - daemon_log("function 'process_incoming_msg': got no msg", 7); +sub open_socket { + my ($PeerAddr, $PeerPort) = @_ ; + if(defined($PeerPort)){ + $PeerAddr = $PeerAddr.":".$PeerPort; + } + my $socket; + $socket = new IO::Socket::INET(PeerAddr => $PeerAddr, + Porto => "tcp", + Type => SOCK_STREAM, + Timeout => 5, + ); + if(not defined $socket) { return; } - $crypted_msg =~ /^([\s\S]*?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)$/; - $crypted_msg = $1; - my $host = sprintf("%s.%s.%s.%s", $2, $3, $4, $5); + &daemon_log("open_socket: $PeerAddr", 7); + return $socket; +} + + +sub check_key_and_xml_validity { + my ($crypted_msg, $module_key) = @_; +#print STDERR "crypted_msg:$crypted_msg\n"; +#print STDERR "modul_key:$module_key\n"; my $msg; my $msg_hash; - my $host_name; - my $host_key; - - # check wether incoming msg is a new msg - $host_name = $bus_address; - $host_key = $bus_key; - daemon_log("process_incoming_msg: host_name: $host_name", 7); - daemon_log("process_incoming_msg: host_key: $host_key", 7); eval{ - $msg = &decrypt_msg($crypted_msg, $host_key); - $msg_hash = &transform_msg2hash($msg); + $msg = &decrypt_msg($crypted_msg, $module_key); + &main::daemon_log("decrypted_msg: \n$msg", 8); + + $msg_hash = $xml->XMLin($msg, ForceArray=>1); + + # check header + my $header_l = $msg_hash->{'header'}; + if( 1 != @{$header_l} ) { + die 'no or more headers specified'; + } + my $header = @{$header_l}[0]; + if( 0 == length $header) { + die 'header has length 0'; + } + + # check source + my $source_l = $msg_hash->{'source'}; + if( 1 != @{$source_l} ) { + die 'no or more sources specified'; + } + my $source = @{$source_l}[0]; + if( 0 == length $source) { + die 'source has length 0'; + } + + # check target + my $target_l = $msg_hash->{'target'}; + if( 1 != @{$target_l} ) { + die 'no or more targets specified '; + } + my $target = @{$target_l}[0]; + if( 0 == length $target) { + die 'target has length 0 '; + } + }; if($@) { - daemon_log("process_incoming_msg: deciphering raise error", 7); - daemon_log("$@", 8); - $msg = undef; - $msg_hash = undef; - $host_name = undef; - $host_key = undef; + &main::daemon_log("WARNING: do not understand the message or msg is not gosa-si envelope conform:", 5); + &main::daemon_log("$@", 8); } - # check wether incoming msg is from a bus_known_server - if( not defined $msg ) { - my $sql_statement= "SELECT * FROM bus_known_server"; - my $query_res = $bus_known_server_db->select_dbentry( $sql_statement ); - while( my ($hit_num, $hit) = each %{ $query_res } ) { - $host_name = $hit->{hostname}; - if( not $host_name =~ "^$host") { - next; - } - $host_key = $hit->{hostkey}; - daemon_log("process_incoming_msg: host_name: $host_name", 7); - daemon_log("process_incoming_msg: host_key: $host_key", 7); - eval{ - $msg = &decrypt_msg($crypted_msg, $host_key); - $msg_hash = &transform_msg2hash($msg); - }; - if($@) { - daemon_log("process_incoming_msg: deciphering raise error", 7); - daemon_log("$@", 8); - $msg = undef; - $msg_hash = undef; - $host_name = undef; - $host_key = undef; - } else { - last; - } - } - } + return ($msg, $msg_hash); +} - if( not defined $msg ) { - daemon_log("WARNING: bus does not understand the message:", 5); - return; - } - # process incoming msg - my $header = @{$msg_hash->{header}}[0]; - my $source = @{$msg_hash->{source}}[0]; +sub input_from_new_server { + no strict "refs"; + my ($input) = @_ ; + my ($msg, $msg_hash); - daemon_log("header from msg: $header", 1); - daemon_log("msg to process:", 5); - daemon_log($msg, 5); + daemon_log("bus_known_server host_name: new host", 7); + daemon_log("bus_known_server host_key: $bus_key", 7); - my @targets = @{$msg_hash->{target}}; - my $len_targets = @targets; + # check if module can open msg envelope with key + ($msg, $msg_hash) = &check_key_and_xml_validity($input, $bus_key); - if ($len_targets == 0){ - daemon_log("ERROR: no target specified for msg $header", 1); + if( (!$msg) || (!$msg_hash) ) { + daemon_log("Incoming message is not from a new gosa-si-server", 5); + } - } elsif ($len_targets == 1){ - # we have only one target symbol - my $target = $targets[0]; - daemon_log("msg is for: $target", 7); + return ($msg, $msg_hash); +} - if($target eq $bus_address) { - # msg is for bus - if($header eq 'here_i_am'){ &here_i_am($msg_hash)} - elsif($header eq 'confirm_new_passwd'){ &confirm_new_passwd($msg_hash)} - elsif($header eq 'got_ping') { &got_ping($msg_hash)} - elsif($header eq 'ping') { &ping($msg_hash)} - elsif($header eq 'who_has') { &who_has($msg_hash)} - elsif($header eq 'new_client') { &new_client($msg_hash)} - elsif($header eq 'delete_client') { &delete_client($msg_hash)} - - } elsif ($target eq "*"){ - # msg is for all server - my $sql_statement= "SELECT * FROM known_server"; - my $query_res = $bus_known_server_db->select_dbentry( $sql_statement ); - while( my ($hit_num, $hit) = each %{ $query_res } ) { - $host_name = $hit->{hostname}; - $host_key = $hit->{hostkey}; - $msg_hash->{target} = [$host_name]; - &send_msg_hash2address($msg_hash, $host_name, $host_key); - } - return; + +sub input_from_known_server { + my ($input, $remote_ip) = @_ ; + my ($msg, $msg_hash); + + my $sql_statement= "SELECT * FROM bus_known_server"; + my $query_res = $bus_known_server_db->select_dbentry( $sql_statement ); + + while( my ($hit_num, $hit) = each %{ $query_res } ) { + my $host_name = $hit->{hostname}; + if( not $host_name =~ "^$remote_ip") { + next; } + my $host_key = $hit->{hostkey}; + daemon_log("bus_known_server host_name: $host_name", 7); + daemon_log("bus_known_server host_key: $host_key", 7); - } else { - # a list of targets is specified - my $target_address; - foreach $target_address (@targets) { - - my $sql_statement= "SELECT * FROM known_server WHERE hostname='$target_address'"; - my $query_res = $bus_known_server_db->select_dbentry( $sql_statement ); - if( 1 == keys %{$query_res} ) { - $host_key = $query_res->{1}->{hostkey}; - &send_msg_hash2address($msg_hash, $target_address, $host_key); - next; - - } else { - my $sql_statement= "SELECT * FROM known_server"; - $query_res = $bus_known_server_db->select_dbentry( $sql_statement ); - while( my ($hit_num, $hit) = each %{$query_res} ) { - my $host_name = $hit->{hostname}; - my $host_key = $hit->{hostkey}; - my $clients = $hit->{clients}; - my @clients = split(/,/, $clients); - foreach my $client (@clients) { - if( not $client eq $target_address ) { - next; - } - $msg_hash->{target} = [ $target_address ]; - &send_msg_hash2address($msg_hash, $host_name, $host_key); - daemon_log("bus forwards msg $header for client $target_address to server $host_name", 3); - last; - } - } - } + # check if module can open msg envelope with module key + my ($tmp_msg, $tmp_msg_hash) = &check_key_and_xml_validity($input, $host_key); + if( (!$tmp_msg) || (!$tmp_msg_hash) ) { + next; + } + else { + $msg = $tmp_msg; + $msg_hash = $tmp_msg_hash; + last; } } + if( (!$msg) || (!$msg_hash) ) { + daemon_log("Incoming message is not from a known gosa-si-server", 5); + } + + return ($msg, $msg_hash); +} + + +sub _start { + my $kernel = $_[KERNEL]; + $kernel->alias_set('gosa_si_bus_session'); return; } +sub _default { + daemon_log("ERROR: can not handle incoming msg with header '$_[ARG0]'", 1); + return; +} -#=== FUNCTION ================================================================ -# NAME: create_passwd -# PARAMETERS: nothing -# RETURNS: new_passwd - string -# DESCRIPTION: creates a 32 bit long random passwd out of "a".."z","A".."Z",0..9 -#=============================================================================== -sub create_passwd { - my $new_passwd = ""; - for(my $i=0; $i<31; $i++) { - $new_passwd .= ("a".."z","A".."Z",0..9)[int(rand(62))] +sub bus_input { + my ($kernel, $heap, $input, $wheel, $session) = @_[KERNEL, HEAP, ARG0, ARG1, SESSION]; + my ($msg, $msg_hash); + my $error = 0; + + daemon_log("Incoming msg:\n$input\n", 8); + + # msg is from a new gosa-si-server + ($msg, $msg_hash) = &input_from_new_server($input); + + # msg is from a gosa-si-server or gosa-si-bus + if(( !$msg ) || ( !$msg_hash ) ){ + ($msg, $msg_hash) = &input_from_known_server($input, $heap->{'remote_ip'}); } - return $new_passwd; -} + # an error occurred + if(( !$msg ) || ( !$msg_hash )){ + $error++; + } + if( $error == 0) { + my @target_l = @{$msg_hash->{'target'}}; + my $source = @{$msg_hash->{'source'}}[0]; + my $header = @{$msg_hash->{header}}[0]; + if( 1 == length(@target_l) && $target_l[0] eq $bus_address ) { + # msg is for bus + $kernel->post('gosa_si_bus_session', $header, $msg, $msg_hash); + } + else { + # msg is for someone else, deliver it + print STDERR "msg is for someone else\n"; + foreach my $target (@target_l) { + print STDERR "target: $target\n"; + if( $target =~ /(\d{3}\.\d{3}\.\d{3}\.\d{3}:\d+)/ ) { + # target is a ip address + my $sql_statement = "SELECT * FROM bus_known_server WHERE hostname='$target'"; + my $sql_statement = "SELECT * FROM bus_known_clients WHERE hostname='$target'"; + } + elsif( $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})/ ) { + # target is a mac address + my $sql_statement = "SELECT registerd FROM bus_known_clients WHERE macaddress='$target'"; + my $query_res = $bus_known_clients_db->select_dbentry( $sql_statement ); + print Dumper $query_res; + + } + else { -#=== FUNCTION ================================================================ -# NAME: read_from_socket -# PARAMETERS: socket - fh - filehandel to read from -# RETURNS: result - string - readed characters from socket -# DESCRIPTION: reads data from socket in 16 byte steps -#=============================================================================== -sub read_from_socket { - my ($socket) = @_; - - $socket->blocking(1); - my $result = <$socket>; - $socket->blocking(0); - my $part_msg; - while ($part_msg = <$socket>) { - if (not defined $part_msg) { last; } - $result .= $part_msg; + } + + } + } } - - #my $result = ""; - #my $len = 16; - #while($len == 16){ - # my $char; - # $len = sysread($socket, $char, 16); - # if($len != 16) { last } - # if($len != 16) { last } - # $result .= $char; - #} - return $result; } -#=== FUNCTION ================================================================ -# NAME: here_i_am -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process the incoming msg 'here_i_am' -#=============================================================================== sub here_i_am { - my ($msg_hash) = @_ ; - my $source = @{$msg_hash->{source}}[0];; + my ( $msg, $msg_hash ) = @_[ ARG0, ARG1 ]; + my $source = @{$msg_hash->{'source'}}[0]; + my $target = @{$msg_hash->{'target'}}[0]; my $new_key = &create_passwd(); @@ -807,12 +726,11 @@ sub here_i_am { hostname=>$source, status=>"registered", hostkey=>$bus_key, - clients=>"", }; $bus_known_server_db->add_dbentry($add_hash); # create outgoing msg - my $out_hash = &create_xml_hash("new_key", $bus_address, $source, $new_key); + my $out_hash = &create_xml_hash("new_key", $target, $source, $new_key); &send_msg_hash2address($out_hash, $source, $bus_key); # change hostkey, reason @@ -820,109 +738,41 @@ sub here_i_am { my $update_str= " SET hostkey='$new_key'"; my $sql_statement= "UPDATE bus_known_server $update_str $where_str"; $bus_known_server_db->update_dbentry($sql_statement); - - return; } -#=== FUNCTION ================================================================ -# NAME: confirm_new_passwd -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub confirm_new_passwd { - my ($msg_hash) = @_ ; - my $source = @{$msg_hash->{source}}[0]; - my $sql_statement= "UPDATE bus_known_server ". - "SET status='key_confirmed' ". - "WHERE hostname='$source' "; - - $bus_known_server_db->update_dbentry($sql_statement); - - return; +sub confirm_new_key { + my ( $msg, $msg_hash ) = @_[ ARG0, ARG1 ]; + my $source = @{$msg_hash->{'source'}}[0]; + daemon_log("'$source' confirms new key", 3); } -#=== FUNCTION ================================================================ -# NAME: ping -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub ping { - my ($msg_hash) = @_ ; - my $header = @{$msg_hash->{header}}[0]; - my $source = @{$msg_hash->{source}}[0]; - - my $sql_statement= "UPDATE bus_known_server SET status='$header' WHERE hostname='$source'"; - $bus_known_server_db->update_dbentry($sql_statement); +sub new_client { + my ($msg, $msg_hash) = @_[ ARG0, ARG1 ]; - my $out_hash = &create_xml_hash("got_ping", $bus_address, $source); + my $new_client = @{$msg_hash->{'new_client'}}[0]; + my $source = @{$msg_hash->{'source'}}[0]; + my $mac_address = @{$msg_hash->{'macaddress'}}[0]; + my $act_timestamp = @{$msg_hash->{'timestamp'}}[0]; - $sql_statement= "SELECT * FROM bus_known_server WHERE hostname='$source'"; - my $res = $bus_known_server_db->select_dbentry( $sql_statement ); - my $hostkey = $res->{1}->{hostkey}; - &send_msg_hash2address($out_hash, $source, $hostkey); - - return; + my $add_hash = { + table => "bus_known_clients", + primkey=>"hostname", + hostname=>$new_client, + status=>'activ', + registered=>$source, + macaddress=>$mac_address, + timestamp=>$act_timestamp, + }; + $bus_known_clients_db->add_dbentry($add_hash); } -#=== FUNCTION ================================================================ -# NAME: got_ping -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub got_ping { - my ($msg_hash) = @_; - my $source = @{$msg_hash->{source}}[0]; - - my $sql_statement= "UPDATE bus_known_server SET status='got_ping' WHERE hostname='$source'"; - $bus_known_server_db->update_dbentry($sql_statement); - - return; -} - - -#=== FUNCTION ================================================================ -# NAME: new_client -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub new_client { - my ($msg_hash) = @_ ; - my $source = @{$msg_hash->{source}}[0]; - my $header = @{$msg_hash->{header}}[0]; - my $new_client = @{$msg_hash->{$header}}[0]; - - my $sql_statement= "SELECT * FROM bus_known_server WHERE hostname='$source'"; - my $res = $bus_known_server_db->select_dbentry( $sql_statement ); - my $clients = $res->{1}->{clients}; - - # if host has alread more clients, than just append - my @clients_l = split(',', $clients); - my @new_clients_l; - foreach my $act_client (@clients_l) { - if( $new_client eq $act_client ) { - # do nothing - next; - } - push(@new_clients_l, $act_client); - } - push(@new_clients_l, $new_client); - $clients = join(",", @new_clients_l); - - $sql_statement= "UPDATE bus_known_server SET clients='$clients' WHERE hostname='$source'"; - $bus_known_server_db->update_dbentry( $sql_statement ); - return; -} - #==== MAIN = main ============================================================== + # parse commandline options Getopt::Long::Configure( "bundling" ); GetOptions("h|help" => \&usage, @@ -938,27 +788,22 @@ GetOptions("h|help" => \&usage, $SIG{CHLD} = 'IGNORE'; -# restart daemon log file -if(-e $log_file ) { unlink $log_file } -daemon_log(" ", 1); -daemon_log("$0 started!", 1); - -# delete old DBsqlite lock files -system('rm -f /tmp/gosa_si_lock*'); # forward error messages to logfile -if( ! $foreground ) { - open(STDERR, '>>', $log_file); - open(STDOUT, '>>', $log_file); +if ( ! $foreground ) { + open STDIN, '/dev/null' or die "Can’t read /dev/null: $!"; + open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!"; + open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!"; } -# Just fork, if we"re not in foreground mode -if( ! $foreground ) { - chdir '/' or die "Can't chdir to /: $!"; - $pid = fork; - setsid or die "Can't start a new session: $!"; - umask 0; -} else { +# Just fork, if we are not in foreground mode +if( ! $foreground ) { + chdir '/' or die "Can't chdir to /: $!"; + $pid = fork; + setsid or die "Can't start a new session: $!"; + umask 0; +} +else { $pid = $$; } @@ -967,79 +812,56 @@ if( 0 != $pid ) { open( LOCK_FILE, ">$pid_file" ); print LOCK_FILE "$pid\n"; close( LOCK_FILE ); - if( ! $foreground ) { exit( 0 ) }; + if( !$foreground ) { + exit( 0 ) + }; } -# connect to bus_known_server_db -my @server_col_names = ('hostname', 'status', 'hostkey', 'timestamp', 'clients' ); -$bus_known_server_db = GOSA::DBsqlite->new($bus_known_server_file_name); -$bus_known_server_db->create_table('bus_known_server', \@server_col_names); - - -# detect own ip and mac address -$network_interface= &get_interface_for_ip($bus_ip); -$bus_mac_address= &get_mac($network_interface); -daemon_log("bus ip address detected: $bus_ip", 1); -daemon_log("bus mac address detected: $bus_mac_address", 1); - -# complete addresses -$bus_address = "$bus_ip:$bus_port"; +# restart daemon log file +if(-e $log_file ) { unlink $log_file } +daemon_log(" ", 1); +daemon_log("started!", 1); -# setup xml parser -$xml = new XML::Simple(); +# delete old DBsqlite lock files +system('rm -f /tmp/gosa_si_lock*gosa-si-bus*'); -# create cipher object -$bus_cipher = &create_ciphering($bus_key); +#prepare other variables +$xml = new XML::Simple(); $bus_address = "$bus_ip:$bus_port"; -# create reading and writing vectors -my $rbits = my $wbits = my $ebits = ""; - -# open the bus socket -if($bus_activ eq "on") { - daemon_log(" ", 1); - $bus = IO::Socket::INET->new(LocalPort => $bus_port, - Type => SOCK_STREAM, - Reuse => 1, - Listen => 20, - ) or die "kann kein TCP-Server an Port $bus_port sein: $@\n"; - vec($rbits, fileno $bus, 1) = 1; - vec($wbits, fileno $bus, 1) = 1; - daemon_log ("start bus at $bus_ip:$bus_port", 1); -} - -# add bus to known_daemons - -#&create_known_daemons_entry($bus_address); -#&update_known_daemons_entry(hostname=>$bus_address, status=>"bus", passwd=>$bus_key); - - -while(1) { - my $nf = select($rbits, $wbits, undef, undef); - # error handling - if($nf < 0 ) { - } - - # something is coming in - if(vec $rbits, fileno $bus, 1 ) { - my $client = $bus->accept(); - my $other_end = getpeername($client); - if(not defined $other_end) { - daemon_log("Gegenstelle konnte nicht identifiziert werden: $!\n"); - } else { - my ($port, $iaddr) = unpack_sockaddr_in($other_end); - my $actual_ip = inet_ntoa($iaddr); - daemon_log("\naccept client from $actual_ip\n", 5); - my $in_msg = &read_from_socket($client); - if(defined $in_msg){ - &activating_child($in_msg, $actual_ip); - } else { - daemon_log("cannot read from $actual_ip\n",1); - } - } - close($client); - } - -} +# detect ip and mac address and complete host address +my $network_interface= &get_interface_for_ip($bus_ip); +$bus_mac_address= &get_mac($network_interface); +daemon_log("gosa-si-bus ip address detected: $bus_ip", 1); +daemon_log("gosa-si-bus mac address detected: $bus_mac_address", 1); +# connect to bus_known_server_db +my @server_col_names = ('hostname', 'status', 'hostkey', 'timestamp'); +$bus_known_server_db = GOSA::DBsqlite->new($bus_known_server_file_name); +$bus_known_server_db->create_table('bus_known_server', \@server_col_names); +my @clients_col_names = ('hostname', 'status', 'registered', 'macaddress', 'timestamp'); +$bus_known_clients_db = GOSA::DBsqlite->new($bus_known_clients_file_name); +$bus_known_clients_db->create_table('bus_known_clients', \@clients_col_names); + +# create socket for incoming xml messages +POE::Component::Server::TCP->new( + Alias => 'gosa-si-bus_socket', + Port => $bus_port, + ClientInput => \&bus_input, +); +daemon_log("start socket for incoming xml messages at port '$bus_port' ", 1); + +# start session +POE::Session->create( + inline_states => { + _start => \&_start, + _default => \&_default, + here_i_am => \&here_i_am, + confirm_new_passwd => \&confirm_new_key, + new_client => \&new_client, + } +); + +POE::Kernel->run(); +exit; diff --git a/gosa-si/gosa-si-client b/gosa-si/gosa-si-client index c11fb7679..2977f620f 100755 --- a/gosa-si/gosa-si-client +++ b/gosa-si/gosa-si-client @@ -1095,12 +1095,8 @@ daemon_log("$0 started!", 1); # delete old DBsqlite lock files system('rm -f /tmp/gosa_si_lock*gosa-si-client*'); - -# complete client_address +# detect ip and mac address and complete host address $client_address = $client_ip.":".$client_port; - - -# detect own ip and mac address my $network_interface= &get_interface_for_ip($client_ip); $client_mac_address= &get_mac($network_interface); daemon_log("gosa-si-client ip address detected: $client_ip", 1); diff --git a/gosa-si/tests/client.php b/gosa-si/tests/client.php index 40df353ea..fba6de2ae 100755 --- a/gosa-si/tests/client.php +++ b/gosa-si/tests/client.php @@ -41,12 +41,13 @@ if($sock->connected()){ # set gosa-si-client to 'activated' #$data = "
gosa_set_activated_for_installation
10.89.1.31:20083 127.0.0.1:20081
"; -$data = "
gosa_detect_hardware
10.89.1.31:20083 10.89.1.31:20081
"; +#$data = "
gosa_detect_hardware
10.89.1.31:20083 10.89.1.31:20081
"; #$data = "
gosa_reboot
10.89.1.31:20083 10.89.1.31:20081
"; #$data = "
gosa_reinstall
10.89.1.31:20083 10.89.1.31:20081
"; #$data = "
gosa_softupdate
10.89.1.31:20083 10.89.1.31:20081
"; #$data = "
gosa_halt
10.89.1.31:20083 10.89.1.31:20081
"; #$data = "
gosa_new_key_for_client
00:01:6c:9d:b9:fa 10.89.1.31:20081
"; +$data = "
gosa_new_key_for_client
00:01:6c:9d:b9:fb 10.89.1.31:20081
"; $sock->write($data); diff --git a/gosa-si/tests/sqlite-check.pl b/gosa-si/tests/sqlite-check.pl index 94d19847f..a6b1bd953 100755 --- a/gosa-si/tests/sqlite-check.pl +++ b/gosa-si/tests/sqlite-check.pl @@ -91,6 +91,19 @@ if (-e $db_name) { print $answer."\n"; } - +$db_name = "/var/lib/gosa-si/gosa-si-bus_known_clients.db"; +if (-e $db_name) { + print "\n############################################################\n"; +# $db_name =~ /\/([^\/]*?)\.db$/; +# my $table_name = $1; + my $table_name = "bus_known_clients"; + print "$db_name\n"; + print "$table_name\n"; + my $sqlite = GOSA::DBsqlite->new($db_name); + my $col_names = $sqlite->get_table_columns($table_name); + print join(', ', @{ $col_names } )."\n" ; + my $answer = $sqlite->show_table($table_name); + print $answer."\n"; +} print "\nFINISH\n"; -- 2.30.2