From: cajus Date: Mon, 21 Jan 2008 08:05:58 +0000 (+0000) Subject: Moved to gosa-si X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=1c930804a95583769c4379a23884a399b379ca34;p=gosa.git Moved to gosa-si git-svn-id: https://oss.gonicus.de/repositories/gosa/trunk@8510 594d385d-05f5-0310-b6e9-bd551577e9d8 --- diff --git a/gosa-si-poe/README b/gosa-si-poe/README deleted file mode 100644 index e8c755530..000000000 --- a/gosa-si-poe/README +++ /dev/null @@ -1,29 +0,0 @@ - -/usr/share/perl5/GOSA -common: -- GosaSupportDaemon.pm -- DBsqlite.pm - -/usr/lib/gosa-si/modules -server-module: -- ArpPackages.pm -- GosaPackages.pm -- ServerPackages.pm -- FAIPackages.pm - -server-events: -/usr/lib/gosa-si/server -- ping - -client-events: -/usr/lib/gosa-si/client - -config-files: /etc/gosa-si/ -- bus.conf -- client.conf -- server.conf - -/var/lib/gosa-si -db's: -- jobs.db - diff --git a/gosa-si-poe/arp-handler-d b/gosa-si-poe/arp-handler-d deleted file mode 100755 index b8698bcf7..000000000 --- a/gosa-si-poe/arp-handler-d +++ /dev/null @@ -1,563 +0,0 @@ -#!/usr/bin/perl -#=============================================================================== -# -# FILE: gosa-support-daemon.pl -# -# USAGE: ./.gosa-support-daemon.pl -# -# DESCRIPTION: -# -# OPTIONS: --- -# REQUIREMENTS: --- -# BUGS: --- -# NOTES: --- -# AUTHOR: Andreas Rettenberger, -# COMPANY: Gonicus GmbH, Arnsberg -# VERSION: 1.0 -# CREATED: 21.08.2007 15:13:51 CEST -# REVISION: --- -#=============================================================================== - -use strict; -use warnings; -use Getopt::Long; -use Config::IniFiles; -use POSIX; -use Fcntl; -use Net::LDAP; -use Net::LDAP::LDIF; -use Net::LDAP::Entry; -use Switch; - - -my ($verbose, $cfg_file, $log_file, $pid_file, $foreground); -my ($timeout, $mailto, $mailfrom, $user, $group); -my ($procid, $pid, $loglevel); -my ($fifo_path, $max_process_timeout, $max_process ); -my %daemon_children; -my ($ldap, $bind_phrase, $password, $ldap_base) ; - -$procid = -1 ; -$foreground = 0 ; -$verbose = 0 ; -$max_process = 2 ; -$max_process_timeout = 1 ; -$ldap_base = "dc=gonicus,dc=de" ; -#$ldap_path = "/var/run/gosa-support-daemon.socket"; -#$log_path = "/var/log/gosa-support-daemon.log"; -#$pid_path = "/var/run/gosa-support-daemon/gosa-support-daemon.pid"; - -#--------------------------------------------------------------------------- -# parse commandline options -#--------------------------------------------------------------------------- -Getopt::Long::Configure( "bundling" ); -GetOptions( "v|verbose+" => \$verbose, - "c|config=s" => \$cfg_file, - "h|help" => \&usage, - "l|logfile=s" => \$log_file, - "p|pid=s" => \$pid_file, - "f|foreground" => \$foreground); - -#--------------------------------------------------------------------------- -# read and set config parameters -#--------------------------------------------------------------------------- -my %cfg_defaults = -("Allgemein" => - {"timeout" => [ \$timeout, 1000 ], - "mailto" => [ \$mailto, 'root@localhost' ], - "mailfrom" => [ \$mailfrom, 'sps-daemon@localhost' ], - "user" => [ \$user, "nobody" ], - "group" => [ \$group, "nogroup" ], - "fifo_path" => [ \$fifo_path, "/home/rettenbe/gonicus/gosa-support/tmp/fifo" ], - "log_file" => [ \$log_file, "/home/rettenbe/gonicus/gosa-support/tmp/gosa-support.log" ], - "pid_file" => [ \$pid_file, "/home/rettenbe/gonicus/gosa-support/tmp/gosa-support.pid" ], - "loglevel" => [ \$loglevel, 1] - }, -"LDAP" => - {"bind" => [ \$bind_phrase, "cn=ldapadmin,dc=gonicus,dc=de" ], - "password" => [ \$password, "tester" ], - } - ); -&read_configfile; - - -#=== FUNCTION ================================================================ -# NAME: check_cmdline_param -# PURPOSE: checks all commandline parameters to validity -# PARAMETERS: none -# RETURNS: none -# DESCRIPTION: ???? -# THROWS: no exceptions -# COMMENTS: none -# SEE ALSO: n/a -#=============================================================================== -sub check_cmdline_param () { - my $err_config; - my $err_log; - my $err_pid; - my $err_counter = 0; - if( not defined( $cfg_file)) { - $err_config = "please specify a config file"; - $err_counter += 1; - } - if( not defined( $log_file)) { - $err_log = "please specify a log file"; - $err_counter += 1; - } - if( not defined( $pid_file)) { - $err_pid = "please specify a pid file"; - $err_counter += 1; - } - if( $err_counter > 0 ) { - &usage( "", 1 ); - if( defined( $err_config)) { print STDERR "$err_config\n"} - if( defined( $err_log)) { print STDERR "$err_log\n" } - if( defined( $err_pid)) { print STDERR "$err_pid\n"} - print STDERR "\n"; - exit( -1 ); - } -} - -#=== FUNCTION ================================================================ -# NAME: check_pid -# PURPOSE: -# PARAMETERS: none -# RETURNS: none -# DESCRIPTION: ???? -# THROWS: no exceptions -# COMMENTS: none -# SEE ALSO: n/a -#=============================================================================== -sub check_pid { - if( open( LOCK_FILE, "<$pid_file") ) { - $procid = ; - if( defined $procid ) { - chomp( $procid ); - if( -f "/proc/$procid/stat" ) { - my($stat) = `cat /proc/$procid/stat` =~ m/$procid \((.+)\).*/; - print "\t".$stat."\n"; - if( "sps-daemon.pl" eq $stat ) { - close( LOCK_FILE ); - exit -1; - } - } - } - close( LOCK_FILE ); - unlink( $pid_file ); - } - - # Try to open PID file - if (!sysopen(LOCK_FILE, $pid_file, O_WRONLY|O_CREAT|O_EXCL, 0644)) { - my($msg) = "Couldn't obtain lockfile '$pid_file' "; - if (open(LOCK_FILE, "<", $pid_file) && ($pid = )) { - chomp($pid); - $msg .= "(PID $pid)\n"; - } else { - $msg .= "(unable to read PID)\n"; - } - if ( ! $foreground ) { - daemon_log( $msg."\n"); - } else { - print( STDERR " $msg " ); - } - exit( -1 ); - } -} - -#=== FUNCTION ================================================================ -# NAME: read_configfile -# PURPOSE: read the configuration file and provide the programm with -# parameters -# PARAMETERS: none -# RETURNS: none -# DESCRIPTION: ???? -# THROWS: no exceptions -# COMMENTS: none -# SEE ALSO: n/a -#=============================================================================== -sub read_configfile { - my $log_time = localtime(time); - my $cfg; - if( defined( $cfg_file) && ( length($cfg_file) > 0 )) { - if( -r $cfg_file ) { - $cfg = Config::IniFiles->new( -file => $cfg_file ); - } else { - usage( "Couldn't read config file: $cfg_file \n" ); - } - } else { - $cfg = Config::IniFiles->new() ; - } - - foreach my $section (keys %cfg_defaults) { # "Parse" config into values - foreach my $param (keys %{$cfg_defaults{ $section }}) { - my $pinfo = $cfg_defaults{ $section }{ $param }; - ${@$pinfo[ 0 ]} = $cfg->val( $section, $param, @$pinfo[ 1 ] ); - } - } - - if(-e $log_file ) { unlink $log_file } - daemon_log("$log_time: config file read\n"); -} - -#=== FUNCTION ================================================================ -# NAME: daemon_log -# PURPOSE: log messages to specified logfile -# PARAMETERS: $msg, $level -# RETURNS: ???? -# DESCRIPTION: Takes a message ($msg) and append it to the logfile. The -# standard log-level ($level) is 1. Messages whith higher level -# than the verbosity-level (defined by commandline) are printed -# out to commandline. Messages with log-level lower than 2 are -# not logged to logfile! -# THROWS: no exceptions -# COMMENTS: none -# SEE ALSO: n/a -#=============================================================================== -sub daemon_log { - my( $msg, $level ) = @_; - if(not defined $msg) { return } - if(not defined $level) { $level = 1 } - open(LOG_HANDLE, ">>$log_file"); - if(not defined open( LOG_HANDLE, ">>$log_file" ) ) { return } - chomp($msg); - #if( $verbose >= $level ) { print "$msg"."\n" } - if( $level <= 1 ) { print LOG_HANDLE $msg."\n" } - if( $foreground ) { print $msg."\n" } - close( LOG_HANDLE ); - } - -#=== FUNCTION ================================================================ -# NAME: signal handler -# PURPOSE: catches signals from the programm and do diffrent things -# than default -# PARAMETERS: none -# RETURNS: none -# DESCRIPTION: sighandler -# THROWS: no exceptions -# COMMENTS: none -# SEE ALSO: n/a -#=============================================================================== -sub sigINT { - my $log_time = localtime(time); - print "INT\n"; - if( -p $fifo_path ) { - close FIFO ; - unlink($fifo_path) ; - daemon_log( "$log_time: FIFO closed after signal INT!\n") ; - } - if(defined($ldap)) { - $ldap->unbind; - } - $SIG{INT} = "DEFAULT" ; - kill INT => $$ ; -} -$SIG{INT} = \&sigINT ; - -#=== FUNCTION ================================================================ -# NAME: usage -# PURPOSE: -# PARAMETERS: none -# RETURNS: none -# DESCRIPTION: print out the usage of the program -# THROWS: no exceptions -# COMMENTS: none -# SEE ALSO: n/a -#=============================================================================== -sub usage { - my( $text, $help ) = @_; - $text = undef if( "h" eq $text ); - (defined $text) && print STDERR "\n$text\n"; - if( (defined $help && $help) || (!defined $help && !defined $text) ) { - print STDERR << "EOF" ; -usage: $0 [-hvf] [-c config, -l logfile, -p pidfile] - - -h : this (help) message - -c : config file - -l : log file (example: /var/log/sps/sps.log) - -p : pid file (example: /var/run/sps/sps.pid) - -f : foreground (don"t fork) - -v : be verbose (multiple to increase verbosity) -EOF - } - print "\n" ; -} - - -#=== FUNCTION ================================================================ -# NAME: open_fifo -# PURPOSE: -# PARAMETERS: $fifo_path -# RETURNS: 0: FIFO couldn"t be setup, 1: FIFO setup correctly -# DESCRIPTION: creates a FIFO at $fifo_path -# THROWS: no exceptions -# COMMENTS: none -# SEE ALSO: n/a -#=============================================================================== -sub open_fifo { - my ($fifo_path) = @_ ; - my $log_time = localtime( time ); - if( -p $fifo_path ) { - daemon_log("$log_time: FIFO at $fifo_path already exists\n"); - return 0; - } - POSIX::mkfifo($fifo_path, 0666) or die "can't mkfifo $fifo_path: $!"; - daemon_log( "$log_time: FIFO started at $fifo_path\n" ) ; - return 1; - } - - -#=== FUNCTION ================================================================ -# NAME: add_ldap_entry -# PURPOSE: adds an element to ldap-tree -# PARAMETERS: -# RETURNS: none -# DESCRIPTION: ???? -# THROWS: no exceptions -# COMMENTS: none -# SEE ALSO: n/a -#=============================================================================== -sub add_ldap_entry { - my ($ldap_tree, $ldap_base, $mac, $gotoSysStatus, $ip, $interface, $desc) = @_; - my $dn = "cn=$mac,ou=incoming,$ldap_base"; - my $s_res = &search_ldap_entry($ldap_tree, $ldap_base, "(|(macAddress=$mac)(dhcpHWAddress=ethernet $mac))"); - my $c_res = $s_res->count; - if($c_res == 1) { - daemon_log("WARNING: macAddress $mac already in LDAP", 1); - return; - } elsif($c_res > 0) { - daemon_log("ERROR: macAddress $mac exists $c_res times in LDAP", 1); - return; - } - - # create LDAP entry - my $entry = Net::LDAP::Entry->new( $dn ); - $entry->dn($dn); - $entry->add("objectClass" => "goHard"); - $entry->add("cn" => $mac); - $entry->add("macAddress" => $mac); - if(defined $gotoSysStatus) {$entry->add("gotoSysStatus" => $gotoSysStatus)} - if(defined $ip) {$entry->add("ipHostNumber" => $ip) } - #if(defined $interface) { } - if(defined $desc) {$entry->add("description" => $desc) } - - # submit entry to LDAP - my $result = $entry->update ($ldap_tree); - - # for $result->code constants please look at Net::LDAP::Constant - my $log_time = localtime( time ); - if($result->code == 68) { # entry already exists - daemon_log("WARNING: $log_time: $dn ".$result->error, 3); - } elsif($result->code == 0) { # everything went fine - daemon_log("$log_time: add entry $dn to ldap", 1); - } else { # if any other error occur - daemon_log("ERROR: $log_time: $dn, ".$result->code.", ".$result->error, 1); - } - return; -} - - -#=== FUNCTION ================================================================ -# NAME: change_ldap_entry -# PURPOSE: ???? -# PARAMETERS: ???? -# RETURNS: ???? -# DESCRIPTION: ???? -# THROWS: no exceptions -# COMMENTS: none -# SEE ALSO: n/a -#=============================================================================== -sub change_ldap_entry { - my ($ldap_tree, $ldap_base, $mac, $gotoSysStatus ) = @_; - - # check if ldap_entry exists or not - my $s_res = &search_ldap_entry($ldap_tree, $ldap_base, "(|(macAddress=$mac)(dhcpHWAddress=ethernet $mac))"); - my $c_res = $s_res->count; - if($c_res == 0) { - daemon_log("WARNING: macAddress $mac not in LDAP", 1); - return; - } elsif($c_res > 1) { - daemon_log("ERROR: macAddress $mac exists $c_res times in LDAP", 1); - return; - } - - my $s_res_entry = $s_res->pop_entry(); - my $dn = $s_res_entry->dn(); - my $result = $ldap->modify( $dn, replace => {'gotoSysStatus' => $gotoSysStatus } ); - - # for $result->code constants please look at Net::LDAP::Constant - my $log_time = localtime( time ); - if($result->code == 32) { # entry doesnt exists - &add_ldap_entry($mac, $gotoSysStatus); - } elsif($result->code == 0) { # everything went fine - daemon_log("$log_time: entry $dn changed successful", 1); - } else { # if any other error occur - daemon_log("ERROR: $log_time: $dn, ".$result->code.", ".$result->error, 1); - } - - return; -} - -#=== FUNCTION ================================================================ -# NAME: search_ldap_entry -# PURPOSE: ???? -# PARAMETERS: [Net::LDAP] $ldap_tree - object of an ldap-tree -# string $sub_tree - dn of the subtree the search is performed -# string $search_string - either a string or a Net::LDAP::Filter object -# RETURNS: [Net::LDAP::Search] $msg - result object of the performed search -# DESCRIPTION: ???? -# THROWS: no exceptions -# COMMENTS: none -# SEE ALSO: n/a -#=============================================================================== -sub search_ldap_entry { - my ($ldap_tree, $sub_tree, $search_string) = @_; - my $msg = $ldap_tree->search( # perform a search - base => $sub_tree, - filter => $search_string, - ) or daemon_log("cannot perform search at ldap: $@", 1); -# if(defined $msg) { -# print $sub_tree."\t".$search_string."\t"; -# print $msg->count."\n"; -# foreach my $entry ($msg->entries) { $entry->dump; }; -# } - - return $msg; -} - - - -#========= MAIN = main ======================================================== -daemon_log( "####### START DAEMON ######\n", 1 ); -&check_cmdline_param ; -&check_pid; -&open_fifo($fifo_path); - -# Just fork, if we"re not in foreground mode -if( ! $foreground ) { $pid = fork(); } -else { $pid = $$; } - -# Do something useful - put our PID into the pid_file -if( 0 != $pid ) { - open( LOCK_FILE, ">$pid_file" ); - print LOCK_FILE "$pid\n"; - close( LOCK_FILE ); - if( !$foreground ) { exit( 0 ) }; -} - - -if( not -p $fifo_path ) { die "fifo file disappeared\n" } -sysopen(FIFO, $fifo_path, O_RDONLY) or die "can't read from $fifo_path: $!" ; - -while( 1 ) { - # checke alle prozesse im hash daemon_children ob sie noch aktiv sind, wenn - # nicht, dann entferne prozess aus hash - while( (my $key, my $val) = each( %daemon_children) ) { - my $status = waitpid( $key, &WNOHANG) ; - if( $status == -1 ) { - delete $daemon_children{$key} ; - daemon_log("childprocess finished: $key", 3) ; - } - } - - # ist die max_process anzahl von prozesskindern erreicht, dann warte und - # prüfe erneut, ob in der zwischenzeit prozesse fertig geworden sind - if( keys( %daemon_children ) >= $max_process ) { - sleep($max_process_timeout) ; - next ; - } - - my $msg = ; - if( not defined( $msg )) { next ; } - - chomp( $msg ); - if( length( $msg ) == 0 ) { next ; } - - my $forked_pid = fork(); -#=== PARENT = parent ========================================================== - if ( $forked_pid != 0 ) { - daemon_log("childprocess forked: $forked_pid", 3) ; - $daemon_children{$forked_pid} = 0 ; - } -#=== CHILD = child ============================================================ - else { - # parse the incoming message from arp, split the message and return - # the values in an array. not defined values are set to "none" - #my ($mac, $ip, $interface, $arp_sig, $desc) = &parse_input( $msg ) ; - daemon_log( "childprocess read from arp: $fifo_path\nline: $msg", 3); - my ($mac, $ip, $interface, $arp_sig, $desc) = split('\s', $msg, 5); - - # create connection to LDAP - $ldap = Net::LDAP->new( "localhost" ) or die "$@"; - $ldap->bind($bind_phrase, - password => $password, - ) ; - - switch($arp_sig) { - case 0 {&change_ldap_entry($ldap, $ldap_base, - $mac, "ip-changed", - )} - case 1 {&change_ldap_entry($ldap, $ldap_base, - $mac, "mac-not-whitelisted", - )} - case 2 {&change_ldap_entry($ldap, $ldap_base, - $mac, "mac-in-blacklist", - )} - case 3 {&add_ldap_entry($ldap, $ldap_base, - $mac, "new-mac-address", $ip, - $interface, $desc, - )} - case 4 {&change_ldap_entry($ldap, $ldap_base, - $mac, "unauthorized-arp-request", - )} - case 5 {&change_ldap_entry($ldap, $ldap_base, - $mac, "abusive-number-of-arp-requests", - )} - case 6 {&change_ldap_entry($ldap, $ldap_base, - $mac, "ether-and-arp-mac-differs", - )} - case 7 {&change_ldap_entry($ldap, $ldap_base, - $mac, "flood-detected", - )} - case 8 {&add_ldap_entry($ldap, $ldap_base, - $mac, $ip, "new-system", - )} - case 9 {&change_ldap_entry($ldap, $ldap_base, - $mac, "mac-changed", - )} - } - - - # ldap search -# my $base_phrase = "dc=gonicus,dc=de"; -# my $filter_phrase = "cn=keinesorge"; -# my $attrs_phrase = "cn macAdress"; -# my $msg_search = $ldap->search( base => $base_phrase, -# filter => $filter_phrase, -# attrs => $attrs_phrase, -# ); -# $msg_search->code && die $msg_search->error; -# -# my @entries = $msg_search->entries; -# my $max = $msg_search->count; -# print "anzahl der entries: $max\n"; -# my $i; -# for ( $i = 0 ; $i < $max ; $i++ ) { -# my $entry = $msg_search->entry ( $i ); -# foreach my $attr ( $entry->attributes ) { -# if( not $attr eq "cn") { -# next; -# } -# print join( "\n ", $attr, $entry->get_value( $attr ) ), "\n\n"; -# } -# } - - # ldap add - - - $ldap->unbind; - exit; - } - -} - - diff --git a/gosa-si-poe/arp-handler-d.cfg b/gosa-si-poe/arp-handler-d.cfg deleted file mode 100644 index 36c24a35b..000000000 --- a/gosa-si-poe/arp-handler-d.cfg +++ /dev/null @@ -1,14 +0,0 @@ -[Allgemein] -timeout = 1000 -mailto = root@localhost -mailfrom = gosa-sd@localhost -user = rettenbe -group = usr -fifo_path = /home/rettenbe/gonicus/projekte/gosa-trunk/contrib/daemon/fifo -log_file = /home/rettenbe/gonicus/projekte/gosa-trunk/contrib/daemon/gosa-sd.log -pid_file = /home/rettenbe/gonicus/projekte/gosa-trunk/contrib/daemon/gosa-sd.pid -loglevel = 1 - -[LDAP] -bind = cn=ldapadmin,dc=gonicus,dc=de -password = tester diff --git a/gosa-si-poe/bus.conf b/gosa-si-poe/bus.conf deleted file mode 100644 index 7ca56e906..000000000 --- a/gosa-si-poe/bus.conf +++ /dev/null @@ -1,13 +0,0 @@ -[general] -log_file = /var/log/gosa-si-bus.log -pid_file = /var/run/gosa-si-bus.pid -child_max = 10 -child_min = 2 -child_timeout = 10 - -[bus] -bus_activ = on -bus_passwd = secret-bus-password -bus_ip = 127.0.0.1 -bus_port = 20080 - diff --git a/gosa-si-poe/client.conf b/gosa-si-poe/client.conf deleted file mode 100644 index 0c65e2cad..000000000 --- a/gosa-si-poe/client.conf +++ /dev/null @@ -1,13 +0,0 @@ -[general] -log_file = /var/log/gosa-si-client.log -pid_file = /var/run/gosa-si-client.pid - -[client] -client_port = 20083 - -[server] -server_ip = 127.0.0.1 -server_port = 20081 -server_passwd = secret-server-password -server_timeout = 5 -server_domain = intranet.gonicus.de diff --git a/gosa-si-poe/debian/README.debian b/gosa-si-poe/debian/README.debian deleted file mode 100644 index 100bd2d6d..000000000 --- a/gosa-si-poe/debian/README.debian +++ /dev/null @@ -1,11 +0,0 @@ -README.Debian for GOto 3.0 --------------------------- - -* Configuring GOto 3.0 - -You need a proper LDAP/FAI/GOsa setup to make this run. More -text will follow later. Sorry. - ----- -Cajus Pollmeier Fri 02 Jun 2006 16:23:50 +0200 - diff --git a/gosa-si-poe/debian/changelog b/gosa-si-poe/debian/changelog deleted file mode 100644 index 5412238b3..000000000 --- a/gosa-si-poe/debian/changelog +++ /dev/null @@ -1,6 +0,0 @@ -gosa-si (1.0-1) unstable; urgency=low - - * Initial release - - -- Cajus Pollmeier Fri, 7 Dec 2007 11:37:45 +0100 - diff --git a/gosa-si-poe/debian/compat b/gosa-si-poe/debian/compat deleted file mode 100644 index 7ed6ff82d..000000000 --- a/gosa-si-poe/debian/compat +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/gosa-si-poe/debian/control b/gosa-si-poe/debian/control deleted file mode 100644 index fd596d22d..000000000 --- a/gosa-si-poe/debian/control +++ /dev/null @@ -1,40 +0,0 @@ -Source: gosa-si -Section: utils -Priority: optional -Maintainer: Cajus Pollmeier -Standards-Version: 3.7.2.2 -Build-Depends: debhelper(>= 4.2.32), dpatch - -Package: gosa-si-common -Architecture: any -Depends: libconfig-inifiles-perl, libcrypt-rijndael-perl, libxml-simple-perl, libipc-shareable-perl, libdata-dumper-simple-perl, libmime-perl, libdbd-sqlite3-perl, libnet-ldap-perl, libnetaddr-ip-perl -Suggests: gosa-si-server, gosa-si-client -Description: GOsa support infrastructure - This package provides common library functionality used by the - infrastructure server and client packages. - . - GOsa is a combination of system-administrator and end-user web - interface, designed to handle LDAP based setups. - -Package: gosa-si-server -Architecture: any -Depends: gosa-si-common -Suggests: gosa -Description: GOsa support infrastructure server - This package provides everything you need in order to deploy a simple - or distributed GOsa support infrastructure. It can be used to trigger - certain actions or retrieve information from clients. - . - GOsa is a combination of system-administrator and end-user web - interface, designed to handle LDAP based setups. - -Package: gosa-si-client -Architecture: any -Depends: gosa-si-common -Suggests: gosa -Description: GOsa support infrastructure client - This package lets you join to a GOsa support infrastructure as a - client in order to provide information or to act on events. - . - GOsa is a combination of system-administrator and end-user web - interface, designed to handle LDAP based setups. diff --git a/gosa-si-poe/debian/copyright b/gosa-si-poe/debian/copyright deleted file mode 100644 index d7463efe4..000000000 --- a/gosa-si-poe/debian/copyright +++ /dev/null @@ -1,8 +0,0 @@ -This package was debianized by Cajus Pollmeier - on Mon, 25 Jun 2007 12:57:35 +0100. - -Copyright: GPL2 - -This code is released under the terms of the GPLv2 license. - -See /usr/share/common-licenses/GPL-2 for the full license. diff --git a/gosa-si-poe/debian/gosa-si b/gosa-si-poe/debian/gosa-si deleted file mode 100644 index 10df929a0..000000000 --- a/gosa-si-poe/debian/gosa-si +++ /dev/null @@ -1,2 +0,0 @@ -# /etc/default/gosa-si - configure the init script -START_BUS=0 diff --git a/gosa-si-poe/debian/gosa-si-client.dirs b/gosa-si-poe/debian/gosa-si-client.dirs deleted file mode 100644 index 2f6b7067d..000000000 --- a/gosa-si-poe/debian/gosa-si-client.dirs +++ /dev/null @@ -1,3 +0,0 @@ -etc/gosa-si -usr/sbin -usr/lib/gosa-si/client/events diff --git a/gosa-si-poe/debian/gosa-si-client.install b/gosa-si-poe/debian/gosa-si-client.install deleted file mode 100644 index e5544c641..000000000 --- a/gosa-si-poe/debian/gosa-si-client.install +++ /dev/null @@ -1,2 +0,0 @@ -gosa-si-client usr/sbin -client.conf etc/gosa-si diff --git a/gosa-si-poe/debian/gosa-si-client.postinst b/gosa-si-poe/debian/gosa-si-client.postinst deleted file mode 100644 index 0747c6a3d..000000000 --- a/gosa-si-poe/debian/gosa-si-client.postinst +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -#DEBHELPER# - -# We exit unless the package is being configured -case "$1" in - abort*upgrade) exit 0;; - abort*remove) exit 0;; - abort*deconfigure) exit 0;; - configure) ;; - *) exit 0; -esac - -[ ! -d /usr/lib/gosa-si/client/events ] && install -d -o root -g root -m 750 /usr/lib/gosa-si/client/events - diff --git a/gosa-si-poe/debian/gosa-si-common.dirs b/gosa-si-poe/debian/gosa-si-common.dirs deleted file mode 100644 index 2d13e8f10..000000000 --- a/gosa-si-poe/debian/gosa-si-common.dirs +++ /dev/null @@ -1,2 +0,0 @@ -/etc/default -/usr/share/perl5/GOSA diff --git a/gosa-si-poe/debian/gosa-si-common.install b/gosa-si-poe/debian/gosa-si-common.install deleted file mode 100644 index 3db70042e..000000000 --- a/gosa-si-poe/debian/gosa-si-common.install +++ /dev/null @@ -1,3 +0,0 @@ -modules/GosaSupportDaemon.pm usr/share/perl5/GOSA -modules/DBsqlite.pm usr/share/perl5/GOSA -debian/gosa-si etc/default diff --git a/gosa-si-poe/debian/gosa-si-common.postinst b/gosa-si-poe/debian/gosa-si-common.postinst deleted file mode 100644 index 3d2b7723d..000000000 --- a/gosa-si-poe/debian/gosa-si-common.postinst +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -#DEBHELPER# - -# We exit unless the package is being configured -case "$1" in - abort*upgrade) exit 0;; - abort*remove) exit 0;; - abort*deconfigure) exit 0;; - configure) ;; - *) exit 0; -esac - -[ -d /var/lib/gosa-si ] || install -d -o root -g root -m 750 /var/lib/gosa-si - diff --git a/gosa-si-poe/debian/gosa-si-server.dirs b/gosa-si-poe/debian/gosa-si-server.dirs deleted file mode 100644 index be099ffcf..000000000 --- a/gosa-si-poe/debian/gosa-si-server.dirs +++ /dev/null @@ -1,4 +0,0 @@ -usr/sbin -usr/lib/gosa-si/modules -usr/lib/gosa-si/server/events -etc/gosa-si diff --git a/gosa-si-poe/debian/gosa-si-server.init b/gosa-si-poe/debian/gosa-si-server.init deleted file mode 100755 index 18e68aefc..000000000 --- a/gosa-si-poe/debian/gosa-si-server.init +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/sh -# Start/stop the GOsa support daemon infrastructure. -# -### BEGIN INIT INFO -# Provides: gosa-si -# Required-Start: $syslog $time -# Required-Stop: $syslog $time -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: GOsa message bus and server component -# Description: gosa-si establishes the communication between a couple of -# GOsa hosting servers and optionally clients to do event -# signaling for all communication partners. -### END INIT INFO - -# Sanity checks -test -f /usr/sbin/gosa-si-server || exit 0 -test -f /usr/sbin/gosa-si-bus || exit 0 - -# Load defaults -START_BUS=0 -[ -r /etc/default/gosa-si ] && . /etc/default/gosa-si - -# Load LSB support functions -. /lib/lsb/init-functions - - -start_bus() { - start-stop-daemon --start --quiet --pidfile /var/run/gosa-si-bus.pid --name gosa-si-bus --startas /usr/sbin/gosa-si-bus -- -} - - -start_server() { - start-stop-daemon --start --quiet --pidfile /var/run/gosa-si-server.pid --name gosa-si-server --startas /usr/sbin/gosa-si-server -- -vvvvv $1 -} - - -stop_bus() { - start-stop-daemon --stop --retry 5 --quiet --pidfile /var/run/gosa-si-bus.pid --name gosa-si-bus -} - - -stop_server() { - start-stop-daemon --stop --retry 5 --quiet --pidfile /var/run/gosa-si-server.pid --name gosa-si-server -} - - -case "$1" in -start) log_daemon_msg "Starting GOsa support infrastructure" - if [ "$START_BUS" == "1" ]; then - log_progress_msg "bus" - start_bus - log_progress_msg "daemon" - start_server - else - log_progress_msg "daemon" - start_server --no-bus - fi - log_end_msg $? - ;; -stop) log_daemon_msg "Stopping GOsa support infrastructure" - if [ "$START_BUS" == "1" ]; then - log_progress_msg "daemon" - stop_server - log_progress_msg "bus" - stop_bus - else - log_progress_msg "daemon" - stop_server - fi - log_end_msg $? - ;; -reload|force-reload|restart) log_daemon_msg "Restarting GOsa support infrastructure" - if [ "$START_BUS" == "1" ]; then - stop_server - stop_bus - start_bus - start_server --no-bus - log_progress_msg "done" - else - stop_server - start_server --no-bus - log_progress_msg "done" - fi - log_end_msg $? - ;; -*) log_action_msg "Usage: /etc/init.d/gosa-si {start|stop|restart|reload|force-reload}" - exit 2 - ;; -esac -exit 0 diff --git a/gosa-si-poe/debian/gosa-si-server.install b/gosa-si-poe/debian/gosa-si-server.install deleted file mode 100644 index b7c600f74..000000000 --- a/gosa-si-poe/debian/gosa-si-server.install +++ /dev/null @@ -1,7 +0,0 @@ -gosa-si-server usr/sbin -gosa-si-bus usr/sbin -server.conf etc/gosa-si -bus.conf etc/gosa-si -modules/ServerPackages.pm usr/lib/gosa-si/modules -modules/GosaPackages.pm usr/lib/gosa-si/modules -server/events/ping usr/lib/gosa-si/server/events diff --git a/gosa-si-poe/debian/rules b/gosa-si-poe/debian/rules deleted file mode 100755 index f54d5592a..000000000 --- a/gosa-si-poe/debian/rules +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/make -f -# Sample debian/rules that uses debhelper. GNU copyright 1997 by Joey Hess. - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -build: patch - #******************************************************** - #* Building ltsp-goto into a Debian/GNU Linux Package * - #* please stand by * - #******************************************************** - -clean: clean-patched unpatch -clean-patched: - dh_testdir - rm -f install-stamp - -rm -f debian/files - -rm -rf debian/tmp - -rm -f debian/substvars - dh_clean - -unpatch: - dpatch deapply-all - rm -rf patch-stamp debian/patched - -install: install-stamp -install-stamp: - dh_testdir - dh_testroot - dh_clean -k - dh_installdirs - - # Create a copy, remove svn stuff - -mkdir debian/tmp - -for i in *; do \ - cp -R $$i debian/tmp ; \ - done - -find debian/tmp -name '*.svn' -type d -exec rm -rf {} \; 2> /dev/null - - -for i in gosa-si-client gosa-si-server modules/GosaPackages.pm modules/ServerPackages.pm modules/TestModule.pm server/events/*; do sed -i 's/use GosaSupportDaemon;/use GOSA::GosaSupportDaemon;/g;s/use DBsqlite;/use GOSA::DBsqlite;/g' debian/tmp/$$i; done - - -sed -i 's!"/etc/gosa-si/modules";!use lib "/usr/lib/gosa-si/modules";!g' debian/tmp/gosa-si-server - - -sed -i 's!"/etc/gosa-si/server/events";!"/usr/lib/gosa-si/server/events";!g' debian/tmp/modules/GosaPackages.pm - - touch install-stamp - -patch: patch-stamp -patch-stamp: - dpatch apply-all - dpatch cat-all >patch-stamp - -binary-indep: install - dh_testdir - dh_testroot - - dh_install --sourcedir=debian/tmp - dh_installdocs - dh_installcron - dh_installexamples - dh_installchangelogs - #dh_installdebconf - dh_installinit -pgosa-si-server --init-script=gosa-si - dh_link - dh_strip - dh_compress - dh_fixperms - dh_perl - dh_installdeb - dh_shlibdeps - - dh_gencontrol - dh_md5sums - dh_builddeb - -source diff: - @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false - -binary: binary-indep -.PHONY: build install clean binary-indep binary - -binary-arch: - diff --git a/gosa-si-poe/gosa-si-bus b/gosa-si-poe/gosa-si-bus deleted file mode 100755 index a5d50f1d2..000000000 --- a/gosa-si-poe/gosa-si-bus +++ /dev/null @@ -1,1362 +0,0 @@ -#!/usr/bin/perl -#=============================================================================== -# -# FILE: gosa-server -# -# USAGE: ./gosa-server -# -# DESCRIPTION: -# -# OPTIONS: --- -# REQUIREMENTS: --- -# BUGS: --- -# NOTES: -# AUTHOR: (Andreas Rettenberger), -# COMPANY: -# VERSION: 1.0 -# CREATED: 12.09.2007 08:54:41 CEST -# REVISION: --- -#=============================================================================== - -use strict; -use warnings; -use Getopt::Long; -use Config::IniFiles; -use POSIX; -use Time::HiRes qw( gettimeofday ); - -use IO::Socket::INET; -use Crypt::Rijndael; -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_passwd, $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 ; - -%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/bus_known_server.db"] - }, -"bus" => - {"bus_activ" => [\$bus_activ, "on"], - "bus_passwd" => [\$bus_passwd, ""], - "bus_ip" => [\$bus_ip, "0.0.0.0"], - "bus_port" => [\$bus_port, "20080"], - } - ); - -#=== FUNCTION ================================================================ -# NAME: read_configfile -# PARAMETERS: cfg_file - string - -# RETURNS: nothing -# DESCRIPTION: read cfg_file and set variables -#=============================================================================== -sub read_configfile { - my $cfg; - if( defined( $cfg_file) && ( length($cfg_file) > 0 )) { - if( -r $cfg_file ) { - $cfg = Config::IniFiles->new( -file => $cfg_file ); - } else { - print STDERR "Couldn't read config file!"; - } - } else { - $cfg = Config::IniFiles->new() ; - } - foreach my $section (keys %cfg_defaults) { - foreach my $param (keys %{$cfg_defaults{ $section }}) { - my $pinfo = $cfg_defaults{ $section }{ $param }; - ${@$pinfo[ 0 ]} = $cfg->val( $section, $param, @$pinfo[ 1 ] ); - } - } -} - -#=== 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 $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 -# PARAMETERS: nothing -# RETURNS: nothing -# DESCRIPTION: handels pid processing -#=============================================================================== -sub check_pid { - $pid = -1; - # Check, if we are already running - if( open(LOCK_FILE, "<$pid_file") ) { - $pid = ; - if( defined $pid ) { - chomp( $pid ); - if( -f "/proc/$pid/stat" ) { - my($stat) = `cat /proc/$pid/stat` =~ m/$pid \((.+)\).*/; - if( $0 eq $stat ) { - close( LOCK_FILE ); - exit -1; - } - } - } - close( LOCK_FILE ); - unlink( $pid_file ); - } - - # create a syslog msg if it is not to possible to open PID file - if (not sysopen(LOCK_FILE, $pid_file, O_WRONLY|O_CREAT|O_EXCL, 0644)) { - my($msg) = "Couldn't obtain lockfile '$pid_file' "; - if (open(LOCK_FILE, '<', $pid_file) - && ($pid = )) - { - chomp($pid); - $msg .= "(PID $pid)\n"; - } else { - $msg .= "(unable to read PID)\n"; - } - if( ! ($foreground) ) { - openlog( $0, "cons,pid", "daemon" ); - syslog( "warning", $msg ); - closelog(); - } - else { - print( STDERR " $msg " ); - } - exit( -1 ); - } -} - - -#=== FUNCTION ================================================================ -# NAME: usage -# PARAMETERS: nothing -# RETURNS: nothing -# DESCRIPTION: print out usage text to STDERR -#=============================================================================== -sub usage { - print STDERR << "EOF" ; -usage: $0 [-hvf] [-c config] - - -h : this (help) message - -c : config file - -f : foreground, process will not be forked to background - -v : be verbose (multiple to increase verbosity) -EOF - print "\n" ; -} - - -#=== FUNCTION ================================================================ -# NAME: sig_int_handler -# PARAMETERS: signal - string - signal arose from system -# RETURNS: noting -# DESCRIPTION: handels tasks to be done befor signal becomes active -#=============================================================================== -sub sig_int_handler { - my ($signal) = @_; - if($bus){ - close($bus); - print "$bus closed\n"; - } - print "$signal\n"; - exit(1); -} -$SIG{INT} = \&sig_int_handler; - -#=== FUNCTION ================================================================ -# NAME: get_interface_for_ip -# PARAMETERS: ip address (i.e. 192.168.0.1) -# RETURNS: array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else -# 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; - } - } - } - } - return $result; -} - -#=== FUNCTION ================================================================ -# NAME: get_interfaces -# PARAMETERS: none -# RETURNS: (list of interfaces) -# DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. -#=============================================================================== -sub get_interfaces { - my @result; - my $PROC_NET_DEV= ('/proc/net/dev'); - - open(PROC_NET_DEV, "<$PROC_NET_DEV") - or die "Could not open $PROC_NET_DEV"; - - my @ifs = ; - - close(PROC_NET_DEV); - - # 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; - } - - return @result; -} - -#=== FUNCTION ================================================================ -# NAME: get_mac -# PARAMETERS: interface name (i.e. eth0) -# RETURNS: (mac address) -# DESCRIPTION: Uses ioctl to get mac address directly from system. -#=============================================================================== -sub get_mac { - my $ifreq= shift; - my $result; - if ($ifreq && length($ifreq) > 0) { - if($ifreq eq "all") { - $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; - } - - socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip') - or die "socket: $!"; - - 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; - } - } - } - } - 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 -#=============================================================================== -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; -} - - -#=== FUNCTION ================================================================ -# NAME: get_processing_child -# 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 -#=============================================================================== -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; - } - } - - 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); - - # 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; - } - } -} - - -#=== FUNCTION ================================================================ -# NAME: process_incoming_msg -# PARAMETERS: crypted_msg - string - incoming crypted message -# RETURNS: nothing -# DESCRIPTION: handels the proceeded distribution to the appropriated functions -#=============================================================================== -sub process_incoming_msg { - my ($crypted_msg) = @_; - if(not defined $crypted_msg) { - daemon_log("function 'process_incoming_msg': got no msg", 7); - 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); - - 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_passwd; - daemon_log("process_incoming_msg: host_name: $host_name", 7); - daemon_log("process_incoming_msg: host_key: $host_key", 7); - eval{ - my $key_cipher = &create_ciphering($host_key); - $msg = &decrypt_msg($crypted_msg, $key_cipher); - $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; - } - - # check wether incoming msg is from a bus_known_server - if( not defined $msg ) { - my $query_res = $bus_known_server_db->select_dbentry( {table=>'bus_known_server'} ); - 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{ - my $key_cipher = &create_ciphering($host_key); - $msg = &decrypt_msg($crypted_msg, $key_cipher); - $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; - } - } - } - - 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]; - - daemon_log("header from msg: $header", 1); - daemon_log("msg to process:", 5); - daemon_log($msg, 5); - - my @targets = @{$msg_hash->{target}}; - my $len_targets = @targets; - - if ($len_targets == 0){ - daemon_log("ERROR: no target specified for msg $header", 1); - - } elsif ($len_targets == 1){ - # we have only one target symbol - my $target = $targets[0]; - daemon_log("msg is for: $target", 7); - - 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 $query_res = $bus_known_server_db->select_dbentry( {table=>'known_server'} ); - 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; - } - - } else { - # a list of targets is specified - my $target_address; - foreach $target_address (@targets) { - - my $query_res = $bus_known_server_db->select_dbentry( {table=>'known_server', hostname=>$target_address} ); - if( 1 == keys %{$query_res} ) { - $host_key = $query_res->{1}->{hostkey}; - &send_msg_hash2address($msg_hash, $target_address, $host_key); - next; - - } else { - $query_res = $bus_known_server_db->select_dbentry( {table=>'known_server'} ); - 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; - } - } - } - } - } - - return; -} - - -#=== FUNCTION ================================================================ -# NAME: get_content_of_known_daemons -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -#sub get_content_of_known_daemons { -# my ($host, $content) = @_; -# 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))] - } - return $new_passwd; -} - - -#=== FUNCTION ================================================================ -# NAME: create_ciphering -# PARAMETERS: passwd - string - used to create ciphering -# RETURNS: cipher - object -# DESCRIPTION: creates a Crypt::Rijndael::MODE_CBC object with passwd as key -#=============================================================================== -#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; -#} - - -#=== FUNCTION ================================================================ -# NAME: encrypt_msg -# PARAMETERS: msg - string - message to encrypt -# my_cipher - ref - reference to a Crypt::Rijndael object -# RETURNS: crypted_msg - string - crypted message -# DESCRIPTION: crypts the incoming message with the Crypt::Rijndael module -#=============================================================================== -#sub encrypt_msg { -# my ($msg, $my_cipher) = @_; -# if(not defined $my_cipher) { print "no cipher object\n"; } -# $msg = "\0"x(16-length($msg)%16).$msg; -# my $crypted_msg = $my_cipher->encrypt($msg); -# chomp($crypted_msg = &encode_base64($crypted_msg)); -# return $crypted_msg; -#} - - -#=== FUNCTION ================================================================ -# NAME: decrypt_msg -# PARAMETERS: crypted_msg - string - message to decrypt -# my_cipher - ref - reference to a Crypt::Rijndael object -# RETURNS: msg - string - decrypted message -# DESCRIPTION: decrypts the incoming message with the Crypt::Rijndael module -#=============================================================================== -#sub decrypt_msg { -# my ($crypted_msg, $my_cipher) = @_ ; -# $crypted_msg = &decode_base64($crypted_msg); -# my $msg = $my_cipher->decrypt($crypted_msg); -# $msg =~ s/^\0*//g; -# return $msg; -#} - - -#=== FUNCTION ================================================================ -# NAME: create_xml_hash -# PARAMETERS: header - string - message header (required) -# source - string - where the message come from (required) -# target - string - where the message should go to (required) -# [header_value] - string - something usefull (optional) -# RETURNS: hash - hash - nomen est omen -# DESCRIPTION: creates a key-value hash, all values are stored in a array -#=============================================================================== -#sub create_xml_hash { -# my ($header, $source, $target, $header_value) = @_ ; -# -# if (not defined $header || not defined $source || not defined $target) { -# daemon_log("ERROR: create_xml_hash function is invoked with uncompleted parameters", 7); -# } -# -# my $hash = { -# header => [$header], -# source => [$source], -# target => [$target], -# $header => [$header_value], -# }; -# #daemon_log("create_xml_hash:", 7), -# #chomp(my $tmp = Dumper $hash); -# #daemon_log("\t$tmp\n", 7); -# return $hash -#} - - -#=== FUNCTION ================================================================ -# NAME: create_xml_string -# PARAMETERS: xml_hash - hash - hash from function create_xml_hash -# RETURNS: xml_string - string - xml string representation of the hash -# DESCRIPTION: transform the hash to a string using XML::Simple module -#=============================================================================== -#sub create_xml_string { -# my ($xml_hash) = @_ ; -# my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml'); -# #$xml_string =~ s/[\n]+//g; -# return $xml_string; -#} - - -#=== FUNCTION ================================================================ -# NAME: add_content2xml_hash -# PARAMETERS: xml_ref - ref - reference to a hash from function create_xml_hash -# element - string - key for the hash -# content - string - value for the hash -# RETURNS: nothing -# DESCRIPTION: add key-value pair to xml_ref, if key alread exists, then append value to list -#=============================================================================== -#sub add_content2xml_hash { -# my ($xml_ref, $element, $content) = @_; -# if(not exists $$xml_ref{$element} ) { -# $$xml_ref{$element} = []; -# } -# my $tmp = $$xml_ref{$element}; -# push(@$tmp, $content); -# return; -#} - - -#=== FUNCTION ================================================================ -# NAME: get_content_from_xml_hash -# PARAMETERS: xml_ref - ref - reference of the xml hash -# element - string - key of the value you want -# RETURNS: value - string - if key is either header, target or source -# value - list - for all other keys in xml hash -# DESCRIPTION: -#=============================================================================== -#sub get_content_from_xml_hash { -# my ($xml_ref, $element) = @_; -# my $result = $xml_ref->{$element}; -# if( $element eq "header" || $element eq "target" || $element eq "source") { -# return @$result[0]; -# } -# return @$result; -#} - - -#=== 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, -# Reuse => 1, -# Timeout => 5, -# ); -# if(not defined $socket) { -# return; -# } -# return $socket; -#} - - -#=== 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: send_msg_hash2address -# PARAMETERS: msg_hash - hash - xml_hash created with function create_xml_hash -# PeerAddr string - socket address to send msg -# PeerPort string - socket port, if not included in socket address -# RETURNS: nothing -# DESCRIPTION: ???? -#=============================================================================== -#sub send_msg_hash2address { -# my ($msg_hash, $address) = @_ ; -# -# # fetch header for logging -# my $header = &get_content_from_xml_hash($msg_hash, "header"); -# -# # generate xml string -# my $msg_xml = &create_xml_string($msg_hash); -# -# # fetch the appropriated passwd from hash -# my $passwd = $known_daemons->{$address}->{passwd}; -# -# # create a ciphering object -# my $act_cipher = &create_ciphering($passwd); -# -# # encrypt xml msg -# my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher); -# -# # open socket -# my $socket = &open_socket($address); -# if(not defined $socket){ -# daemon_log("ERROR: cannot send '$header'-msg to $address , server not reachable", 1); -# return; -# } -# -# # send xml msg -# print $socket $crypted_msg."\n"; -# -# close $socket; -# daemon_log("send '$header'-msg to $address", 5); -# daemon_log("crypted_msg:\n\t$crypted_msg", 7); -# return; -#} - - -#=== FUNCTION ================================================================ -# NAME: send_msg_hash2all -# PARAMETERS: msg_hash - hash - xml_hash created with function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: send msg_hash to all registered daemons -#=============================================================================== -#sub send_msg_hash2all { -# my ($msg_hash) = @_; -# -# # fetch header for logging -# my $header = &get_content_from_xml_hash($msg_hash, "header"); -# -# # generate xml string -# my $msg_xml = &create_xml_string($msg_hash); -# -# # fetch a list of all target addresses -# my @targets = keys(%$known_daemons); -# -# # itterates through the list an send each the msg -# foreach my $target (@targets) { -# if($target eq $bus_address) {next}; # do not send msg to bus -# -# # fetch the appropriated passwd -# my $passwd = $known_daemons->{$target}->{passwd}; -# -# # create ciphering object -# my $act_cipher = &create_ciphering($passwd); -# -# # encrypt xml msg -# my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher); -# -# # open socket -# my $socket = &open_socket($target); -# if(not defined $socket){ -# daemon_log("ERROR: cannot open socket to $target , server not reachable", 1); -# &update_known_daemons_entry(hostname=>$target, status=>"down"); -# next; -# } -# -# # send xml msg -# print $socket $crypted_msg."\n"; -# -# close $socket; -# daemon_log("send '$header'-msg to $target", 5); -# daemon_log("crypted_msg:\n\t$crypted_msg", 7); -# } -# return; -#} - - -#=== 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 $new_key = &create_passwd(); - - # create bus_known_server entry - my $add_hash = { - table=>"bus_known_server", - primkey=>"hostname", - hostname=>$source, - status=>"registered", - hostkey=>$bus_passwd, - clients=>"", - }; - $bus_known_server_db->add_dbentry($add_hash); - - # create outgoing msg - my $out_hash = &create_xml_hash("new_passwd", $bus_address, $source, $new_key); - &send_msg_hash2address($out_hash, $source, $bus_passwd); - - # change hostkey, reason - my $update_hash = { table=>'bus_known_server' }; - $update_hash->{where} = [ { hostname=>[$source] } ]; - $update_hash->{update} = [ { hostkey=>[$new_key] } ]; - $bus_known_server_db->update_dbentry($update_hash); - - 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 $update_hash = { table=>'bus_known_server' }; - $update_hash->{where} = [ { hostname=>[$source] } ]; - $update_hash->{update} = [ { status=>['key_confirmed'] } ]; - $bus_known_server_db->update_dbentry($update_hash); - - return; -} - - -#=== 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 $update_hash = { table=>'bus_known_server', - where=> [ { hostname=>[$source] } ], - update=> [ { status=>$header } ], - }; - $bus_known_server_db->update_dbentry($update_hash); - - my $out_hash = &create_xml_hash("got_ping", $bus_address, $source); - - my $res = $bus_known_server_db->select_dbentry( { table=>'bus_known_server', hostname=>$source } ); - my $hostkey = $res->{1}->{hostkey}; - &send_msg_hash2address($out_hash, $source, $hostkey); - - return; -} - - -#=== FUNCTION ================================================================ -# NAME: make ping -# PARAMETERS: address - string - address which should be pinged -# RETURNS: nothing -# DESCRIPTION: send ping message to address -#=============================================================================== -#sub make_ping { -# my ($address) = @_; -# daemon_log("ping:$address\n", 1); -# my $out_hash = &create_xml_hash("ping", "$bus_ip:$bus_port", $address); -# &send_msg_hash2address($out_hash, $address); -# return; -#} - - -#=== 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 $update_hash = { table=>'bus_known_server', - where=> [ { hostname=>[$source] } ], - update=> [ { status=>'got_ping' } ], - }; - $bus_known_server_db->update_dbentry($update_hash); - - 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 $res = $bus_known_server_db->select_dbentry( { table=>'bus_known_server', hostname=>$source } ); - my $clients = $res->{1}->{clients}; - - # if host has alread more clients, than just append - if( length($clients) != 0 ) { - $clients .= ",$new_client"; - } else { - $clients = $new_client; - } - - my $update_hash = { table=>'bus_known_server', - where=>[ {hostname=>[$source] } ], - update=>[ {clients=>[$clients] } ], - }; - - $bus_known_server_db->update_dbentry( $update_hash ); - return; -} - - -#=== FUNCTION ================================================================ -# NAME: delete_client -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -#sub delete_client { -# my ($msg_hash) = @_ ; -# my $source = &get_content_from_xml_hash($msg_hash, "source"); -# my $header = &get_content_from_xml_hash($msg_hash, "header"); -# my $del_client = (&get_content_from_xml_hash($msg_hash, $header))[0]; -# -# if (not exists $known_daemons->{$source}->{$del_client}) { -# daemon_log -# } -# delete $known_daemons->{$source}->{$del_client}; -# -# return; -#} - - -#=== FUNCTION ================================================================ -# NAME: print_known_daemons_hash -# PARAMETERS: nothing -# RETURNS: nothing -# DESCRIPTION: nome est omen -#=============================================================================== -#sub print_known_daemons_hash { -# my ($tmp) = @_; -# print "####################################\n"; -# print "# status of known_daemons\n"; -# my $hosts; -# my $host_hash; -# $shmkh->shlock(LOCK_EX); -# my @hosts = keys %$known_daemons; -# foreach my $host (@hosts) { -# my $status = $known_daemons->{$host}->{status} ; -# my $passwd = $known_daemons->{$host}->{passwd}; -# my $timestamp = $known_daemons->{$host}->{timestamp}; -# my @clients = keys %{$known_daemons->{$host}->{clients}}; -# my $client_string = join(", ", @clients); -# print "$host\n"; -# print "\tstatus: $status\n"; -# print "\tpasswd: $passwd\n"; -# print "\ttimestamp: $timestamp\n"; -# print "\tclients: $client_string\n"; -# -# } -# $shmkh->shunlock(LOCK_EX); -# print "####################################\n\n"; -# return; -#} - - -#=== FUNCTION ================================================================ -# NAME: create_known_daemons_entry -# PARAMETERS: hostname - string - ip address and port of host -# RETURNS: nothing -# DESCRIPTION: nome est omen -#=============================================================================== -#sub create_known_daemons_entry { -# my ($hostname) = @_; -# $shmkh->shlock(LOCK_EX); -# $known_daemons->{$hostname} = {}; -# $known_daemons->{$hostname}->{status} = "none"; -# $known_daemons->{$hostname}->{passwd} = "none"; -# $known_daemons->{$hostname}->{timestamp} = "none"; -# $known_daemons->{$hostname}->{clients} = {}; -# $shmkh->shunlock(LOCK_EX); -# return; -#} - - -#=== FUNCTION ================================================================ -# NAME: update_known_daemons_entry -# PARAMETERS: hostname - string - ip address and port of host (required) -# status - string - (optional) -# passwd - string - (optional) -# client - string - ip address and port of client (optional) -# RETURNS: nothing -# DESCRIPTION: nome est omen and updates each time the timestamp of hostname -#=============================================================================== -#sub update_known_daemons_entry { -# my $arg = { -# hostname => undef, status => undef, passwd => undef, -# client => undef, -# @_ }; -# my $hostname = $arg->{hostname}; -# my $status = $arg->{status}; -# my $passwd = $arg->{passwd}; -# my $client = $arg->{client}; -# -# if (not defined $hostname) { -# daemon_log("ERROR: function add_content2known_daemons is not invoked with requiered parameter 'hostname'", 1); -# return; -# } -# -# 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; -# $month+=1; -# $month = $month < 10 ? $month = "0".$month : $month; -# $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; -# $year+=1900; -# my $t = "$year$month$monthday$hours$minutes$seconds"; -# -# $shmkh->shlock(LOCK_EX); -# if (defined $status) { -# $known_daemons->{$hostname}->{status} = $status; -# } -# if (defined $passwd) { -# $known_daemons->{$hostname}->{passwd} = $passwd; -# } -# if (defined $client) { -# $known_daemons->{$hostname}->{clients}->{$client} = ""; -# } -# $known_daemons->{$hostname}->{timestamp} = $t; -# $shmkh->shunlock(LOCK_EX); -# return; -#} - - -#==== MAIN = main ============================================================== - -# parse commandline options -Getopt::Long::Configure( "bundling" ); -GetOptions("h|help" => \&usage, - "c|config=s" => \$cfg_file, - "f|foreground" => \$foreground, - "v|verbose+" => \$verbose, - ); - -# read and set config parameters -&check_cmdline_param ; -&read_configfile; -&check_pid; - -$SIG{CHLD} = 'IGNORE'; - -# restart daemon log file -if(-e $log_file ) { unlink $log_file } -daemon_log(" ", 1); -daemon_log("$0 started!", 1); - -# forward error messages to logfile -if( ! $foreground ) { - open(STDERR, '>>', $log_file); - open(STDOUT, '>>', $log_file); -} - -# 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 { $pid = $$; } - -# Do something useful - put our PID into the pid_file -if( 0 != $pid ) { - open( LOCK_FILE, ">$pid_file" ); - print LOCK_FILE "$pid\n"; - close( LOCK_FILE ); - 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"; - -# setup xml parser -$xml = new XML::Simple(); - -# create cipher object -$bus_cipher = &create_ciphering($bus_passwd); -$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_passwd); - - -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); - } - -} - - diff --git a/gosa-si-poe/gosa-si-client b/gosa-si-poe/gosa-si-client deleted file mode 100755 index 69a5f7ffd..000000000 --- a/gosa-si-poe/gosa-si-client +++ /dev/null @@ -1,1363 +0,0 @@ -#!/usr/bin/perl -#=============================================================================== -# -# FILE: gosa-server -# -# USAGE: gosa-si-client -# -# DESCRIPTION: -# -# OPTIONS: --- -# REQUIREMENTS: libnetaddr-ip-perl -# BUGS: --- -# NOTES: -# AUTHOR: (Andreas Rettenberger), -# COMPANY: -# VERSION: 1.0 -# CREATED: 12.09.2007 08:54:41 CEST -# REVISION: --- -#=============================================================================== - -use strict; -use warnings; -use Getopt::Long; -use Config::IniFiles; -use POSIX; -use Time::HiRes qw( gettimeofday ); - -use Fcntl; -use IO::Socket::INET; -use Crypt::Rijndael; -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 File::Spec; -use Cwd; -use NetAddr::IP; -use GOSA::GosaSupportDaemon; - - -my ($cfg_file, %cfg_defaults, $foreground, $verbose, $pid_file, $procid, $pid, $log_file); -my ($server_address, $server_ip, $server_port, $server_domain, $server_passwd, $server_cipher, $server_timeout); -my ($client_address, $client_ip, $client_port, $client_mac_address, $network_interface, $ldap_config, $pam_config, $nss_config); -my ($input_socket, $rbits, $wbits, $ebits, $xml, $known_hosts, $ldap_enabled); -my (@events); - -# default variables -my $event_dir = "/usr/lib/gosa-si/client/events"; -$known_hosts = {}; -$foreground = 0 ; -%cfg_defaults = -("general" => - {"log_file" => [\$log_file, "/var/run/".$0.".log"], - "pid_file" => [\$pid_file, "/var/run/".$0.".pid"], - }, -"client" => - {"client_port" => [\$client_port, "20083"], - "client_ip" => [\$client_ip, "0.0.0.0"], - "ldap" => [\$ldap_enabled, 1], - "ldap_config" => [\$ldap_config, "/etc/ldap/ldap.conf"], - "pam_config" => [\$pam_config, "/etc/pam_ldap.conf"], - "nss_config" => [\$nss_config, "/etc/libnss_ldap.conf"], - }, -"server" => - {"server_ip" => [\$server_ip, ""], - "server_port" => [\$server_port, "20081"], - "server_passwd" => [\$server_passwd, ""], - "server_timeout" => [\$server_timeout, 10], - "server_domain" => [\$server_domain, ""], - }, - ); - - -#=== FUNCTION ================================================================ -# NAME: read_configfile -# PARAMETERS: cfg_file - string - -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub read_configfile { - my $cfg; - if( defined( $cfg_file) && ( length($cfg_file) > 0 )) { - if( -r $cfg_file ) { - $cfg = Config::IniFiles->new( -file => $cfg_file ); - } else { - print STDERR "Couldn't read config file!"; - } - } else { - $cfg = Config::IniFiles->new() ; - } - foreach my $section (keys %cfg_defaults) { - foreach my $param (keys %{$cfg_defaults{ $section }}) { - my $pinfo = $cfg_defaults{ $section }{ $param }; - ${@$pinfo[ 0 ]} = $cfg->val( $section, $param, @$pinfo[ 1 ] ); - } - } -} - - -#=== FUNCTION ================================================================ -# NAME: logging -# PARAMETERS: level - string - default 'info' -# msg - string - -# facility - string - default 'LOG_DAEMON' -# RETURNS: -# DESCRIPTION: -#=============================================================================== -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){ - print LOG_HANDLE $msg."\n"; - if(defined $foreground) { print $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: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub check_cmdline_param () { - my $err_config; - my $err_counter = 0; - if( not defined( $cfg_file)) { - #$err_config = "please specify a config file"; - #$err_counter += 1; - my $cwd = getcwd; - my $name = "/etc/gosa-si/client.conf"; - $cfg_file = File::Spec->catfile( $cwd, $name ); - print STDERR "no conf file specified\n try to use default: $cfg_file\n"; - } - if( $err_counter > 0 ) { - &usage( "", 1 ); - if( defined( $err_config)) { print STDERR "$err_config\n"} - print STDERR "\n"; - exit( -1 ); - } -} - - -#=== FUNCTION ================================================================ -# NAME: check_pid -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub check_pid { - $pid = -1; - # Check, if we are already running - if( open(LOCK_FILE, "<$pid_file") ) { - $pid = ; - if( defined $pid ) { - chomp( $pid ); - if( -f "/proc/$pid/stat" ) { - my($stat) = `cat /proc/$pid/stat` =~ m/$pid \((.+)\).*/; - if( $0 eq $stat ) { - close( LOCK_FILE ); - exit -1; - } - } - } - close( LOCK_FILE ); - unlink( $pid_file ); - } - - # create a syslog msg if it is not to possible to open PID file - if (not sysopen(LOCK_FILE, $pid_file, O_WRONLY|O_CREAT|O_EXCL, 0644)) { - my($msg) = "Couldn't obtain lockfile '$pid_file' "; - if (open(LOCK_FILE, '<', $pid_file) - && ($pid = )) - { - chomp($pid); - $msg .= "(PID $pid)\n"; - } else { - $msg .= "(unable to read PID)\n"; - } - if( ! ($foreground) ) { - openlog( $0, "cons,pid", "daemon" ); - syslog( "warning", $msg ); - closelog(); - } - else { - print( STDERR " $msg " ); - } - exit( -1 ); - } -} - -#=== FUNCTION ================================================================ -# NAME: get_interface_for_ip -# PARAMETERS: ip address (i.e. 192.168.0.1) -# RETURNS: array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else -# 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; - last; - } - } - } - } - return $result; -} - -#=== FUNCTION ================================================================ -# NAME: get_interfaces -# PARAMETERS: none -# RETURNS: (list of interfaces) -# DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. -#=============================================================================== -sub get_interfaces { - my @result; - my $PROC_NET_DEV= ('/proc/net/dev'); - - open(PROC_NET_DEV, "<$PROC_NET_DEV") - or die "Could not open $PROC_NET_DEV"; - - my @ifs = ; - - close(PROC_NET_DEV); - - # 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; - } - - return @result; -} - -#=== FUNCTION ================================================================ -# NAME: get_mac -# PARAMETERS: interface name (i.e. eth0) -# RETURNS: (mac address) -# DESCRIPTION: Uses ioctl to get mac address directly from system. -#=============================================================================== -sub get_mac { - my $ifreq= shift; - my $result; - if ($ifreq && length($ifreq) > 0) { - if($ifreq eq "all") { - if(defined($server_ip)) { - $result = &get_local_mac_for_remote_ip($server_ip); - } 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 ($client_mac_address and length($client_mac_address) > 0) { - $result= $client_mac_address; - } - - socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip') - or die "socket: $!"; - - 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; - } - } - } - } - 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: 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 get_local_mac_for_remote_ip { - my $ifreq= shift; - my $result= "00:00:00:00:00:00"; - 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; - } - } - - - return $result; -} - -#=== FUNCTION ================================================================ -# NAME: usage -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub usage { - my( $text, $help ) = @_; - $text = undef if( "h" eq $text ); - (defined $text) && print STDERR "\n$text\n"; - if( (defined $help && $help) || (!defined $help && !defined $text) ) { - print STDERR << "EOF" ; -usage: $0 [-hvf] [-c config] - - -h : this (help) message - -c : config file - -f : foreground, process will not be forked to background - -v : be verbose (multiple to increase verbosity) -EOF - } - print "\n" ; -} - -#=== FUNCTION ================================================================ -# NAME: get_server_addresses -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub get_server_addresses { - my $domain= shift; - my @result; - my $dig_cmd= 'dig +nocomments srv _gosad._tcp.'.$domain; - - my $output= `$dig_cmd 2>&1`; - open (PIPE, "$dig_cmd 2>&1 |"); - while() { - chomp $_; - # If it's not a comment - if($_ =~ m/^[^;]/) { - my @matches= split /\s+/; - - # Push hostname with port - if($matches[3] eq 'SRV') { - push @result, $matches[7].':'.$matches[6]; - } elsif ($matches[3] eq 'A') { - my $i=0; - - # Substitute the hostname with the ip address of the matching A record - foreach my $host (@result) { - if ((split /\:/, $host)[0] eq $matches[0]) { - $result[$i]= $matches[4].':'.(split /\:/, $host)[1]; - } - $i++; - } - } - } - } - close(PIPE); - return @result; -} - - -#=== FUNCTION ================================================================ -# NAME: register_at_server -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub register_at_server { - my ($tmp) = @_; - - # create new passwd and ciphering object for client-server communication - my $new_server_passwd = &create_passwd(); - my $new_server_cipher; - - # detect all client accepted events - opendir(DIR, $event_dir) - or daemon_log("cannot find directory $event_dir!\ngosa-si-client starts without any accepting events!", 1); - my $file_name; - my @events_list = (); - while(defined($file_name = readdir(DIR))){ - if ($file_name eq "." || $file_name eq "..") { - next; - } - push(@events_list, $file_name); - } - my $events = join(",", @events_list); - daemon_log("found events: $events", 1); - - # fill in all possible servers - my @servers; - if (defined $server_domain) { - my @tmp_servers = &get_server_addresses($server_domain); - foreach my $server (@tmp_servers) { unshift(@servers, $server); } - } - # add server address from config file at first position of server list - if (defined $server_address) { - unshift(@servers, $server_address); - } - daemon_log("found servers in configuration file and via DNS:", 5); - foreach my $server (@servers) { - daemon_log("\t$server", 5); - } - - my ($rout, $wout, $reg_server); - foreach my $server (@servers) { - - # create msg hash - my $register_hash = &create_xml_hash("here_i_am", $client_address, $server); - &add_content2xml_hash($register_hash, "new_passwd", $new_server_passwd); - &add_content2xml_hash($register_hash, "mac_address", $client_mac_address); - &add_content2xml_hash($register_hash, "events", $events); - - my $tmp = print Dumper $register_hash; - - # send xml hash to server with general server passwd - my $answer = &send_msg_hash2address($register_hash, $server, $server_passwd); - - if ($answer != 0) { next; } - - # waiting for response - daemon_log("waiting for response...\n", 5); - my $nf = select($rout=$rbits, $wout=$wbits, undef, $server_timeout); - - # something is coming in - if(vec $rout, fileno $input_socket, 1) { - my $crypted_msg; - my $client = $input_socket->accept(); - my $other_end = getpeername($client); - if(not defined $other_end) { - daemon_log("client cannot be identified: $!\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){ - chomp($in_msg); - $crypted_msg = $in_msg; - } else { - daemon_log("cannot read from $actual_ip\n", 5); - } - } - close($client); - - # validate acknowledge msg from server - $new_server_cipher = &create_ciphering($new_server_passwd); - my $msg_hash; - eval { - my $decrypted_msg = &decrypt_msg($crypted_msg, $new_server_cipher); - daemon_log("decrypted register msg: $decrypted_msg", 5); - $msg_hash = $xml->XMLin($decrypted_msg, ForceArray=>1); - }; - if($@) { - daemon_log("ERROR: do not understand the incoming message:" , 5); - daemon_log("$@", 7); - } else { - my $header = @{$msg_hash->{header}}[0]; - if($header eq "registered") { - $reg_server = $server; - last; - } elsif($header eq "denied") { - my $reason = (&get_content_from_xml_hash($msg_hash, "denied"))[0]; - daemon_log("registration at $server denied: $reason", 1); - } else { - daemon_log("cannot register at $server", 1); - } - } - } - # if no answer arrive, try next server in list - - } - - if(defined $reg_server) { - daemon_log("registered at $reg_server", 1); - } else { - daemon_log("cannot register at any server", 1); - daemon_log("exiting!!!", 1); - exit(1); - } - - # update the global available variables - $server_address = $reg_server; - $server_passwd = $new_server_passwd; - $server_cipher = $new_server_cipher; - return; -} - - -#=== FUNCTION ================================================================ -# NAME: create_xml_hash -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -#sub create_xml_hash { -# my ($header, $source, $target, $header_value) = @_; -# my $hash = { -# header => [$header], -# source => [$source], -# target => [$target], -# $header => [$header_value], -# }; -# daemon_log("create_xml_hash:", 7), -# chomp(my $tmp = Dumper $hash); -# daemon_log("\t$tmp\n", 7); -# return $hash -#} - - -#=== FUNCTION ================================================================ -# NAME: create_xml_string -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -#sub create_xml_string { -# my ($xml_hash) = @_ ; -# my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml'); -# $xml_string =~ s/[\n]+//g; -# daemon_log("create_xml_string:\n\t$xml_string\n", 7); -# return $xml_string; -#} - - -#=== FUNCTION ================================================================ -# NAME: add_content2xml_hash -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -#sub add_content2xml_hash { -# my ($xml_ref, $element, $content) = @_; -# if(not exists $$xml_ref{$element} ) { -# $$xml_ref{$element} = []; -# } -# my $tmp = $$xml_ref{$element}; -# push(@$tmp, $content); -# return; -#} - - -#=== FUNCTION ================================================================ -# NAME: get_content_from_xml_hash -# PARAMETERS: ref : reference to the xml hash -# string: key of the value you want -# RETURNS: STRING AND ARRAY -# DESCRIPTION: if key of the hash is either 'header', 'target' or 'source' the -# function returns a string cause it is expected that these keys -# do just have one value, all other keys returns an array!!! -#=============================================================================== -#sub get_content_from_xml_hash { -# my ($xml_ref, $element) = @_; -# my $result = $xml_ref->{$element}; -# if( $element eq "header" || $element eq "target" || $element eq "source") { -# return @$result[0]; -# } -# return @$result; -#} - -# my ($xml_ref, $element) = @_; -# if (exists $xml_ref->{$element}) { -# my $result = $xml_ref->{$element}; -# if( $element eq "header" || $element eq "target" || $element eq "source") { -# return @$result[0]; -# } else { -# return @$result; -# } -# -# } else { -# my $result = (); -# return @$result; -# } -#} - - -#=== FUNCTION ================================================================ -# NAME: encrypt_msg -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -#sub encrypt_msg { -# my ($msg, $my_cipher) = @_; -# if(not defined $my_cipher) { print "no cipher object\n"; } -# $msg = "\0"x(16-length($msg)%16).$msg; -# my $crypted_msg = $my_cipher->encrypt($msg); -# chomp($crypted_msg = &encode_base64($crypted_msg)); -# return $crypted_msg; -#} - - -#=== FUNCTION ================================================================ -# NAME: decrypt_msg -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -#sub decrypt_msg { -# my ($crypted_msg, $my_cipher) = @_ ; -# $crypted_msg = &decode_base64($crypted_msg); -# my $msg = $my_cipher->decrypt($crypted_msg); -# $msg =~ s/\0*//g; -# return $msg; -#} - - -#=== FUNCTION ================================================================ -# NAME: create_ciphering -# PARAMETERS: -# RETURNS: cipher object -# DESCRIPTION: -#=============================================================================== -#sub create_ciphering { -# my ($passwd) = @_; -# $passwd = substr(md5_hex("$passwd") x 32, 0, 32); -# my $iv = substr(md5_hex('GONICUS GmbH'),0, 16); -# -# #daemon_log("iv: $iv", 7); -# #daemon_log("key: $passwd", 7); -# my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC()); -# $my_cipher->set_iv($iv); -# return $my_cipher; -#} - - -#=== FUNCTION ================================================================ -# NAME: create_passwd -# PARAMETERS: -# RETURNS: cipher object -# DESCRIPTION: -#=============================================================================== -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; -} - - -#=== FUNCTION ================================================================ -# NAME: send_msg_hash2address -# PARAMETERS: msg string - xml message -# PeerAddr string - socket address to send msg -# PeerPort string - socket port, if not included in socket address -# RETURNS: nothing -# DESCRIPTION: ???? -#=============================================================================== -#sub send_msg_hash2address { -# my ($msg_hash, $address, $passwd) = @_ ; -# -# # fetch header for logging -# my $header = @{$msg_hash->{header}}[0]; -# -# # generiere xml string -# my $msg_xml = &create_xml_string($msg_hash); -# -# # hole das entsprechende passwd aus dem hash -# if(not defined $passwd) { -# if(exists $known_hosts->{$address}) { -# $passwd = $known_hosts->{$address}->{passwd}; -# } elsif ($address eq $server_address) { -# $passwd = $server_passwd; -# } else { -# daemon_log("$address not known, neither as server nor as client", 1); -# return "failed"; -# } -# } -# -# # erzeuge ein ciphering object -# my $act_cipher = &create_ciphering($passwd); -# -# # encrypt xml msg -# my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher); -# -# # öffne socket -# my $socket = &open_socket($address); -# if(not defined $socket){ -# daemon_log("cannot open socket to $address, server not reachable", 1); -# daemon_log("cannot send '$header'-msg", 1); -# return "failed"; -# } -# -# # versende xml msg -# print $socket $crypted_msg."\n"; -# -# # schließe socket -# close $socket; -# -# daemon_log("send '$header'-msg to $address", 5); -# daemon_log("crypted_msg:\n\t$crypted_msg", 7); -# -# return "done"; -#} - - -#=== 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: -#=============================================================================== -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) { - #daemon_log("cannot connect to socket at $PeerAddr, $@\n"); - return; - } - daemon_log("open_socket:\n\t$PeerAddr", 7); - return $socket; -} - - -#=== FUNCTION ================================================================ -# NAME: read_from_socket -# PARAMETERS: socket fh - -# RETURNS: result string - readed characters from socket -# DESCRIPTION: reads data from socket in 16 byte steps -#=============================================================================== -sub read_from_socket { - my ($socket) = @_; - my $result = ""; - - $socket->blocking(1); - $result = <$socket>; - - $socket->blocking(0); - while ( my $char = <$socket> ) { - if (not defined $char) { last } - $result .= $char; - } - return $result; - - - -# my ($socket) = @_; -# 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: print_known_hosts_hash -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub print_known_hosts_hash { - my ($tmp) = @_; - print "####################################\n"; - print "# status of known_hosts\n"; - my $hosts; - my $host_hash; - my @hosts = keys %$known_hosts; - foreach my $host (@hosts) { - #my @elements = keys %$known_hosts->{$host}; - my $status = $known_hosts->{$host}->{status} ; - my $passwd = $known_hosts->{$host}->{passwd}; - my $timestamp = $known_hosts->{$host}->{timestamp}; - print "$host\n"; - print "\t$status\n"; - print "\t$passwd\n"; - print "\t$timestamp\n"; - } - print "####################################\n"; - return; -} - -#=== FUNCTION ================================================================ -# NAME: -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub create_known_hosts_entry { - my ($hostname) = @_; - $known_hosts->{$hostname} = {}; - $known_hosts->{$hostname}->{status} = "none"; - $known_hosts->{$hostname}->{passwd} = "none"; - $known_hosts->{$hostname}->{timestamp} = "none"; - return; -} - - -#=== FUNCTION ================================================================ -# NAME: -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub update_known_hosts_entry { - my ($hostname, $status, $passwd, $timestamp) = @_; - 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; - $month+=1; - $month = $month < 10 ? $month = "0".$month : $month; - $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; - $year+=1900; - my $t = "$year$month$monthday$hours$minutes$seconds"; - - if($status) { - $known_hosts->{$hostname}->{status} = $status; - } - if($passwd) { - $known_hosts->{$hostname}->{passwd} = $passwd; - } - if($timestamp) { - $t = $timestamp; - } - $known_hosts->{$hostname}->{timestamp} = $t; - return; -} - - -#=== FUNCTION ================================================================ -# NAME: -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub add_content2known_hosts { - my ($hostname, $element, $content) = @_; - 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; - $month+=1; - $month = $month < 10 ? $month = "0".$month : $month; - $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; - $year+=1900; - my $t = "$year$month$monthday$hours$minutes$seconds"; - - $known_hosts->{$hostname}->{$element} = $content; - $known_hosts->{$hostname}->{timestamp} = $t; - return; -} - - -#=== FUNCTION ================================================================ -# NAME: -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub process_incoming_msg { - my ($crypted_msg) = @_; - if(not defined $crypted_msg) { - daemon_log("function 'process_incoming_msg': got no msg", 7); - } - $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("msg from host:", 1); - daemon_log("\t$host", 1); - daemon_log("crypted msg:", 7); - daemon_log("\t$crypted_msg", 7); - - my $act_cipher = &create_ciphering($server_passwd); - - # try to decrypt incoming msg - my ($msg, $msg_hash); - eval{ - $msg = &decrypt_msg($crypted_msg, $act_cipher); - $msg_hash = $xml->XMLin($msg, ForceArray=>1); - }; - if($@) { - daemon_log("ERROR: incoming msg cannot be decrypted with server passwd", 1); - return; - } - - my $header = @{$msg_hash->{header}}[0]; - - daemon_log("receive '$header' from $host", 1); -# daemon_log("header from msg:", 1); -# daemon_log("\t$header", 1); -# daemon_log("msg to process:", 7); -# daemon_log("\t$msg", 7); - - #check whether msg to process is a event - opendir(DIR, $event_dir) - or daemon_log("cannot find directory $event_dir, no events specified", 5); - my $file_name; - while(defined($file_name = readdir(DIR))){ - if ($file_name eq "." || $file_name eq "..") { - next; - } - if ($file_name eq $header) { - my $cmd = "$event_dir/$file_name '$msg'"; - my $result_xml = ""; - open(PIPE, "$cmd 2>&1 |"); - while() { - $result_xml.=$_; - last; - } - close(PIPE); - my $res_hash = &transform_msg2hash($result_xml); - my $res_target = @{$res_hash->{target}}[0]; - &send_msg_hash2address($res_hash, $server_address); - - return; - } - } - close(DIR); - daemon_log("could not assign the msg $header to an event", 5); - - if ($header eq 'new_ldap_config') { if ($ldap_enabled == 1) {&new_ldap_config($msg_hash)}} - elsif ($header eq 'ping') { &got_ping($msg_hash) } - elsif ($header eq 'wake_up') { &execute_event($msg_hash)} - elsif ($header eq 'new_passwd') { &new_passwd()} - else { daemon_log("ERROR: no function assigned to msg $header", 5) } - - return; -} - - -#=== FUNCTION ================================================================ -# NAME: -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub update_status { - my ($new_status) = @_ ; - my $out_hash = &create_xml_hash("update_status", $client_address, $server_address); - &add_content2xml_hash($out_hash, "update_status", $new_status); - &send_msg_hash2address($out_hash, $server_address); - return; -} - - -#=== FUNCTION ================================================================ -# NAME: -# PARAMETERS: -# RETURNS: -# DESCRIPTION: -#=============================================================================== -sub server_leaving { - my ($msg_hash) = @_ ; - my $source = &get_content_from_xml_hash("source"); - my $header = &get_content_from_xml_hash("header"); - - daemon_log("gosa daemon $source is going down, cause registration procedure", 1); - my $server_address = "none"; - my $server_passwd = "none"; - my $server_cipher = "none"; - - # reinitialization of default values in config file - &read_configfile; - - # registrated at new daemon - ®ister_at_server(); - - return; -} - - -sub got_ping { - my ($msg_hash) = @_ ; - - my $source = &get_content_from_xml_hash($msg_hash, 'source'); - my $target = &get_content_from_xml_hash($msg_hash, 'target'); - my $header = &get_content_from_xml_hash($msg_hash, 'header'); - - &add_content2known_hosts(hostname=>$target, status=>$header); - - my $out_hash = &create_xml_hash("got_ping", $target, $source); - &send_msg_hash2address($out_hash, $source, $server_passwd); - - return; -} - - -sub new_ldap_config { - my ($msg_hash) = @_ ; - my $element; - my @ldap_uris; - my $ldap_base; - my @ldap_options; - my @pam_options; - my @nss_options; - my $goto_admin; - my $goto_secret; - - # Transform input into array - while ( my ($key, $value) = each(%$msg_hash) ) { - if ($key =~ /^(source|target|header)$/) { - next; - } - - foreach $element (@$value) { - if ($key =~ /^ldap_uri$/) { - push (@ldap_uris, $element); - next; - } - if ($key =~ /^ldap_base$/) { - $ldap_base= $element; - next; - } - if ($key =~ /^goto_admin$/) { - $goto_admin= $element; - next; - } - if ($key =~ /^goto_secret$/) { - $goto_secret= $element; - next; - } - if ($key =~ /^ldap_cfg$/) { - push (@ldap_options, "$element"); - next; - } - if ($key =~ /^pam_cfg$/) { - push (@pam_options, "$element"); - next; - } - if ($key =~ /^nss_cfg$/) { - push (@nss_options, "$element"); - next; - } - } - } - - # Setup ldap.conf - my $file1; - my $file2; - open(file1, "> $ldap_config"); - print file1 "# This file was automatically generated by gosa-si-client. Do not change.\n"; - print file1 "URI"; - foreach $element (@ldap_uris) { - print file1 " $element"; - } - print file1 "\nBASE $ldap_base\n"; - foreach $element (@ldap_options) { - print file1 "$element\n"; - } - close (file1); - daemon_log("wrote $ldap_config", 5); - - # Setup pam_ldap.conf / libnss_ldap.conf - open(file1, "> $pam_config"); - open(file2, "> $nss_config"); - print file1 "# This file was automatically generated by gosa-si-client. Do not change.\n"; - print file2 "# This file was automatically generated by gosa-si-client. Do not change.\n"; - print file1 "uri"; - print file2 "uri"; - foreach $element (@ldap_uris) { - print file1 " $element"; - print file2 " $element"; - } - print file1 "\nbase $ldap_base\n"; - print file2 "\nbase $ldap_base\n"; - foreach $element (@pam_options) { - print file1 "$element\n"; - } - foreach $element (@nss_options) { - print file2 "$element\n"; - } - close (file2); - daemon_log("wrote $nss_config", 5); - close (file1); - daemon_log("wrote $pam_config", 5); - - # Create goto.secrets if told so - if (defined $goto_admin){ - open(file1, "> /etc/goto/secret"); - close(file1); - chown(0,0, "/etc/goto/secret"); - chmod(0600, "/etc/goto/secret"); - open(file1, "> /etc/goto/secret"); - print file1 $goto_admin.":".$goto_secret."\n"; - close(file1); - daemon_log("wrote /etc/goto/secret", 5); - } - - return; - -} - - -sub execute_event { - my ($msg_hash)= @_; - my $configdir= '/etc/gosa-si/client/events/'; - my $result; - - my $header = &get_content_from_xml_hash($msg_hash, 'header'); - my $source = &get_content_from_xml_hash($msg_hash, 'source'); - my $target = &get_content_from_xml_hash($msg_hash, 'target'); - - - if((not defined $source) - && (not defined $target) - && (not defined $header)) { - daemon_log("ERROR: Entries missing in XML msg for gosa events under $configdir"); - } else { - my $parameters=""; - my @params = &get_content_from_xml_hash($msg_hash, $header); - my $params = join(", ", @params); - daemon_log("execute_event: got parameters: $params", 5); - - if (@params) { - foreach my $param (@params) { - my $param_value = (&get_content_from_xml_hash($msg_hash, $param))[0]; - daemon_log("execute_event: parameter -> value: $param -> $param_value", 7); - $parameters.= " ".$param_value; - } - } - - my $cmd= $configdir.$header."$parameters"; - daemon_log("execute_event: executing cmd: $cmd", 7); - $result= ""; - open(PIPE, "$cmd 2>&1 |"); - while() { - $result.=$_; - } - close(PIPE); - } - - # process the event result - - - return; -} - - -sub new_passwd { - # my ($msg_hash) = @_ ; - my $new_server_passwd = &create_passwd(); - my $new_server_cipher = &create_ciphering($new_server_passwd); - - my $out_hash = &create_xml_hash("new_passwd", $client_address, $server_address, $new_server_passwd); - - &send_msg_hash2address($out_hash, $server_address, $server_passwd); - - $server_passwd = $new_server_passwd; - $server_cipher = $new_server_cipher; - return; -} - - - - -#==== MAIN = main ============================================================== - -# parse commandline options -Getopt::Long::Configure( "bundling" ); -GetOptions("h|help" => \&usage, - "c|config=s" => \$cfg_file, - "f|foreground" => \$foreground, - "v|verbose+" => \$verbose, - ); - -# read and set config parameters -&check_cmdline_param ; -&read_configfile; -&check_pid; - -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: $!"; -} - - -# restart daemon log file -if(-e $log_file ) { unlink $log_file } -daemon_log(" ", 1); -daemon_log("$0 started!", 1); - -# Just fork, if we"re not in foreground mode -if( ! $foreground ) { $pid = fork(); } -else { $pid = $$; } - -# Do something useful - put our PID into the pid_file -if( 0 != $pid ) { - open( LOCK_FILE, ">$pid_file" ); - print LOCK_FILE "$pid\n"; - close( LOCK_FILE ); - if( !$foreground ) { exit( 0 ) }; -} - -# detect own ip and mac address -$network_interface= &get_interface_for_ip($client_ip); -$client_mac_address= &get_mac($network_interface); - -# ($client_ip, $client_mac_address) = &get_ip_and_mac(); -#if (not defined $client_ip) { -# die "EXIT: ip address of $0 could not be detected"; -#} -daemon_log("client ip address detected: $client_ip", 1); -daemon_log("client mac address detected: $client_mac_address", 1); - -# prepare variables -if (defined $server_ip && defined $server_port) { - $server_address = $server_ip.":".$server_port; -} -$client_address = $client_ip.":".$client_port; - -# setup xml parser -$xml = new XML::Simple(); - -# create input socket -daemon_log(" ", 1); -$rbits = $wbits = $ebits = ""; -$input_socket = IO::Socket::INET->new(LocalPort => $client_port, - Type => SOCK_STREAM, - Reuse => 1, - Listen => 20, - ); -if(not defined $input_socket){ - daemon_log("cannot be a tcp server at $client_port : $@\n"); -} else { - daemon_log("start client at $client_address",1) ; - vec($rbits, fileno $input_socket, 1) = 1; - vec($wbits, fileno $input_socket, 1) = 1; -} - -# register at server -daemon_log(" ", 1); -®ister_at_server(); - - -############## -# Debugging -############# -#sleep(2); -#&update_status("ich_bin_ein_neuer_status"); - -################################### -#everything ready, okay, lets start -################################### -while(1) { - my ($rout, $wout); - my $nf = select($rout=$rbits, $wout=$wbits, undef, undef); - - # error handling - if($nf < 0 ) { - } - - # something is coming in - if(vec $rout, fileno $input_socket, 1) { - my $client = $input_socket->accept(); - my $other_end = getpeername($client); - - if(not defined $other_end) { - daemon_log("client cannot be identified: $!"); - } else { - my ($port, $iaddr) = unpack_sockaddr_in($other_end); - my $actual_ip = inet_ntoa($iaddr); - daemon_log("accept client from $actual_ip", 5); - my $in_msg = &read_from_socket($client); - if(defined $in_msg){ - chomp($in_msg); - $in_msg = $in_msg.".".$actual_ip; - &process_incoming_msg($in_msg); - - } - } - } -} - - - - diff --git a/gosa-si-poe/gosa-si-server b/gosa-si-poe/gosa-si-server deleted file mode 100755 index 19fdc07d1..000000000 --- a/gosa-si-poe/gosa-si-server +++ /dev/null @@ -1,731 +0,0 @@ -#!/usr/bin/perl -#=============================================================================== -# -# FILE: gosa-sd -# -# USAGE: ./gosa-sd -# -# DESCRIPTION: -# -# OPTIONS: --- -# REQUIREMENTS: libconfig-inifiles-perl libcrypt-rijndael-perl libxml-simple-perl -# libdata-dumper-simple-perl libdbd-sqlite3-perl libnet-ldap-perl -# libpoe-perl -# BUGS: --- -# NOTES: -# AUTHOR: (Andreas Rettenberger), -# COMPANY: -# VERSION: 1.0 -# CREATED: 12.09.2007 08:54:41 CEST -# REVISION: --- -#=============================================================================== - -use strict; -use warnings; -use Getopt::Long; -use Config::IniFiles; -use POSIX; -use Time::HiRes qw( gettimeofday ); - -use Fcntl; -use IO::Socket::INET; -use IO::Handle; -use IO::Select; -use Symbol qw(qualify_to_ref); -use Crypt::Rijndael; -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; -use POE qw(Component::Server::TCP); - -my $modules_path = "/usr/lib/gosa-si/modules"; -use lib "/usr/lib/gosa-si/modules"; - -my (%cfg_defaults, $foreground, $verbose, $ping_timeout); -my ($bus, $msg_to_bus, $bus_cipher); -my ($server, $server_mac_address, $server_events); -my ($gosa_server, $job_queue_timeout, $job_queue_table_name, $job_queue_file_name,$job_queue_loop_delay); -my ($known_modules, $known_clients_file_name, $known_server_file_name); -my ($max_clients); -my ($pid_file, $procid, $pid, $log_file); -my (%free_child, %busy_child, $child_max, $child_min, %child_alive_time, $child_timeout); -my ($arp_activ, $arp_fifo, $arp_fifo_path); - -# variables declared in config file are always set to 'our' -our (%cfg_defaults, $log_file, $pid_file, - $bus_activ, $bus_passwd, $bus_ip, $bus_port, - $server_activ, $server_ip, $server_port, $server_passwd, $max_clients, - $arp_activ, $arp_fifo_path, - $gosa_activ, $gosa_passwd, $gosa_ip, $gosa_port, $gosa_timeout, -); - -# additional variable which should be globaly accessable -our $xml; -our $server_address; -our $bus_address; -our $gosa_address; -our $no_bus; -our $no_arp; -our $verbose; -our $forground; -our $cfg_file; - -# specifies the verbosity of the daemon_log -$verbose = 0 ; - -# if foreground is not null, script will be not forked to background -$foreground = 0 ; - -# specifies the timeout seconds while checking the online status of a registrating client -$ping_timeout = 5; - -$no_bus = 0; - -$no_arp = 0; - -# name of table for storing gosa jobs -our $job_queue_table_name = 'jobs'; -our $job_db; - -# holds all other gosa-sd as well as the gosa-sd-bus -our $known_server_db; - -# holds all registrated clients -our $known_clients_db; - -%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], - "job_queue_timeout" => [\$job_queue_timeout, undef], - "job_queue_file_name" => [\$job_queue_file_name, '/var/lib/gosa-si/jobs.db'], - "job_queue_loop_delay" => [\$job_queue_loop_delay, 3], - "known_clients_file_name" => [\$known_clients_file_name, '/var/lib/gosa-si/known_clients.db' ], - "known_server_file_name" => [\$known_server_file_name, '/var/lib/gosa-si/known_server.db'], - }, -"bus" => - {"bus_activ" => [\$bus_activ, "on"], - "bus_passwd" => [\$bus_passwd, ""], - "bus_ip" => [\$bus_ip, "0.0.0.0"], - "bus_port" => [\$bus_port, "20080"], - }, -"server" => - {"server_activ" => [\$server_activ, "on"], - "server_ip" => [\$server_ip, "0.0.0.0"], - "server_port" => [\$server_port, "20081"], - "server_passwd" => [\$server_passwd, ""], - "max_clients" => [\$max_clients, 100], - }, -"arp" => - {"arp_activ" => [\$arp_activ, "on"], - "arp_fifo_path" => [\$arp_fifo_path, "/var/run/gosa-si/arp-notify"], - }, -"gosa" => - {"gosa_activ" => [\$gosa_activ, "on"], - "gosa_ip" => [\$gosa_ip, "0.0.0.0"], - "gosa_port" => [\$gosa_port, "20082"], - "gosa_passwd" => [\$gosa_passwd, "none"], - }, - ); - - -#=== FUNCTION ================================================================ -# NAME: usage -# PARAMETERS: nothing -# RETURNS: nothing -# DESCRIPTION: print out usage text to STDERR -#=============================================================================== -sub usage { - print STDERR << "EOF" ; -usage: $0 [-hvf] [-c config] - - -h : this (help) message - -c : config file - -f : foreground, process will not be forked to background - -v : be verbose (multiple to increase verbosity) - -no-bus : starts $0 without connection to bus - -no-arp : starts $0 without connection to arp module - -EOF - print "\n" ; -} - - -#=== FUNCTION ================================================================ -# NAME: read_configfile -# PARAMETERS: cfg_file - string - -# RETURNS: nothing -# DESCRIPTION: read cfg_file and set variables -#=============================================================================== -sub read_configfile { - my $cfg; - if( defined( $cfg_file) && ( length($cfg_file) > 0 )) { - if( -r $cfg_file ) { - $cfg = Config::IniFiles->new( -file => $cfg_file ); - } else { - print STDERR "Couldn't read config file!\n"; - } - } else { - $cfg = Config::IniFiles->new() ; - } - foreach my $section (keys %cfg_defaults) { - foreach my $param (keys %{$cfg_defaults{ $section }}) { - my $pinfo = $cfg_defaults{ $section }{ $param }; - ${@$pinfo[ 0 ]} = $cfg->val( $section, $param, @$pinfo[ 1 ] ); - } - } -} - - -#=== FUNCTION ================================================================ -# NAME: logging -# PARAMETERS: level - string - default 'info' -# msg - string - -# facility - string - default 'LOG_DAEMON' -# RETURNS: nothing -# DESCRIPTION: function for logging -#=============================================================================== -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", "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 ); - } -#log into syslog -# 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)) { - $cfg_file = "/etc/gosa-si/server.conf"; - if(! -r $cfg_file) { - $err_config = "please specify a config file"; - $err_counter += 1; - } - } - if( $err_counter > 0 ) { - &usage( "", 1 ); - if( defined( $err_config)) { print STDERR "$err_config\n"} - print STDERR "\n"; - exit( -1 ); - } -} - - -#=== FUNCTION ================================================================ -# NAME: check_pid -# PARAMETERS: nothing -# RETURNS: nothing -# DESCRIPTION: handels pid processing -#=============================================================================== -sub check_pid { - $pid = -1; - # Check, if we are already running - if( open(LOCK_FILE, "<$pid_file") ) { - $pid = ; - if( defined $pid ) { - chomp( $pid ); - if( -f "/proc/$pid/stat" ) { - my($stat) = `cat /proc/$pid/stat` =~ m/$pid \((.+)\).*/; - if( $0 eq $stat ) { - close( LOCK_FILE ); - exit -1; - } - } - } - close( LOCK_FILE ); - unlink( $pid_file ); - } - - # create a syslog msg if it is not to possible to open PID file - if (not sysopen(LOCK_FILE, $pid_file, O_WRONLY|O_CREAT|O_EXCL, 0644)) { - my($msg) = "Couldn't obtain lockfile '$pid_file' "; - if (open(LOCK_FILE, '<', $pid_file) - && ($pid = )) - { - chomp($pid); - $msg .= "(PID $pid)\n"; - } else { - $msg .= "(unable to read PID)\n"; - } - if( ! ($foreground) ) { - openlog( $0, "cons,pid", "daemon" ); - syslog( "warning", $msg ); - closelog(); - } - else { - print( STDERR " $msg " ); - } - exit( -1 ); - } -} - -#=== FUNCTION ================================================================ -# NAME: import_modules -# PARAMETERS: module_path - string - abs. path to the directory the modules -# are stored -# RETURNS: nothing -# DESCRIPTION: each file in module_path which ends with '.pm' is imported by -# "require 'file';" -#=============================================================================== -sub import_modules { - daemon_log(" ", 1); - - if (not -e $modules_path) { - daemon_log("ERROR: cannot find directory or directory is not readable: $modules_path", 1); - } - - opendir (DIR, $modules_path) or die "ERROR while loading modules from directory $modules_path : $!\n"; - while (defined (my $file = readdir (DIR))) { - if (not $file =~ /(\S*?).pm$/) { - next; - } - eval { require $file; }; - if ($@) { - daemon_log("ERROR: gosa-si-server could not load module $file", 1); - daemon_log("$@", 5); - } else { - my $mod_name = $1; - my $info = eval($mod_name.'::get_module_info()'); - my ($input_address, $input_key, $input, $input_active, $input_type) = @{$info}; - $known_modules->{$mod_name} = $info; - - daemon_log("module $mod_name loaded", 1); - } - } - - # for debugging - #while ( my ($module, $tag_hash) = each(%$known_modules)) { - # print "\tmodule: $module"."\n"; - # print "\ttags: ".join(", ", keys(%$tag_hash))."\n"; - #} - close (DIR); -} - - -#=== FUNCTION ================================================================ -# NAME: sig_int_handler -# PARAMETERS: signal - string - signal arose from system -# RETURNS: noting -# DESCRIPTION: handels tasks to be done befor signal becomes active -#=============================================================================== -sub sig_int_handler { - my ($signal) = @_; - - daemon_log("shutting down gosa-si-server", 1); - exit(1); -} -$SIG{INT} = \&sig_int_handler; - - -#=== FUNCTION ================================================================ -# NAME: create_known_client -# PARAMETERS: hostname - string - key for the hash known_clients -# RETURNS: nothing -# DESCRIPTION: creates a dummy entry for hostname in known_clients -#=============================================================================== -sub create_known_client { - my ($hostname) = @_; - - my $entry = { table=>'known_clients', - hostname=>$hostname, - status=>'none', - hostkey=>'none', - timestamp=>'none', - macaddress=>'none', - events=>'none', - }; - my $res = $known_clients_db->add_dbentry($entry); - if ($res > 0) { - daemon_log("ERROR: cannot add entry to known_clients.db: $res", 1); - } - - return; -} - -#==== MAIN = main ============================================================== -# parse commandline options -Getopt::Long::Configure( "bundling" ); -GetOptions("h|help" => \&usage, - "c|config=s" => \$cfg_file, - "f|foreground" => \$foreground, - "v|verbose+" => \$verbose, - "no-bus+" => \$no_bus, - "no-arp+" => \$no_arp, - ); - -# read and set config parameters -&check_cmdline_param ; -&read_configfile; -&check_pid; - -$SIG{CHLD} = 'IGNORE'; - -# forward error messages to logfile -if( ! $foreground ) { - open(STDERR, '>>', $log_file); - open(STDOUT, '>>', $log_file); -} - -# 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 = $$; -} - -# Do something useful - put our PID into the pid_file -if( 0 != $pid ) { - open( LOCK_FILE, ">$pid_file" ); - print LOCK_FILE "$pid\n"; - close( LOCK_FILE ); - if( !$foreground ) { - exit( 0 ) - }; -} - -daemon_log(" ", 1); -daemon_log("$0 started!", 1); - -# delete old DBsqlite lock files -system('rm -f /tmp/gosa_si_lock*'); - -# connect to gosa-si job queue -my @job_col_names = ("id", "timestamp", "status", "result", "headertag", "targettag", "xmlmessage", "macaddress"); -$job_db = GOSA::DBsqlite->new($job_queue_file_name); -$job_db->create_table('jobs', \@job_col_names); - -# connect to known_clients_db -my @clients_col_names = ('hostname', 'status', 'hostkey', 'timestamp', 'macaddress', 'events'); -$known_clients_db = GOSA::DBsqlite->new($known_clients_file_name); -$known_clients_db->create_table('known_clients', \@clients_col_names); - -# connect to known_server_db -my @server_col_names = ('hostname', 'status', 'hostkey', 'timestamp'); -$known_server_db = GOSA::DBsqlite->new($known_server_file_name); -$known_server_db->create_table('known_server', \@server_col_names); - -# import all modules -&import_modules; - -# check wether all modules are gosa-si valid passwd check - -# create reading and writing vectors -my $rbits = my $wbits = my $ebits = ""; - -# add all module inputs to listening vector -# while( my ($mod_name, $info) = each %$known_modules ) { -# my ($input_address, $input_key, $input, $input_activ, $input_type) = @{$info}; -# vec($rbits, fileno $input, 1) = 1; -# -# } - - -## start arp fifo -#if ($no_arp > 0) { -# $arp_activ = "off"; -#} -#my $my_fifo; -#if($arp_activ eq "on") { -# daemon_log(" ", 1); -# $my_fifo = &open_fifo($arp_fifo_path); -# if($my_fifo == 0) { die "fifo file disappeared\n" } -# sysopen($arp_fifo, $arp_fifo_path, O_RDWR) or die "can't read from $arp_fifo: $!" ; -# -# vec($rbits, fileno $arp_fifo, 1) = 1; -#} -# - -################################### -##everything ready, okay, lets start -################################### -#while(1) { -# -# # add all handles from the childs -# while ( my ($pid, $child_hash) = each %busy_child ) { -# -# # check whether process still exists -# my $exitus_pid = waitpid($pid, WNOHANG); -# if($exitus_pid != 0) { -# delete $busy_child{$pid}; -# next; -# } -# -# # add child fhd to the listener -# my $fhd = $$child_hash{'pipe_rd'}; -# vec($rbits, fileno $fhd, 1) = 1; -# } -# -# my ($rout, $wout); -# my $nf = select($rout=$rbits, $wout=$wbits, undef, $job_queue_timeout); -# -# # error handling -# if($nf < 0 ) { -# } -# -# -## if($arp_activ eq "on" && vec($rout, fileno $arp_fifo, 1)) { -## my $in_msg = <$arp_fifo>; -## chomp($in_msg); -## print "arp_activ: msg: $in_msg\n"; -## my $act_passwd = $known_daemons->{$bus_address}->{passwd}; -## print "arp_activ: arp_passwd: $act_passwd\n"; -## -## my $in_msg_hash = $xml->XMLin($in_msg, ForceArray=>1); -## -## my $target = &get_content_from_xml_hash($in_msg_hash, 'target'); -## -## if ($target eq $server_address) { -## print "arp_activ: forward to server\n"; -## my $arp_cipher = &create_ciphering($act_passwd); -## my $crypted_msg = &encrypt_msg($in_msg, $arp_cipher); -## &activating_child($crypted_msg, $server_ip); -## } else { -## print "arp_activ: send to bus\n"; -## &send_msg_hash2address($in_msg_hash, $bus_address); -## } -## print "\n"; -## } -# -# -# # check input fhd of all modules -# while ( my ($mod_name, $info) = each %$known_modules) { -# my $input_fhd = @{$info}[2]; -# my $input_activ = @{$info}[3]; -# if (vec($rout, fileno $input_fhd, 1) && $input_activ eq 'on') { -# daemon_log(" ", 1); -# my $client = $input_fhd->accept(); -# my $other_end = getpeername($client); -# if(not defined $other_end) { -# daemon_log("client cannot be identified: $!"); -# } else { -# my ($port, $iaddr) = unpack_sockaddr_in($other_end); -# my $actual_ip = inet_ntoa($iaddr); -# daemon_log("accept client at daemon socket from $actual_ip", 5); -# my $in_msg = &read_from_socket($client); -# if(defined $in_msg){ -# chomp($in_msg); -# &activating_child($in_msg, $actual_ip, $client); -# } else { -# daemon_log("cannot read from $actual_ip", 5); -# } -# } -# } -# } -# -# # check all processing childs whether they are finished ('done') or -# while ( my ($pid, $child_hash) = each %busy_child ) { -# my $fhd = $$child_hash{'pipe_rd'}; -# -# if (vec($rout, fileno $fhd, 1) ) { -# daemon_log("process child $pid is ready to read", 5); -# -# my $in_msg; -# while (1) { -# my $part_in_msg = <$fhd>; -# if( $part_in_msg eq "ENDMESSAGE\n") { -# last; -# } -# $in_msg .= $part_in_msg; -# } -# chomp($in_msg); -# -# if (not defined $in_msg) { -# next; -# } elsif ($in_msg =~ "done") { -# daemon_log("process child read: $in_msg", 7); -# delete $busy_child{$pid}; -# $free_child{$pid} = $child_hash; -# -# } else { -# daemon_log("process child read:", 7); -# daemon_log("\n$in_msg", 8); -# # send computed answer back to connected client -# my $act_client = $busy_child{$pid}{client_ref}; -# print $act_client $in_msg."\n"; -# delete $busy_child{$pid}; -# $free_child{$pid} = $child_hash; -# -# } -# } -# } -# -# -# } -# -# -#} - -POE::Session->create -( - inline_states => { - _start => \&trigger_db_loop, - watch_for_new_jobs => \&watch_for_new_jobs, - } -); - -POE::Component::Server::TCP->new -( - Port => $server_port, - ClientInput => \&client_input, -); - -POE::Kernel->run(); -exit; - -sub client_input { - my ($heap,$input,$wheel) = @_[HEAP, ARG0, ARG1]; - ###################################### - # forward msg to all imported modules - no strict "refs"; - my $answer; - my %act_modules = %$known_modules; - while( my ($module, $info) = each(%act_modules)) { - daemon_log("Processing module ".$module, 3); - my $tmp = &{ $module."::process_incoming_msg" }($input.".".$heap->{remote_ip}."\n"); - if (defined $tmp) { - $answer = $tmp; - } - daemon_log("Got answer from module ".$module.": ".$answer,3); - } - daemon_log("processing of msg finished", 5); - - if (defined $answer) { - $heap->{client}->put($answer); - } else { - $heap->{client}->put("done\n"); - } -} - -sub trigger_db_loop { - my ($kernel) = $_[KERNEL]; - $kernel->delay_set('watch_for_new_jobs',3); -} - -sub watch_for_new_jobs { - my ($kernel,$heap) = @_[KERNEL, HEAP]; - - # check gosa job queue for jobs with executable timestamp - 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; - $month+=1; - $month = $month < 10 ? $month = "0".$month : $month; - $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; - $year+=1900; - my $timestamp = "$year$month$monthday$hours$minutes$seconds"; - - my $res = $job_db->select_dbentry( { table=>$job_queue_table_name, status=>'waiting', timestamp=>$timestamp } ); - - while( my ($id, $hit) = each %{$res} ) { - - my $jobdb_id = $hit->{id}; - my $macaddress = $hit->{macaddress}; - my $job_msg_hash = &transform_msg2hash($hit->{xmlmessage}); - my $out_msg_hash = $job_msg_hash; - my $res_hash = $known_clients_db->select_dbentry( {table=>'known_clients', macaddress=>$macaddress} ); - # expect macaddress is unique!!!!!! - my $target = $res_hash->{1}->{hostname}; - - if (not defined $target) { - &daemon_log("ERROR: no host found for mac address: $job_msg_hash->{mac}[0]", 1); - &daemon_log("xml message: $hit->{xmlmessage}", 5); - my $update_hash = { table=>$job_queue_table_name, - update=> [ { status=>['error'], result=>["no host found for mac address"] } ], - where=> [ { id=>[$jobdb_id] } ], - }; - my $res = $job_db->update_dbentry($update_hash); - - next; - } - - # add target - &add_content2xml_hash($out_msg_hash, "target", $target); - - # add new header - my $out_header = $job_msg_hash->{header}[0]; - $out_header =~ s/job_/gosa_/; - delete $out_msg_hash->{header}; - &add_content2xml_hash($out_msg_hash, "header", $out_header); - - # add sqlite_id - &add_content2xml_hash($out_msg_hash, "jobdb_id", $jobdb_id); - - my $out_msg = &create_xml_string($out_msg_hash); - - # encrypt msg as a GosaPackage module - my $cipher = &create_ciphering($gosa_passwd); - my $crypted_out_msg = &encrypt_msg($out_msg, $cipher); - - my $error = &send_msg_hash2address($out_msg_hash, "$gosa_ip:$gosa_port", $gosa_passwd); - - if ($error == 0) { - my $sql = "UPDATE '$job_queue_table_name' SET status='processing', targettag='$target' WHERE id='$jobdb_id'"; - my $res = $job_db->exec_statement($sql); - } else { - my $update_hash = { table=>$job_queue_table_name, - update=> [ { status=>'error' } ], - where=> [ { id=>$jobdb_id } ], - }; - my $res = $job_db->update_dbentry($update_hash); - } - } - - $kernel->delay_set('watch_for_new_jobs',3); -} diff --git a/gosa-si-poe/modules/DBsqlite.pm b/gosa-si-poe/modules/DBsqlite.pm deleted file mode 100644 index 20463d782..000000000 --- a/gosa-si-poe/modules/DBsqlite.pm +++ /dev/null @@ -1,377 +0,0 @@ -package GOSA::DBsqlite; - - -use strict; -use warnings; -use DBI; -use Data::Dumper; -use threads; -use Time::HiRes qw(usleep); - -my $col_names = {}; - -sub new { - my $class = shift; - my $db_name = shift; - - my $lock='/tmp/gosa_si_lock'; - my $_lock = $db_name; - $_lock =~ tr/\//_/; - $lock.=$_lock; - my $self = {dbh=>undef,db_name=>undef,db_lock=>undef,db_lock_handle=>undef}; - my $dbh = DBI->connect("dbi:SQLite:dbname=$db_name"); - $self->{dbh} = $dbh; - $self->{db_name} = $db_name; - $self->{db_lock} = $lock; - bless($self,$class); - - return($self); -} - -sub lock_exists : locked { - my $self=shift; - my $funcname=shift; - my $lock = $self->{db_lock}; - my $result=(-f $lock); - if($result) { - #print STDERR "(".((defined $funcname)?$funcname:"").") Lock (PID ".$$.") $lock gefunden\n"; - usleep 100; - } - return $result; -} - -sub create_lock : locked { - my $self=shift; - my $funcname=shift; - #print STDERR "(".((defined $funcname)?$funcname:"").") Erzeuge Lock (PID ".$$.") ".($self->{db_lock})."\n"; - - my $lock = $self->{db_lock}; - while( -f $lock ) { - #print STDERR "(".((defined $funcname)?$funcname:"").") Lock (PID ".$$.") $lock gefunden\n"; - sleep 1; - } - - open($self->{db_lock_handle},'>',$self->{db_lock}); -} - -sub remove_lock : locked { - my $self=shift; - my $funcname=shift; - #print STDERR "(".((defined $funcname)?$funcname:"").") Entferne Lock (PID ".$$.") ".$self->{db_lock}."\n"; - close($self->{db_lock_handle}); - unlink($self->{db_lock}); -} - -sub create_table { - my $self = shift; - my $table_name = shift; - my $col_names_ref = shift; - $col_names->{ $table_name } = $col_names_ref; - my $col_names_string = join(', ', @{$col_names_ref}); - my $sql_statement = "CREATE TABLE IF NOT EXISTS $table_name ( $col_names_string )"; - &create_lock($self,'create_table'); - $self->{dbh}->do($sql_statement); - &remove_lock($self,'create_table'); - return 0; -} - - - -sub add_dbentry { - my $self = shift; - my $arg = shift; - - # if dbh not specified, return errorflag 1 - my $table = $arg->{table}; - if( not defined $table ) { - return 1 ; - } - - # specify primary key in table - if (not exists $arg->{primkey}) { - return 2; - } - my $primkey = $arg->{primkey}; - - # if primkey is id, fetch max id from table and give new job id= max(id)+1 - if ($primkey eq 'id') { - my $id; - my $sql_statement = "SELECT MAX(id) FROM $table"; - &create_lock($self,'add_dbentry'); - my $max_id = @{ @{ $self->{dbh}->selectall_arrayref($sql_statement) }[0] }[0]; - &remove_lock($self,'add_dbentry'); - if( defined $max_id) { - $id = $max_id + 1; - } else { - $id = 1; - } - $arg->{id} = $id; - } - - # check wether value to primary key is specified - if ( not exists $arg->{ $primkey } ) { - return 3; - } - - # if timestamp is not provided, add timestamp - if( not exists $arg->{timestamp} ) { - $arg->{timestamp} = &get_time; - } - - # check wether primkey is unique in table, otherwise return errorflag - my $sql_statement = "SELECT * FROM $table WHERE $primkey='$arg->{$primkey}'"; - &create_lock($self,'add_dbentry'); - my $res = @{ $self->{dbh}->selectall_arrayref($sql_statement) }; - &remove_lock($self,'add_dbentry'); - if ($res == 0) { - # fetch column names of table - my $col_names = &get_table_columns("",$table); - - # assign values to column name variables - my @add_list; - foreach my $col_name (@{$col_names}) { - # use function parameter for column values - if (exists $arg->{$col_name}) { - push(@add_list, $arg->{$col_name}); - } - } - - my $sql_statement = "INSERT INTO $table VALUES ('".join("', '", @add_list)."')"; - print STDERR $sql_statement; - &create_lock($self,'add_dbentry'); - my $db_res = $self->{dbh}->do($sql_statement); - &remove_lock($self,'add_dbentry'); - if( $db_res != 1 ) { - return 4; - } else { - return 0; - } - - } else { - my $update_hash = { table=>$table }; - $update_hash->{where} = [ { $primkey=>[ $arg->{$primkey} ] } ]; - $update_hash->{update} = [ {} ]; - while( my ($pram, $val) = each %{$arg} ) { - if( $pram eq 'table' ) { next; } - if( $pram eq 'primkey' ) { next; } - $update_hash->{update}[0]->{$pram} = [$val]; - } - my $db_res = &update_dbentry( $self, $update_hash ); - if( $db_res != 1 ) { - return 5; - } else { - return 0; - } - - } -} - - -# error-flags -# 1 no table ($table) defined -# 2 no restriction parameter ($restric_pram) defined -# 3 no restriction value ($restric_val) defined -# 4 column name not known in table -# 5 no column names to change specified -sub update_dbentry { - my $self = shift; - my $arg = shift; - - - # check completeness of function parameter - # extract table statement from arg hash - my $table = $arg->{table}; - if (not defined $table) { - return 1; - } else { - delete $arg->{table}; - } - - # extract where parameter from arg hash - my $where_statement = ""; - if( exists $arg->{where} ) { - my $where_hash = @{ $arg->{where} }[0]; - if( 0 < keys %{ $where_hash } ) { - my @where_list; - while( my ($rest_pram, $rest_val) = each %{ $where_hash } ) { - my $statement; - if( $rest_pram eq 'timestamp' ) { - $statement = "$rest_pram<'@{ $rest_val }[0]'"; - } else { - $statement = "$rest_pram='@{ $rest_val }[0]'"; - } - push( @where_list, $statement ); - } - $where_statement .= "WHERE ".join('AND ', @where_list); - } - } - - # extract update parameter from arg hash - my $update_hash = @{ $arg->{update} }[0]; - my $update_statement = ""; - if( 0 < keys %{ $update_hash } ) { - my @update_list; - while( my ($rest_pram, $rest_val) = each %{ $update_hash } ) { - my $statement = "$rest_pram='@{ $rest_val }[0]'"; - push( @update_list, $statement ); - } - $update_statement .= join(', ', @update_list); - } - - my $sql_statement = "UPDATE $table SET $update_statement $where_statement"; - &create_lock($self,'update_dbentry'); - my $db_answer = $self->{dbh}->do($sql_statement); - &remove_lock($self,'update_dbentry'); - return $db_answer; -} - - -sub del_dbentry { - my $self = shift; - my $arg = shift; - - - # check completeness of function parameter - # extract table statement from arg hash - my $table = $arg->{table}; - if (not defined $table) { - return 1; - } else { - delete $arg->{table}; - } - - # collect select statements - my @del_list; - while (my ($pram, $val) = each %{$arg}) { - if ( $pram eq 'timestamp' ) { - push(@del_list, "$pram < '$val'"); - } else { - push(@del_list, "$pram = '$val'"); - } - } - - my $where_statement; - if( not @del_list ) { - $where_statement = ""; - } else { - $where_statement = "WHERE ".join(' AND ', @del_list); - } - - my $sql_statement = "DELETE FROM $table $where_statement"; - &create_lock($self,'del_dbentry'); - my $db_res = $self->{dbh}->do($sql_statement); - &remove_lock($self,'del_dbentry'); - return $db_res; -} - - -sub get_table_columns { - my $self = shift; - my $table = shift; - my @column_names; - - if(exists $col_names->{$table}) { - @column_names = @{$col_names->{$table}}; - } else { - &create_lock($self,'get_table_columns'); - my @res = @{$self->{dbh}->selectall_arrayref("pragma table_info('$table')")}; - &remove_lock($self,'get_table_columns'); - foreach my $column (@res) { - push(@column_names, @$column[1]); - } - } - return \@column_names; - -} - -sub select_dbentry { - my $self = shift; - my $arg = shift; - - - # check completeness of function parameter - # extract table statement from arg hash - my $table = $arg->{table}; - if (not defined $table) { - return 1; - } else { - delete $arg->{table}; - } - - # collect select statements - my @select_list; - my $sql_statement; - while (my ($pram, $val) = each %{$arg}) { - if ( $pram eq 'timestamp' ) { - push(@select_list, "$pram < '$val'"); - } else { - push(@select_list, "$pram = '$val'"); - } - } - - if (@select_list == 0) { - $sql_statement = "SELECT * FROM '$table'"; - } else { - $sql_statement = "SELECT * FROM '$table' WHERE ".join(' AND ', @select_list); - } - - # query db - &create_lock($self,'select_dbentry'); - my $query_answer = $self->{dbh}->selectall_arrayref($sql_statement); - &remove_lock($self,'select_dbentry'); - - # fetch column list of db and create a hash with column_name->column_value of the select query - my $column_list = &get_table_columns($self, $table); - my $list_len = @{ $column_list } ; - my $answer = {}; - my $hit_counter = 0; - - foreach my $hit ( @{ $query_answer }) { - $hit_counter++; - for ( my $i = 0; $i < $list_len; $i++) { - $answer->{ $hit_counter }->{ @{ $column_list }[$i] } = @{ $hit }[$i]; - } - } - - return $answer; -} - - -sub show_table { - my $self = shift; - my $table_name = shift; - &create_lock($self,'show_table'); - my @res = @{$self->{dbh}->selectall_arrayref( "SELECT * FROM $table_name")}; - &remove_lock($self,'show_table'); - my @answer; - foreach my $hit (@res) { - push(@answer, "hit: ".join(', ', @{$hit})); - } - return join("\n", @answer); -} - - -sub exec_statement { - my $self = shift; - my $sql_statement = shift; - &create_lock($self,'exec_statement'); - my @res = @{$self->{dbh}->selectall_arrayref($sql_statement)}; - &remove_lock($self, 'exec_statement'); - return \@res; -} - -sub get_time { - 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; - $month+=1; - $month = $month < 10 ? $month = "0".$month : $month; - $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; - $year+=1900; - return "$year$month$monthday$hours$minutes$seconds"; -} - - -1; diff --git a/gosa-si-poe/modules/GosaPackages.pm b/gosa-si-poe/modules/GosaPackages.pm deleted file mode 100644 index 86895caeb..000000000 --- a/gosa-si-poe/modules/GosaPackages.pm +++ /dev/null @@ -1,610 +0,0 @@ -package GosaPackages; - -use Exporter; -@ISA = ("Exporter"); - -use strict; -use warnings; -use GOSA::GosaSupportDaemon; -use IO::Socket::INET; -use XML::Simple; -use File::Spec; -use Data::Dumper; -use GOSA::DBsqlite; -use MIME::Base64; - -BEGIN{} -END{} - -my ($server_activ, $server_ip, $server_mac_address, $server_port, $server_passwd, $max_clients, $server_event_dir); -my ($bus_activ, $bus_passwd, $bus_ip, $bus_port); -my ($gosa_activ, $gosa_ip, $gosa_mac_address, $gosa_port, $gosa_passwd, $network_interface); -my ($job_queue_timeout, $job_queue_file_name); - -my $gosa_server; - -my %cfg_defaults = -("general" => - {"job_queue_file_name" => [\$job_queue_file_name, '/var/lib/gosa-si/jobs.db'], - }, -"server" => - {"server_activ" => [\$server_activ, "on"], - "server_ip" => [\$server_ip, "0.0.0.0"], - "server_port" => [\$server_port, "20081"], - "server_passwd" => [\$server_passwd, ""], - "max_clients" => [\$max_clients, 100], - "server_event_dir" => [\$server_event_dir, '/usr/lib/gosa-si/server/events'], - }, -"bus" => - {"bus_activ" => [\$bus_activ, "on"], - "bus_passwd" => [\$bus_passwd, ""], - "bus_ip" => [\$bus_ip, "0.0.0.0"], - "bus_port" => [\$bus_port, "20080"], - }, -"gosa" => - {"gosa_activ" => [\$gosa_activ, "on"], - "gosa_ip" => [\$gosa_ip, "0.0.0.0"], - "gosa_port" => [\$gosa_port, "20082"], - "gosa_passwd" => [\$gosa_passwd, "none"], - }, -); - - -## START ########################## - -# read configfile and import variables -&read_configfile(); -$network_interface= &get_interface_for_ip($server_ip); -$gosa_mac_address= &get_mac($network_interface); - -# complete addresses -my $server_address = "$server_ip:$server_port"; -my $bus_address = "$bus_ip:$bus_port"; -my $gosa_address = "$gosa_ip:$gosa_port"; - -# create general settings for this module -my $gosa_cipher = &create_ciphering($gosa_passwd); -my $xml = new XML::Simple(); - -# open gosa socket -if ($gosa_activ eq "on") { - &main::daemon_log(" ",1); - $gosa_server = IO::Socket::INET->new(LocalPort => $gosa_port, - Type => SOCK_STREAM, - Reuse => 1, - Listen => 1, - ); - if (not defined $gosa_server) { - &main::daemon_log("cannot start tcp server at $gosa_port for communication to gosa: $@", 1); - die; - } else { - &main::daemon_log("start server for communication to gosa: $gosa_address", 1); - - } -} - -# create gosa job queue as a SQLite DB -my $table_name = "jobs"; -my $sqlite = GOSA::DBsqlite->new($job_queue_file_name); - - - - -## FUNCTIONS ################################################################# - -sub get_module_info { - my @info = ($gosa_address, - $gosa_passwd, - $gosa_server, - $gosa_activ, - "socket", - ); - return \@info; -} - - -#=== FUNCTION ================================================================ -# NAME: read_configfile -# PARAMETERS: cfg_file - string - -# RETURNS: nothing -# DESCRIPTION: read cfg_file and set variables -#=============================================================================== -sub read_configfile { - my $cfg; - if( defined( $main::cfg_file) && ( length($main::cfg_file) > 0 )) { - if( -r $main::cfg_file ) { - $cfg = Config::IniFiles->new( -file => $main::cfg_file ); - } else { - print STDERR "Couldn't read config file!"; - } - } else { - $cfg = Config::IniFiles->new() ; - } - foreach my $section (keys %cfg_defaults) { - foreach my $param (keys %{$cfg_defaults{ $section }}) { - my $pinfo = $cfg_defaults{ $section }{ $param }; - ${@$pinfo[0]} = $cfg->val( $section, $param, @$pinfo[1] ); - } - } -} - -#=== FUNCTION ================================================================ -# NAME: get_interface_for_ip -# PARAMETERS: ip address (i.e. 192.168.0.1) -# RETURNS: array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else -# 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; - } - } - } - } - return $result; -} - -#=== FUNCTION ================================================================ -# NAME: get_interfaces -# PARAMETERS: none -# RETURNS: (list of interfaces) -# DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. -#=============================================================================== -sub get_interfaces { - my @result; - my $PROC_NET_DEV= ('/proc/net/dev'); - - open(PROC_NET_DEV, "<$PROC_NET_DEV") - or die "Could not open $PROC_NET_DEV"; - - my @ifs = ; - - close(PROC_NET_DEV); - - # 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; - } - - return @result; -} - -#=== FUNCTION ================================================================ -# NAME: get_mac -# PARAMETERS: interface name (i.e. eth0) -# RETURNS: (mac address) -# DESCRIPTION: Uses ioctl to get mac address directly from system. -#=============================================================================== -sub get_mac { - my $ifreq= shift; - my $result; - if ($ifreq && length($ifreq) > 0) { - if($ifreq eq "all") { - $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 ($gosa_mac_address and length($gosa_mac_address) > 0) { - $result= $gosa_mac_address; - } - - socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip') - or die "socket: $!"; - - 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; - } - } - } - } - 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: 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; - } - &main::daemon_log("open_socket to: $PeerAddr", 7); - return $socket; -} - - -#=== FUNCTION ================================================================ -# NAME: process_incoming_msg -# PARAMETERS: crypted_msg - string - incoming crypted message -# RETURNS: nothing -# DESCRIPTION: handels the proceeded distribution to the appropriated functions -#=============================================================================== -sub process_incoming_msg { - my ($crypted_msg) = @_ ; - &main::daemon_log("Got message $crypted_msg", 5); - if( (not(defined($crypted_msg))) || (length($crypted_msg) <= 0)) { - &main::daemon_log("function 'process_incoming_msg': got no msg", 7); - 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); - - # collect addresses from possible incoming clients - # only gosa is allowd as incoming client - &main::daemon_log("GosaPackages: host_key: $host", 7); - &main::daemon_log("GosaPackages: key_passwd: $gosa_passwd", 7); - - $gosa_cipher = &create_ciphering($gosa_passwd); - - # determine the correct passwd for deciphering of the incoming msgs - my $msg = ""; - my $msg_hash; - eval{ - $msg = &decrypt_msg($crypted_msg, $gosa_cipher); - &main::daemon_log("GosaPackages: decrypted_msg: \n$msg", 7); - - $msg_hash = $xml->XMLin($msg, ForceArray=>1); - }; - if($@) { - &main::daemon_log("WARNING: GosaPackages do not understand the message:", 5); - &main::daemon_log("$@", 7); - return; - } - - my $header = @{$msg_hash->{header}}[0]; - - &main::daemon_log("GosaPackages: receive '$header' from $host", 1); - - my $out_msg; - if ($header =~ /^job_/) { - $out_msg = &process_job_msg($msg, $msg_hash); - } elsif ($header =~ /^gosa_/) { - $out_msg = &process_gosa_msg($msg, $header); - } else { - &main::daemon_log("ERROR: $header is not a valid GosaPackage-header, need a 'job_' or a 'gosa_' prefix"); - } - - if (not defined $out_msg) { - return; - } - - if ($out_msg =~ /(\d*?)<\/jobdb_id>/) { - my $job_id = $1; - my $sql = "BEGIN TRANSATION; UPDATE '".$main::job_queue_table_name. - "' SET status='done', result='".$out_msg. - "' WHERE id='$job_id'; COMMIT;"; - my $res = $main::job_db->exec_statement($sql); - return; - - } else { - - my $out_cipher = &create_ciphering($gosa_passwd); - $out_msg = &encrypt_msg($out_msg, $out_cipher); - return $out_msg; - } - -} - -sub process_gosa_msg { - my ($msg, $header) = @_ ; - my $out_msg; - $header =~ s/gosa_//; - - # decide wether msg is a core function or a event handler - if ( $header eq 'query_jobdb') { $out_msg = &query_jobdb } - elsif ($header eq 'delete_jobdb_entry') { $out_msg = &delete_jobdb_entry } - elsif ($header eq 'clear_jobdb') { $out_msg = &clear_jobdb } - elsif ($header eq 'update_status_jobdb_entry' ) { $out_msg = &update_status_jobdb_entry } - elsif ($header eq 'update_timestamp_jobdb_entry' ) { $out_msg = &update_timestamp_jobdb_entry } - else { - # msg could not be assigned to core function - # fetch all available eventhandler under $server_event_dir - opendir (DIR, $server_event_dir) or &main::daemon_log("ERROR cannot open $server_event_dir: $!\n", 1) and return; - while (defined (my $file = readdir (DIR))) { - if (not $file eq $header) { - next; - } - # try to deliver incoming msg to eventhandler - my $cmd = File::Spec->join($server_event_dir, $header)." '$msg'"; - &main::daemon_log("GosaPackages: execute event_handler $header", 3); - &main::daemon_log("GosaPackages: cmd: $cmd", 7); - - $out_msg = ""; - open(PIPE, "$cmd 2>&1 |"); - while() { - $out_msg.=$_; - } - close(PIPE); - &main::daemon_log("GosaPackages: answer of cmd: $out_msg", 5); - last; - } - } - - # if delivery not possible raise error and return - if (not defined $out_msg) { - &main::daemon_log("ERROR: GosaPackages: no event handler or core function defined for $header", 1); - } elsif ($out_msg eq "") { - &main::daemon_log("ERROR: GosaPackages got not answer from event_handler $header", 1); - } - return $out_msg; - -} - - -sub process_job_msg { - my ($msg, $msg_hash)= @_ ; - - my $header = @{$msg_hash->{header}}[0]; - $header =~ s/job_//; - - # check wether mac address is already known in known_daemons or known_clients - my $target = 'none'; - - # add job to job queue - my $func_dic = {table=>$main::job_queue_table_name, - primkey=>'id', - timestamp=>@{$msg_hash->{timestamp}}[0], - status=>'waiting', - result=>'none', - headertag=>$header, - targettag=>$target, - xmlmessage=>$msg, - macaddress=>@{$msg_hash->{mac}}[0], - }; - my $res = $main::job_db->add_dbentry($func_dic); - if (not $res == 0) { - &main::daemon_log("ERROR: GosaPackages: process_job_msg: $res", 1); - } - - &main::daemon_log("GosaPackages: $header job successfully added to job queue", 3); - return "<1>$res"; - -} - - -sub db_res_2_xml { - my ($db_res) = @_ ; - - my $xml = ""; - - while ( my ($hit, $hash) = each %{ $db_res } ) { - $xml .= "\n"; - - while ( my ($column_name, $column_value) = each %{$hash} ) { - $xml .= "<$column_name>"; - my $xml_content; - if( $column_name eq "xmlmessage" ) { - $xml_content = &encode_base64($column_value); - } else { - $xml_content = $column_value; - } - $xml .= $xml_content; - $xml .= ""; - } - - $xml .= ""; - } - - $xml .= ""; - return $xml; -} - - -## CORE FUNCTIONS ############################################################ - -sub query_jobdb { - my ($msg) = @_; - my $msg_hash = &transform_msg2hash($msg); - - # prepare query sql statement - my @where = @{$msg_hash->{where}}; - my $where_hash = {table=>$main::job_queue_table_name }; - foreach my $where_pram (@where) { - my $where_val = @{$msg_hash->{$where_pram}}[0]; - if (defined $where_val) { - $where_hash->{$where_pram} = $where_val; - } - } - - # execute db query - my $res_hash = $main::job_db->select_dbentry($where_hash); - - my $out_xml = &db_res_2_xml($res_hash); - return $out_xml; -} - -sub delete_jobdb_entry { - my ($msg) = @_ ; - my $msg_hash = &transform_msg2hash($msg); - - # prepare query sql statement - my @where = @{$msg_hash->{where}}; - my $where_hash = {table=>$main::job_queue_table_name }; - foreach my $where_pram (@where) { - my $where_val = @{$msg_hash->{$where_pram}}[0]; - if (defined $where_val) { - $where_hash->{$where_pram} = $where_val; - } - } - - # execute db query - my $db_res = $main::job_db->del_dbentry($where_hash); - - my $res; - if( $db_res > 0 ) { - $res = 0 ; - } else { - $res = 1; - } - - # prepare xml answer - my $out_xml = "$res"; - return $out_xml; - -} - -sub clear_jobdb { - my ($msg) = @_ ; - my $msg_hash = &transform_msg2hash($msg); - - my $where_hash = {table=>$main::job_queue_table_name }; - - # execute db query - my $db_res = $main::job_db->del_dbentry($where_hash); - print STDERR "db_res=$db_res\n"; - my $res; - if( $db_res eq '0E0' ) { - $res = 0 ; - } else { - $res = 1; - } - - # prepare xml answer - my $out_xml = "$res"; - return $out_xml; -} - -sub update_status_jobdb_entry { - my ($msg) = @_ ; - my $msg_hash = &transform_msg2hash($msg); - - # prepare query sql statement - my $update_hash = {table=>$main::job_queue_table_name }; - if( exists $msg_hash->{where} ) { - $update_hash->{where} = $msg_hash->{where}; - } else { - $update_hash->{where} = []; - } - - if( not exists $msg_hash->{update}[0]->{status} ) { - return "1"; - } - $update_hash->{update} = [ { status=>$msg_hash->{update}[0]->{status} } ]; - - # execute db query - my $db_res = $main::job_db->update_dbentry($update_hash); - - # transform db answer to error returnment - my $res; - if( $db_res > 0 ) { - $res = 0 ; - } else { - $res = 1; - } - - # prepare xml answer - my $out_xml = "$res"; - return $out_xml; -} - -sub update_timestamp_jobdb_entry { - my ($msg) = @_ ; - my $msg_hash = &transform_msg2hash($msg); - - # prepare query sql statement - my $update_hash = {table=>$main::job_queue_table_name }; - if( exists $msg_hash->{where} ) { - $update_hash->{where} = $msg_hash->{where}; - } else { - $update_hash->{where} = []; - } - - if( not exists $msg_hash->{update}[0]->{timestamp} ) { - return "1"; - } - - $update_hash->{update} = [ { timestamp=>$msg_hash->{update}[0]->{timestamp} } ]; - - # execute db query - my $db_res = $main::job_db->update_dbentry($update_hash); - - # transform db answer to error returnment - my $res; - if( $db_res > 0 ) { - $res = 0 ; - } else { - $res = 1; - } - - # prepare xml answer - my $out_xml = "$res"; - return $out_xml; - -} - - -1; - - - - - - - - - - diff --git a/gosa-si-poe/modules/GosaSupportDaemon.pm b/gosa-si-poe/modules/GosaSupportDaemon.pm deleted file mode 100644 index cf26ca49f..000000000 --- a/gosa-si-poe/modules/GosaSupportDaemon.pm +++ /dev/null @@ -1,300 +0,0 @@ -package GOSA::GosaSupportDaemon; - -use Exporter; -@ISA = qw(Exporter); -@EXPORT = qw(create_xml_hash send_msg_hash2address get_content_from_xml_hash add_content2xml_hash create_xml_string encrypt_msg decrypt_msg create_ciphering transform_msg2hash get_time send_msg); - -use strict; -use warnings; -use IO::Socket::INET; -use Crypt::Rijndael; -use Digest::MD5 qw(md5 md5_hex md5_base64); -use MIME::Base64; -use XML::Simple; - - - -BEGIN {} - -END {} - -### Start ###################################################################### - -my $xml = new XML::Simple(); - -sub process_incoming_msg { - return; -} - -sub daemon_log { - my ($msg, $level) = @_ ; - &main::daemon_log($msg, $level); - return; -} - - -#=== FUNCTION ================================================================ -# NAME: create_xml_hash -# PARAMETERS: header - string - message header (required) -# source - string - where the message come from (required) -# target - string - where the message should go to (required) -# [header_value] - string - something usefull (optional) -# RETURNS: hash - hash - nomen est omen -# DESCRIPTION: creates a key-value hash, all values are stored in a array -#=============================================================================== -sub create_xml_hash { - my ($header, $source, $target, $header_value) = @_; - my $hash = { - header => [$header], - source => [$source], - target => [$target], - $header => [$header_value], - }; - return $hash -} - - -sub transform_msg2hash { - my ($msg) = @_ ; - my $hash = $xml->XMLin($msg, ForceArray=>1); - - # xml tags without a content are created as an empty hash - # substitute it with an empty list - while( my ($xml_tag, $xml_content) = each %{ $hash } ) { - if( 1 == @{ $xml_content } ) { - # there is only one element in xml_content list ... - my $element = @{ $xml_content }[0]; - if( ref($element) eq "HASH" ) { - # and this element is an hash ... - my $len_element = keys %{ $element }; - if( $len_element == 0 ) { - # and this hash is empty, then substitute the xml_content - # with an empty string in list - $hash->{$xml_tag} = [ "none" ]; - } - } - } - } - - return $hash; -} - - -#=== FUNCTION ================================================================ -# NAME: send_msg_hash2address -# PARAMETERS: msg_hash - hash - xml_hash created with function create_xml_hash -# PeerAddr string - socket address to send msg -# PeerPort string - socket port, if not included in socket address -# RETURNS: nothing -# DESCRIPTION: ???? -#=============================================================================== -sub send_msg_hash2address ($$$){ - my ($msg_hash, $address, $passwd) = @_ ; - - # fetch header for logging - my $header = @{$msg_hash->{header}}[0]; - - # generate xml string - my $msg_xml = &create_xml_string($msg_hash); - - # create ciphering object - my $act_cipher = &create_ciphering($passwd); - - # encrypt xml msg - my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher); - - # opensocket - my $socket = &open_socket($address); - if(not defined $socket){ - daemon_log("cannot send '$header'-msg to $address , server not reachable", 5); - return 1; - } - - # send xml msg - print $socket $crypted_msg."\n"; - - close $socket; - - daemon_log("send '$header'-msg to $address", 1); - daemon_log("message:\n$msg_xml", 8); - return 0; -} - - -#=== FUNCTION ================================================================ -# NAME: get_content_from_xml_hash -# PARAMETERS: xml_ref - ref - reference of the xml hash -# element - string - key of the value you want -# RETURNS: value - string - if key is either header, target or source -# value - list - for all other keys in xml hash -# DESCRIPTION: -#=============================================================================== -sub get_content_from_xml_hash { - my ($xml_ref, $element) = @_ ; - #my $result = $main::xml_ref->{$element}; - #if( $element eq "header" || $element eq "target" || $element eq "source") { - # return @$result[0]; - #} - my @result = $xml_ref->{$element}; - return \@result; -} - - -#=== FUNCTION ================================================================ -# NAME: add_content2xml_hash -# PARAMETERS: xml_ref - ref - reference to a hash from function create_xml_hash -# element - string - key for the hash -# content - string - value for the hash -# RETURNS: nothing -# DESCRIPTION: add key-value pair to xml_ref, if key alread exists, -# then append value to list -#=============================================================================== -sub add_content2xml_hash { - my ($xml_ref, $element, $content) = @_; - if(not exists $$xml_ref{$element} ) { - $$xml_ref{$element} = []; - } - my $tmp = $$xml_ref{$element}; - push(@$tmp, $content); - return; -} - - -#=== FUNCTION ================================================================ -# NAME: create_xml_string -# PARAMETERS: xml_hash - hash - hash from function create_xml_hash -# RETURNS: xml_string - string - xml string representation of the hash -# DESCRIPTION: transform the hash to a string using XML::Simple module -#=============================================================================== -sub create_xml_string { - my ($xml_hash) = @_ ; - my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml'); - #$xml_string =~ s/[\n]+//g; - #daemon_log("create_xml_string:",7); - #daemon_log("$xml_string\n", 7); - return $xml_string; -} - - -#=== FUNCTION ================================================================ -# NAME: encrypt_msg -# PARAMETERS: msg - string - message to encrypt -# my_cipher - ref - reference to a Crypt::Rijndael object -# RETURNS: crypted_msg - string - crypted message -# DESCRIPTION: crypts the incoming message with the Crypt::Rijndael module -#=============================================================================== -sub encrypt_msg { - my ($msg, $my_cipher) = @_; - if(not defined $my_cipher) { print "no cipher object\n"; } - $msg = "\0"x(16-length($msg)%16).$msg; - $msg = $my_cipher->encrypt($msg); - chomp($msg = &encode_base64($msg)); - return $msg; -} - - -#=== FUNCTION ================================================================ -# NAME: decrypt_msg -# PARAMETERS: crypted_msg - string - message to decrypt -# my_cipher - ref - reference to a Crypt::Rijndael object -# RETURNS: msg - string - decrypted message -# DESCRIPTION: decrypts the incoming message with the Crypt::Rijndael module -#=============================================================================== -sub decrypt_msg { - my ($msg, $my_cipher) = @_ ; - if(defined $msg && defined $my_cipher) { - $msg = &decode_base64($msg); - } - $msg = $my_cipher->decrypt($msg); - $msg =~ s/\0*//g; - return $msg; -} - - -#=== FUNCTION ================================================================ -# NAME: create_ciphering -# PARAMETERS: passwd - string - used to create ciphering -# RETURNS: cipher - object -# DESCRIPTION: creates a Crypt::Rijndael::MODE_CBC object with passwd as key -#=============================================================================== -sub create_ciphering { - my ($passwd) = @_; - $passwd = substr(md5_hex("$passwd") x 32, 0, 32); - my $iv = substr(md5_hex('GONICUS GmbH'),0, 16); - - #daemon_log("iv: $iv", 7); - #daemon_log("key: $passwd", 7); - my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC()); - $my_cipher->set_iv($iv); - return $my_cipher; -} - - -#=== 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 get_time { - 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; - $month+=1; - $month = $month < 10 ? $month = "0".$month : $month; - $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; - $year+=1900; - return "$year$month$monthday$hours$minutes$seconds"; - -} - - -#=== FUNCTION ================================================================ -# NAME: send_msg -# DESCRIPTION: Send a message to a destination -# PARAMETERS: [header] Name of the header -# [from] sender ip -# [to] recipient ip -# [data] Hash containing additional attributes for the xml -# package -# RETURNS: nothing -#=============================================================================== -sub send_msg ($$$$$) { - my ($header, $from, $to, $data, $hostkey) = @_; - - my $out_hash = &create_xml_hash($header, $from, $to); - - while ( my ($key, $value) = each(%$data) ) { - if(ref($value) eq 'ARRAY'){ - map(&add_content2xml_hash($out_hash, $key, $_), @$value); - } else { - &add_content2xml_hash($out_hash, $key, $value); - } - } - - &send_msg_hash2address($out_hash, $to, $hostkey); -} - -1; diff --git a/gosa-si-poe/modules/ServerPackages.pm b/gosa-si-poe/modules/ServerPackages.pm deleted file mode 100644 index 95baac87a..000000000 --- a/gosa-si-poe/modules/ServerPackages.pm +++ /dev/null @@ -1,890 +0,0 @@ -package ServerPackages; - -use Exporter; -@ISA = ("Exporter"); - -# Each module has to have a function 'process_incoming_msg'. This function works as a interface to gosa-sd and receives the msg hash from gosa-sd. 'process_incoming_function checks, wether it has a function to process the incoming msg and forward the msg to it. - - -use strict; -use warnings; -use GOSA::GosaSupportDaemon; -use IO::Socket::INET; -use XML::Simple; -use Data::Dumper; -use Net::LDAP; -use Socket qw/PF_INET SOCK_DGRAM inet_ntoa sockaddr_in/; - -BEGIN{} -END {} - -my ($known_clients_file_name); -my ($server_activ, $server_ip, $server_mac_address, $server_port, $server_passwd, $max_clients, $ldap_uri, $ldap_base, $ldap_admin_dn, $ldap_admin_password); -my ($bus_activ, $bus_passwd, $bus_ip, $bus_port); -my $server; -my $network_interface; -my $no_bus; -my (@ldap_cfg, @pam_cfg, @nss_cfg, $goto_admin, $goto_secret); - - -my %cfg_defaults = -( -"server" => - {"server_activ" => [\$server_activ, "on"], - "server_ip" => [\$server_ip, "0.0.0.0"], - "server_mac_address" => [\$server_mac_address, ""], - "server_port" => [\$server_port, "20081"], - "server_passwd" => [\$server_passwd, ""], - "max_clients" => [\$max_clients, 100], - "ldap_uri" => [\$ldap_uri, ""], - "ldap_base" => [\$ldap_base, ""], - "ldap_admin_dn" => [\$ldap_admin_dn, ""], - "ldap_admin_password" => [\$ldap_admin_password, ""], - }, -"bus" => - {"bus_activ" => [\$bus_activ, "on"], - "bus_passwd" => [\$bus_passwd, ""], - "bus_ip" => [\$bus_ip, ""], - "bus_port" => [\$bus_port, "20080"], - }, -); - -### START ##################################################################### - -# read configfile and import variables -&read_configfile(); - -# detect interfaces and mac address -$network_interface= &get_interface_for_ip($server_ip); -$server_mac_address= &get_mac($network_interface); - -&main::daemon_log("server ip address detected: $server_ip", 1); -&main::daemon_log("server mac address detected: $server_mac_address", 1); - -# complete addresses -my $server_address = "$server_ip:$server_port"; -my $bus_address = "$bus_ip:$bus_port"; - -# create general settings for this module -my $xml = new XML::Simple(); - -## open server socket -#if($server_activ eq "on"){ -# &main::daemon_log(" ", 1); -# $server = IO::Socket::INET->new(LocalPort => $server_port, -# Type => SOCK_STREAM, -# Reuse => 1, -# Listen => 20, -# ); -# if(not defined $server){ -# &main::daemon_log("cannot be a tcp server at $server_port : $@"); -# die; -# } else { -# &main::daemon_log("start server: $server_address", 1); -# } -#} -# -# -## register at bus -#if ($main::no_bus > 0) { -# $bus_activ = "off" -#} -#if($bus_activ eq "on") { -# &main::daemon_log(" ", 1); -# ®ister_at_bus(); -#} - -### functions ################################################################# - - -sub get_module_info { - my @info = ($server_address, - $server_passwd, - $server, - $server_activ, - "socket", - ); - return \@info; -} - - -#=== FUNCTION ================================================================ -# NAME: read_configfile -# PARAMETERS: cfg_file - string - -# RETURNS: nothing -# DESCRIPTION: read cfg_file and set variables -#=============================================================================== -sub read_configfile { - my $cfg; - if( defined( $main::cfg_file) && ( length($main::cfg_file) > 0 )) { - if( -r $main::cfg_file ) { - $cfg = Config::IniFiles->new( -file => $main::cfg_file ); - } else { - print STDERR "Couldn't read config file!"; - } - } else { - $cfg = Config::IniFiles->new() ; - } - foreach my $section (keys %cfg_defaults) { - foreach my $param (keys %{$cfg_defaults{ $section }}) { - my $pinfo = $cfg_defaults{ $section }{ $param }; - ${@$pinfo[0]} = $cfg->val( $section, $param, @$pinfo[1] ); - } - } - - # Read non predefined sections - my $param; - if ($cfg->SectionExists('ldap')){ - foreach $param ($cfg->Parameters('ldap')){ - push (@ldap_cfg, "$param ".$cfg->val('ldap', $param)); - } - } - if ($cfg->SectionExists('pam_ldap')){ - foreach $param ($cfg->Parameters('pam_ldap')){ - push (@pam_cfg, "$param ".$cfg->val('pam_ldap', $param)); - } - } - if ($cfg->SectionExists('nss_ldap')){ - foreach $param ($cfg->Parameters('nss_ldap')){ - push (@nss_cfg, "$param ".$cfg->val('nss_ldap', $param)); - } - } - if ($cfg->SectionExists('goto')){ - $goto_admin= $cfg->val('goto', 'terminal_admin'); - $goto_secret= $cfg->val('goto', 'terminal_secret'); - } else { - $goto_admin= undef; - $goto_secret= undef; - } - -} - -#=== FUNCTION ================================================================ -# NAME: get_interface_for_ip -# PARAMETERS: ip address (i.e. 192.168.0.1) -# RETURNS: array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else -# 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; - } - } - } - } - return $result; -} - -#=== FUNCTION ================================================================ -# NAME: get_interfaces -# PARAMETERS: none -# RETURNS: (list of interfaces) -# DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. -#=============================================================================== -sub get_interfaces { - my @result; - my $PROC_NET_DEV= ('/proc/net/dev'); - - open(PROC_NET_DEV, "<$PROC_NET_DEV") - or die "Could not open $PROC_NET_DEV"; - - my @ifs = ; - - close(PROC_NET_DEV); - - # 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; - } - - return @result; -} - -#=== FUNCTION ================================================================ -# NAME: get_mac -# PARAMETERS: interface name (i.e. eth0) -# RETURNS: (mac address) -# DESCRIPTION: Uses ioctl to get mac address directly from system. -#=============================================================================== -sub get_mac { - my $ifreq= shift; - my $result; - if ($ifreq && length($ifreq) > 0) { - if($ifreq eq "all") { - $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 ($server_mac_address and length($server_mac_address) > 0) { - $result= $server_mac_address; - } - - socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip') - or die "socket: $!"; - - 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; - } - } - } - } - 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: 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; -# } -# &main::daemon_log("open_socket to: $PeerAddr", 7); -# return $socket; -#} - -#=== FUNCTION ================================================================ -# NAME: register_at_bus -# PARAMETERS: nothing -# RETURNS: nothing -# DESCRIPTION: creates an entry in known_daemons and send a 'here_i_am' msg to bus -#=============================================================================== -sub register_at_bus { - - # add bus to known_server_db - my $res = $main::known_server_db->add_dbentry( {table=>'known_server', - primkey=>'hostname', - hostname=>$bus_address, - status=>'bus', - hostkey=>$bus_passwd, - timestamp=>&get_time, - } ); - my $msg_hash = &create_xml_hash("here_i_am", $server_address, $bus_address); - my $answer = ""; - $answer = &send_msg_hash2address($msg_hash, $bus_address, $bus_passwd); - if ($answer == 0) { - &main::daemon_log("register at bus: $bus_address", 1); - } else { - &main::daemon_log("unable to send 'register'-msg to bus '$bus_address': $answer", 1); - } - return; -} - -#=== FUNCTION ================================================================ -# NAME: process_incoming_msg -# PARAMETERS: crypted_msg - string - incoming crypted message -# RETURNS: nothing -# DESCRIPTION: handels the proceeded distribution to the appropriated functions -#=============================================================================== -sub process_incoming_msg { - my ($crypted_msg) = @_ ; - if(not defined $crypted_msg) { - &main::daemon_log("function 'process_incoming_msg': got no msg", 7); - } - - &main::daemon_log("ServerPackages: incoming msg: \n$crypted_msg", 8); - - $crypted_msg =~ /^([\s\S]*?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)$/; - $crypted_msg = $1; - my $host="0.0.0.0"; - if($1 && $2 && $3 && $4) { - $host = sprintf("%s.%s.%s.%s", $2, $3, $4, $5); - } - - my $msg; - my $msg_hash; - my $host_name; - my $host_key; - - # check wether incoming msg is a new msg - $host_name = $server_address; - $host_key = $server_passwd; - &main::daemon_log("ServerPackage: host_name: $host_name", 7); - &main::daemon_log("ServerPackage: host_key: $host_key", 7); - eval{ - my $key_cipher = &create_ciphering($host_key); - $msg = &decrypt_msg($crypted_msg, $key_cipher); - $msg_hash = &transform_msg2hash($msg); - }; - if($@) { - &main::daemon_log("ServerPackage: deciphering raise error", 7); - &main::daemon_log("$@", 8); - $msg = undef; - $msg_hash = undef; - $host_name = undef; - $host_key = undef; - } - - # check wether incoming msg is from a known_server - if( not defined $msg ) { - my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server'} ); - while( my ($hit_num, $hit) = each %{ $query_res } ) { - $host_name = $hit->{hostname}; - if( not $host_name =~ "^$host") { - next; - } - $host_key = $hit->{hostkey}; - &main::daemon_log("ServerPackage: host_name: $host_name", 7); - &main::daemon_log("ServerPackage: host_key: $host_key", 7); - eval{ - my $key_cipher = &create_ciphering($host_key); - $msg = &decrypt_msg($crypted_msg, $key_cipher); - $msg_hash = &transform_msg2hash($msg); - }; - if($@) { - &main::daemon_log("ServerPackage: deciphering raise error", 7); - &main::daemon_log("$@", 8); - $msg = undef; - $msg_hash = undef; - $host_name = undef; - $host_key = undef; - } else { - last; - } - } - } - - # check wether incoming msg is from a known_client - if( not defined $msg ) { - my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients'} ); - while( my ($hit_num, $hit) = each %{ $query_res } ) { - $host_name = $hit->{hostname}; - if( not $host_name =~ "^$host") { - next; - } - $host_key = $hit->{hostkey}; - &main::daemon_log("ServerPackage: host_name: $host_name", 7); - &main::daemon_log("ServerPackage: host_key: $host_key", 7); - eval{ - my $key_cipher = &create_ciphering($host_key); - $msg = &decrypt_msg($crypted_msg, $key_cipher); - $msg_hash = &transform_msg2hash($msg); - }; - if($@) { - &main::daemon_log("ServerPackage: deciphering raise error", 7); - &main::daemon_log("$@", 8); - $msg = undef; - $msg_hash = undef; - $host_name = undef; - $host_key = undef; - } else { - last; - } - } - } - - if( not defined $msg ) { - &main::daemon_log("WARNING: ServerPackage do not understand the message:", 5); - &main::daemon_log("$@", 7); - return; - } - - # process incoming msg - my $header = @{$msg_hash->{header}}[0]; - my $source = @{$msg_hash->{source}}[0]; - - &main::daemon_log("receive '$header' at ServerPackages from $host", 1); - &main::daemon_log("ServerPackages: msg to process: \n$msg", 5); - - my @targets = @{$msg_hash->{target}}; - my $len_targets = @targets; - if ($len_targets == 0){ - &main::daemon_log("ERROR: ServerPackages: no target specified for msg $header", 1); - - } elsif ($len_targets == 1){ - # we have only one target symbol - my $target = $targets[0]; - &main::daemon_log("SeverPackages: msg is for: $target", 7); - - # msg is for server - if ($header eq 'new_passwd'){ &new_passwd($msg_hash)} - elsif ($header eq 'here_i_am') { &here_i_am($msg_hash)} - elsif ($header eq 'who_has') { &who_has($msg_hash) } - elsif ($header eq 'who_has_i_do') { &who_has_i_do($msg_hash)} - elsif ($header eq 'update_status') { &update_status($msg_hash) } - elsif ($header eq 'got_ping') { &got_ping($msg_hash)} - elsif ($header eq 'get_load') { &execute_actions($msg_hash)} - else { - if ($target eq "*") { - # msg is for all clients - my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients'} ); - 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); - } - - } else { - # msg is for one host - my $host_key; - - - if( not defined $host_key ) { - my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients', hostname=>$target} ); - if( 1 == keys %{$query_res} ) { - $host_key = $query_res->{1}->{host_key}; - } - } - - if( not defined $host_key ) { - my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server', hostname=>$target} ); - if( 1 == keys %{$query_res} ) { - $host_key = $query_res->{1}->{host_key}; - } - } - - if( not defined $host_key ) { - &main::daemon_log("ERROR: ServerPackages: target '".$target. - "' is not known neither in known_clients nor in known_server",1); - } else { - &send_msg_hash2address($msg_hash, $target, $host_key); - } - } - } - - } elsif ($len_targets > 1 ) { - # we have more than one target - # TODO to be implemented - } - - return ; -} - - -#=== 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 $target = @{$msg_hash->{target}}[0]; - my $header = @{$msg_hash->{header}}[0]; - - if(exists $main::known_daemons->{$source}) { - &main::add_content2known_daemons(hostname=>$source, status=>$header); - } else { - &main::add_content2known_clients(hostname=>$source, status=>$header); - } - - return; -} - - -#=== FUNCTION ================================================================ -# NAME: new_passwd -# PARAMETERS: msg_hash - ref - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub new_passwd { - my ($msg_hash) = @_; - - my $header = @{$msg_hash->{header}}[0]; - my $source_name = @{$msg_hash->{source}}[0]; - my $source_key = @{$msg_hash->{new_passwd}}[0]; - my $query_res; - - # check known_clients_db - $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients', hostname=>$source_name} ); - if( 1 == keys %{$query_res} ) { - my $update_hash = { table=>'known_clients' }; - $update_hash->{where} = [ { hostname=>[$source_name] } ]; - $update_hash->{update} = [ { - hostkey=>[$source_key], - timestamp=>[&get_time], - } ]; - my $res = $main::known_clients_db->update_dbentry( $update_hash ); - - my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name); - &send_msg_hash2address($hash, $source_name, $source_key); - return; - } - - # check known_server_db - $query_res = $main::known_server_db->select_dbentry( {table=>'known_server', hostname=>$source_name } ); - if( 1 == keys %{$query_res} ) { - my $update_hash = { table=>'known_server' }; - $update_hash->{where} = [ { hostname=>[$source_name] } ]; - $update_hash->{update} = [ { - hostkey=>[$source_key], - timestamp=>[&get_time], - } ]; - my $res = $main::known_server_db->update_dbentry( $update_hash ); - - my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name); - &send_msg_hash2address($hash, $source_name, $source_key); - return; - } - - &main::daemon_log("ERROR: $source_name not known for '$header'-msg", 1); - return; -} - - -sub send_msg_hash { - my ($hash, $host_name, $host_key); - - - my $answer = &send_msg_hash2address($hash, $host_name, $host_key); - - return; -} - - -#=== FUNCTION ================================================================ -# NAME: here_i_am -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub here_i_am { - my ($msg_hash) = @_; - - my $source = @{$msg_hash->{source}}[0]; - my $mac_address = @{$msg_hash->{mac_address}}[0]; - my $out_hash; - - # number of known clients - my $nu_clients = keys %{ $main::known_clients_db->select_dbentry( {table=>'known_clients'} ) }; - - # check wether client address or mac address is already known - if (exists $main::known_clients->{$source}) { - &main::daemon_log("WARNING: $source is already known as a client", 1); - &main::daemon_log("WARNING: values for $source are being overwritten", 1); - $nu_clients --; - } - - # number of actual activ clients - my $act_nu_clients = $nu_clients; - - &main::daemon_log("number of actual activ clients: $act_nu_clients", 5); - &main::daemon_log("number of maximal allowed clients: $max_clients", 5); - - if($max_clients <= $act_nu_clients) { - my $out_hash = &create_xml_hash("denied", $server_address, $source); - &add_content2xml_hash($out_hash, "denied", "I_cannot_take_any_more_clients!"); - my $passwd = @{$msg_hash->{new_passwd}}[0]; - &send_msg_hash2address($out_hash, $source, $passwd); - return; - } - - # new client accepted - my $new_passwd = @{$msg_hash->{new_passwd}}[0]; - - # create entry in known_clients - my $events = @{$msg_hash->{events}}[0]; - - # add entry to known_clients_db - my $res = $main::known_clients_db->add_dbentry( {table=>'known_clients', - primkey=>'hostname', - hostname=>$source, - events=>$events, - macaddress=>$mac_address, - status=>'registered', - hostkey=>$new_passwd, - timestamp=>&get_time, - } ); - - if ($res != 0) { - &main::daemon_log("ERROR: cannot add entry to known_clients: $res"); - return; - } - - # return acknowledgement to client - $out_hash = &create_xml_hash("registered", $server_address, $source); - &send_msg_hash2address($out_hash, $source, $new_passwd); - - # notify registered client to bus - if( $bus_activ eq "on") { - # fetch actual bus key - my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server'} ); - my $hostkey = $query_res->{1}->{hostkey}; - - # send update msg to bus - $out_hash = &create_xml_hash("new_client", $server_address, $bus_address, $source); - &send_msg_hash2address($out_hash, $bus_address, $hostkey); - - &main::daemon_log("send bus msg that client '$source' has registerd at server '$server_address'", 3); - } - - # give the new client his ldap config - &new_ldap_config($source); - - return; -} - - -#=== FUNCTION ================================================================ -# NAME: who_has -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: process this incoming message -#=============================================================================== -sub who_has { - my ($msg_hash) = @_ ; - - # what is your search pattern - my $search_pattern = @{$msg_hash->{who_has}}[0]; - my $search_element = @{$msg_hash->{$search_pattern}}[0]; - &main::daemon_log("who_has-msg looking for $search_pattern $search_element", 7); - - # scanning known_clients for search_pattern - my @host_addresses = keys %$main::known_clients; - my $known_clients_entries = length @host_addresses; - my $host_address; - foreach my $host (@host_addresses) { - my $client_element = $main::known_clients->{$host}->{$search_pattern}; - if ($search_element eq $client_element) { - $host_address = $host; - last; - } - } - - # search was successful - if (defined $host_address) { - my $source = @{$msg_hash->{source}}[0]; - my $out_msg = &create_xml_hash("who_has_i_do", $server_address, $source, "mac_address"); - &add_content2xml_hash($out_msg, "mac_address", $search_element); - &send_msg_hash2address($out_msg, $bus_address); - } - return; -} - - -sub who_has_i_do { - my ($msg_hash) = @_ ; - my $header = @{$msg_hash->{header}}[0]; - my $source = @{$msg_hash->{source}}[0]; - my $search_param = @{$msg_hash->{$header}}[0]; - my $search_value = @{$msg_hash->{$search_param}}[0]; - print "\ngot msg $header:\nserver $source has client with $search_param $search_value\n"; -} - - -#=== FUNCTION ================================================================ -# NAME: new_ldap_config -# PARAMETERS: address - string - ip address and port of a host -# RETURNS: nothing -# DESCRIPTION: send to address the ldap configuration found for dn gotoLdapServer -#=============================================================================== -sub new_ldap_config { - my ($address) = @_ ; - - my $res = $main::known_clients_db->select_dbentry( { table=>'known_clients', hostname=>$address } ); - - # check hit - my $hit_counter = keys %{$res}; - if( not $hit_counter == 1 ) { - &main::daemon_log("ERROR: more or no hit found in known_clients_db by query by '$address'", 1); - } - - my $macaddress = $res->{1}->{macaddress}; - my $hostkey = $res->{1}->{hostkey}; - - if (not defined $macaddress) { - &main::daemon_log("ERROR: no mac address found for client $address", 1); - return; - } - - # Build LDAP connection - my $ldap = Net::LDAP->new($ldap_uri); - if( not defined $ldap ) { - &main::daemon_log("ERROR: cannot connect to ldap: $ldap_uri", 1); - return; - } - - - # Bind to a directory with dn and password - my $mesg= $ldap->bind($ldap_admin_dn, $ldap_admin_password); - - # Perform search - $mesg = $ldap->search( base => $ldap_base, - scope => 'sub', - attrs => ['dn', 'gotoLdapServer'], - filter => "(&(objectClass=GOhard)(macaddress=$macaddress))"); - $mesg->code && die $mesg->error; - - # Sanity check - if ($mesg->count != 1) { - &main::daemon_log("WARNING: client mac address $macaddress not found/not unique in ldap search", 1); - &main::daemon_log("\tbase: $ldap_base", 1); - &main::daemon_log("\tscope: sub", 1); - &main::daemon_log("\tattrs: dn, gotoLdapServer", 1); - &main::daemon_log("\tfilter: (&(objectClass=GOhard)(macaddress=$macaddress))", 1); - return; - } - - my $entry= $mesg->entry(0); - my $dn= $entry->dn; - my @servers= $entry->get_value("gotoLdapServer"); - my @ldap_uris; - my $server; - my $base; - - # Do we need to look at an object class? - if ($#servers < 1){ - $mesg = $ldap->search( base => $ldap_base, - scope => 'sub', - attrs => ['dn', 'gotoLdapServer'], - filter => "(&(objectClass=gosaGroupOfNames)(member=$dn))"); - $mesg->code && die $mesg->error; - - # Sanity check - if ($mesg->count != 1) { - &main::daemon_log("WARNING: no LDAP information found for client mac $macaddress", 1); - return; - } - - $entry= $mesg->entry(0); - $dn= $entry->dn; - @servers= $entry->get_value("gotoLdapServer"); - } - - @servers= sort (@servers); - - foreach $server (@servers){ - $base= $server; - $server =~ s%^[^:]+:[^:]+:(ldap.*://[^/]+)/.*$%$1%; - $base =~ s%^[^:]+:[^:]+:ldap.*://[^/]+/(.*)$%$1%; - push (@ldap_uris, $server); - } - - # Unbind - $mesg = $ldap->unbind; - - # Assemble data package - my %data = ( 'ldap_uri' => \@ldap_uris, 'ldap_base' => $base, - 'ldap_cfg' => \@ldap_cfg, 'pam_cfg' => \@pam_cfg,'nss_cfg' => \@nss_cfg ); - - # Need to append GOto settings? - if (defined $goto_admin and defined $goto_secret){ - $data{'goto_admin'}= $goto_admin; - $data{'goto_secret'}= $goto_secret; - } - - # Send information - send_msg("new_ldap_config", $server_address, $address, \%data, $hostkey); - - return; -} - - -#=== FUNCTION ================================================================ -# NAME: execute_actions -# PARAMETERS: msg_hash - hash - hash from function create_xml_hash -# RETURNS: nothing -# DESCRIPTION: invokes the script specified in msg_hash which is located under -# /etc/gosad/actions -#=============================================================================== -sub execute_actions { - my ($msg_hash) = @_ ; - my $configdir= '/etc/gosad/actions/'; - my $result; - - my $header = @{$msg_hash->{header}}[0]; - my $source = @{$msg_hash->{source}}[0]; - my $target = @{$msg_hash->{target}}[0]; - - if((not defined $source) - && (not defined $target) - && (not defined $header)) { - &main::daemon_log("ERROR: Entries missing in XML msg for gosad actions under /etc/gosad/actions"); - } else { - my $parameters=""; - my @params = @{$msg_hash->{$header}}; - my $params = join(", ", @params); - &main::daemon_log("execute_actions: got parameters: $params", 5); - - if (@params) { - foreach my $param (@params) { - my $param_value = (&get_content_from_xml_hash($msg_hash, $param))[0]; - &main::daemon_log("execute_actions: parameter -> value: $param -> $param_value", 7); - $parameters.= " ".$param_value; - } - } - - my $cmd= $configdir.$header."$parameters"; - &main::daemon_log("execute_actions: executing cmd: $cmd", 7); - $result= ""; - open(PIPE, "$cmd 2>&1 |"); - while() { - $result.=$_; - } - close(PIPE); - } - - # process the event result - - - return; -} - - -1; diff --git a/gosa-si-poe/modules/TestModule.pm b/gosa-si-poe/modules/TestModule.pm deleted file mode 100644 index 90c8d6abb..000000000 --- a/gosa-si-poe/modules/TestModule.pm +++ /dev/null @@ -1,76 +0,0 @@ -package TestModule; - -use Exporter; -@ISA = ("Exporter"); - -use strict; -use warnings; -use GosaSupportDaemon; - -BEGIN{ -} - -END{} - -### START ########## - - -sub get_module_tags { - - # lese config file aus dort gibt es eine section Basic - # dort stehen drei packettypen, für die sich das modul anmelden kann, gosa-admin-packages, - # server-packages, client-packages - my %tag_hash = (gosa_admin_packages => "yes", - server_packages => "yes", - client_packages => "yes", - ); - return \%tag_hash; -} - - -sub process_incoming_msg { - my ($crypted_msg) = @_ ; - if(not defined $crypted_msg) { - &main::daemon_log("function 'process_incoming_msg': got no msg", 7); - } - &main::daemon_log("TestModule: crypted_msg:$crypted_msg", 7); - &main::daemon_log("TestModule: crypted_msg len:".length($crypted_msg), 7); - - - # chomp address from host who send the message - $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); - - my $gosa_passwd = $main::gosa_passwd; - my $gosa_cipher = &create_ciphering($gosa_passwd); - - my $in_msg; - my $in_hash; - eval{ - $in_msg = &decrypt_msg($crypted_msg, $gosa_cipher); - $in_hash = &transform_msg2hash($in_msg); - }; - if ($@) { - &main::daemon_log("TestModul konnte msg nicht entschlüsseln:", 5); - &main::daemon_log("$@", 7); - return; - } - - my $header = @{$in_hash->{header}}[0]; - my $ip_address = @{$in_hash->{target}}[0]; - - - # hier kommt die logik suche den entsprechenden daemon, der den client target hat - - my $out_hash = &create_xml_hash("halt", $main::server_address, $ip_address); - - &send_msg_hash2address($out_hash, $ip_address); - - &main::daemon_log("TestModul: ip $ip_address bekommt $header "); - return ; -} - - - - diff --git a/gosa-si-poe/server.conf b/gosa-si-poe/server.conf deleted file mode 100644 index 3386c00a6..000000000 --- a/gosa-si-poe/server.conf +++ /dev/null @@ -1,32 +0,0 @@ -[general] -log_file = /var/log/gosa-si-server.log -pid_file = /var/run/gosa-si-server.pid -child_max = 10 -child_min = 2 -child_timeout = 10 -job_queue_timeout = 5 - -[bus] -bus_activ = on -bus_passwd = secret-bus-password -bus_ip = 127.0.0.1 -bus_port = 20080 - -[server] -server_activ = on -server_port = 20081 -server_passwd = secret-server-password -max_clients = 5 -server_event_dir = /usr/lib/gosa-si/server/events - -[arp] -arp_activ = off -arp_fifo_path = /var/run/gosa-si/arp-notify - -[gosa] -gosa_activ = on -gosa_ip = 127.0.0.1 -gosa_port = 20082 -gosa_passwd = secret-gosa-password -gosa_timeout = 5 - diff --git a/gosa-si-poe/server/events/ping b/gosa-si-poe/server/events/ping deleted file mode 100755 index f8ae99606..000000000 --- a/gosa-si-poe/server/events/ping +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -use GosaSupportDaemon; - - -# transform msg to hash -my $hash = &transform_msg2hash($ARGV[0]); - -# extract from hash all what you need -my $header = @{$hash->{header}}[0]; -my $source = @{$hash->{source}}[0]; -my $target = @{$hash->{target}}[0]; -my $jobdb_id = @{$hash->{jobdb_id}}[0]; - -# and do what ever you want - - -my $out_hash = &create_xml_hash("got_ping", "10.89.1.155:10001", "10.89.1.155:10000"); -if (defined $jobdb_id) { - &add_content2xml_hash($out_hash, 'jobdb_id', $jobdb_id); -} -my $out_xml = &create_xml_string($out_hash); -print $out_xml; - diff --git a/gosa-si-poe/tests/client.php b/gosa-si-poe/tests/client.php deleted file mode 100755 index 8c715148d..000000000 --- a/gosa-si-poe/tests/client.php +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/php5 -q -setEncryptionKey("secret-gosa-password"); - -if($sock->connected()){ - /* Prepare a hunge bunch of data to be send */ - -# add -#$data = "
gosa_ping
10.89.1.155:2008210.89.1.155:20080
"; -# $data = "
job_ping
10.89.1.155:2008300:1B:77:04:8A:6C 19700101000000
"; -# $data = "
job_sayHello
10.89.1.155:2008300:1B:77:04:8A:6C 20130102133900
"; -# $data = "
job_ping
10.89.1.155:2008300:1B:77:04:8A:6C 20130102133900
"; - -# delete - #$data = "
gosa_delete_jobdb_entry
headertag sayHello
"; - -# update - #$data = "
gosa_update_status_jobdb_entry
waiting processing
"; - #$data = "
gosa_update_status_jobdb_entry
waiting
"; - #$data = "
gosa_update_timestamp_jobdb_entry
20130123456789
"; - -# query -$data = "
gosa_query_jobdb
statuserror
"; - -# clear - #$data = "
gosa_clear_jobdb
"; - - $sock->write($data); - $answer = "nothing"; - $answer = $sock->read(); - echo ">>>$answer<<<\n"; - $sock->close(); -}else{ - echo "... FAILED!\n"; -} - -?> diff --git a/gosa-si-poe/tests/sqlite-check.pl b/gosa-si-poe/tests/sqlite-check.pl deleted file mode 100755 index 63f2ac6d8..000000000 --- a/gosa-si-poe/tests/sqlite-check.pl +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/perl -#=============================================================================== -# -# FILE: DBD-SQlite.pl -# -# USAGE: ./DBD-SQlite.pl -# -# DESCRIPTION: -# -# OPTIONS: --- -# REQUIREMENTS: --- -# BUGS: --- -# NOTES: --- -# AUTHOR: (), <> -# COMPANY: -# VERSION: 1.0 -# CREATED: 20.12.2007 08:54:52 CET -# REVISION: --- -#=============================================================================== - -use strict; -use warnings; -use GOSA::DBsqlite; - - -print "START\n"; -my $res; -my $db_name; - -$db_name = "/var/lib/gosa-si/jobs.db"; -if (-e $db_name) { - print "\n############################################################\n"; - $db_name =~ /\/([^\/]*?)\.db$/; - my $table_name = $1; - 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"; -} - - -$db_name = "/var/lib/gosa-si/known_clients.db"; -if (-e $db_name) { - print "\n############################################################\n"; - $db_name =~ /\/([^\/]*?)\.db$/; - my $table_name = $1; - - 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"; -} - - -$db_name = "/var/lib/gosa-si/known_server.db"; -if (-e $db_name) { - print "\n############################################################\n"; - $db_name =~ /\/([^\/]*?)\.db$/; - my $table_name = $1; - - 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"; -} - - -$db_name = "/var/lib/gosa-si/bus_known_server.db"; -if (-e $db_name) { - print "\n############################################################\n"; - $db_name =~ /\/([^\/]*?)\.db$/; - my $table_name = $1; - 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"; diff --git a/gosa-si-poe/tests/testGOsa.pl b/gosa-si-poe/tests/testGOsa.pl deleted file mode 100644 index 9ecb8f385..000000000 --- a/gosa-si-poe/tests/testGOsa.pl +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/perl -#=============================================================================== -# -# FILE: testGosa.pl -# -# USAGE: ./testGosa.pl -# -# DESCRIPTION: -# -# OPTIONS: --- -# REQUIREMENTS: --- -# BUGS: --- -# NOTES: --- -# AUTHOR: (), <> -# COMPANY: -# VERSION: 1.0 -# CREATED: 06.12.2007 14:31:37 CET -# REVISION: --- -#=============================================================================== - -use strict; -use warnings; -use IO::Socket::INET; -use Digest::MD5 qw(md5 md5_hex md5_base64); -use Crypt::Rijndael; -use MIME::Base64; - -sub create_ciphering { - my ($passwd) = @_; - - $passwd = substr(md5_hex("$passwd") x 32, 0, 32); - my $iv = substr(md5_hex('GONICUS GmbH'),0, 16); - print "iv: $iv\n"; - print "key: $passwd\n"; - - my $my_cipher = Crypt::Rijndael->new($passwd ,Crypt::Rijndael::MODE_CBC() ); - $my_cipher->set_iv($iv); - return $my_cipher; -} - -sub decrypt_msg { - my ($crypted_msg, $my_cipher) = @_ ; - $crypted_msg = &decode_base64($crypted_msg); - my $msg = $my_cipher->decrypt($crypted_msg); - return $msg; -} - -sub encrypt_msg { - my ($msg, $my_cipher) = @_; - if(not defined $my_cipher) { print "no cipher object\n"; } - $msg = "\0"x(16-length($msg)%16).$msg; - my $crypted_msg = $my_cipher->encrypt($msg); - chomp($crypted_msg = &encode_base64($crypted_msg)); - return $crypted_msg; -} - - - -my $gosa_server = IO::Socket::INET->new(LocalPort => "9999", - Type => SOCK_STREAM, - Reuse => 1, - Listen => 1, - ); - - - - - -my $client = $gosa_server->accept(); -my $other_end = getpeername($client); -if(not defined $other_end) { - print "client cannot be identified:"; -} else { - my ($port, $iaddr) = unpack_sockaddr_in($other_end); - my $actual_ip = inet_ntoa($iaddr); - print "accept client at gosa socket from $actual_ip\n"; - chomp(my $crypted_msg = <$client>); - print "crypted msg: <<<$crypted_msg<<<\n"; - - my $cipher = &create_ciphering("ferdinand_frost"); - - my $msg = &decrypt_msg($crypted_msg, $cipher); - print "msg: <<<$msg<<<\n"; - - print "\n#################################\n\n"; - - my $answer = "gosa answer: $msg"; - - print "answer: $answer\n"; - - my $out_cipher = &create_ciphering("ferdinand_frost"); - my $crypted_answer = &encrypt_msg($answer, $out_cipher); - - print $client $crypted_answer."\n"; - -} - -sleep(3); -close($client); - - - - - - - - diff --git a/gosa-si/README b/gosa-si/README new file mode 100644 index 000000000..e8c755530 --- /dev/null +++ b/gosa-si/README @@ -0,0 +1,29 @@ + +/usr/share/perl5/GOSA +common: +- GosaSupportDaemon.pm +- DBsqlite.pm + +/usr/lib/gosa-si/modules +server-module: +- ArpPackages.pm +- GosaPackages.pm +- ServerPackages.pm +- FAIPackages.pm + +server-events: +/usr/lib/gosa-si/server +- ping + +client-events: +/usr/lib/gosa-si/client + +config-files: /etc/gosa-si/ +- bus.conf +- client.conf +- server.conf + +/var/lib/gosa-si +db's: +- jobs.db + diff --git a/gosa-si/arp-handler-d b/gosa-si/arp-handler-d new file mode 100755 index 000000000..b8698bcf7 --- /dev/null +++ b/gosa-si/arp-handler-d @@ -0,0 +1,563 @@ +#!/usr/bin/perl +#=============================================================================== +# +# FILE: gosa-support-daemon.pl +# +# USAGE: ./.gosa-support-daemon.pl +# +# DESCRIPTION: +# +# OPTIONS: --- +# REQUIREMENTS: --- +# BUGS: --- +# NOTES: --- +# AUTHOR: Andreas Rettenberger, +# COMPANY: Gonicus GmbH, Arnsberg +# VERSION: 1.0 +# CREATED: 21.08.2007 15:13:51 CEST +# REVISION: --- +#=============================================================================== + +use strict; +use warnings; +use Getopt::Long; +use Config::IniFiles; +use POSIX; +use Fcntl; +use Net::LDAP; +use Net::LDAP::LDIF; +use Net::LDAP::Entry; +use Switch; + + +my ($verbose, $cfg_file, $log_file, $pid_file, $foreground); +my ($timeout, $mailto, $mailfrom, $user, $group); +my ($procid, $pid, $loglevel); +my ($fifo_path, $max_process_timeout, $max_process ); +my %daemon_children; +my ($ldap, $bind_phrase, $password, $ldap_base) ; + +$procid = -1 ; +$foreground = 0 ; +$verbose = 0 ; +$max_process = 2 ; +$max_process_timeout = 1 ; +$ldap_base = "dc=gonicus,dc=de" ; +#$ldap_path = "/var/run/gosa-support-daemon.socket"; +#$log_path = "/var/log/gosa-support-daemon.log"; +#$pid_path = "/var/run/gosa-support-daemon/gosa-support-daemon.pid"; + +#--------------------------------------------------------------------------- +# parse commandline options +#--------------------------------------------------------------------------- +Getopt::Long::Configure( "bundling" ); +GetOptions( "v|verbose+" => \$verbose, + "c|config=s" => \$cfg_file, + "h|help" => \&usage, + "l|logfile=s" => \$log_file, + "p|pid=s" => \$pid_file, + "f|foreground" => \$foreground); + +#--------------------------------------------------------------------------- +# read and set config parameters +#--------------------------------------------------------------------------- +my %cfg_defaults = +("Allgemein" => + {"timeout" => [ \$timeout, 1000 ], + "mailto" => [ \$mailto, 'root@localhost' ], + "mailfrom" => [ \$mailfrom, 'sps-daemon@localhost' ], + "user" => [ \$user, "nobody" ], + "group" => [ \$group, "nogroup" ], + "fifo_path" => [ \$fifo_path, "/home/rettenbe/gonicus/gosa-support/tmp/fifo" ], + "log_file" => [ \$log_file, "/home/rettenbe/gonicus/gosa-support/tmp/gosa-support.log" ], + "pid_file" => [ \$pid_file, "/home/rettenbe/gonicus/gosa-support/tmp/gosa-support.pid" ], + "loglevel" => [ \$loglevel, 1] + }, +"LDAP" => + {"bind" => [ \$bind_phrase, "cn=ldapadmin,dc=gonicus,dc=de" ], + "password" => [ \$password, "tester" ], + } + ); +&read_configfile; + + +#=== FUNCTION ================================================================ +# NAME: check_cmdline_param +# PURPOSE: checks all commandline parameters to validity +# PARAMETERS: none +# RETURNS: none +# DESCRIPTION: ???? +# THROWS: no exceptions +# COMMENTS: none +# SEE ALSO: n/a +#=============================================================================== +sub check_cmdline_param () { + my $err_config; + my $err_log; + my $err_pid; + my $err_counter = 0; + if( not defined( $cfg_file)) { + $err_config = "please specify a config file"; + $err_counter += 1; + } + if( not defined( $log_file)) { + $err_log = "please specify a log file"; + $err_counter += 1; + } + if( not defined( $pid_file)) { + $err_pid = "please specify a pid file"; + $err_counter += 1; + } + if( $err_counter > 0 ) { + &usage( "", 1 ); + if( defined( $err_config)) { print STDERR "$err_config\n"} + if( defined( $err_log)) { print STDERR "$err_log\n" } + if( defined( $err_pid)) { print STDERR "$err_pid\n"} + print STDERR "\n"; + exit( -1 ); + } +} + +#=== FUNCTION ================================================================ +# NAME: check_pid +# PURPOSE: +# PARAMETERS: none +# RETURNS: none +# DESCRIPTION: ???? +# THROWS: no exceptions +# COMMENTS: none +# SEE ALSO: n/a +#=============================================================================== +sub check_pid { + if( open( LOCK_FILE, "<$pid_file") ) { + $procid = ; + if( defined $procid ) { + chomp( $procid ); + if( -f "/proc/$procid/stat" ) { + my($stat) = `cat /proc/$procid/stat` =~ m/$procid \((.+)\).*/; + print "\t".$stat."\n"; + if( "sps-daemon.pl" eq $stat ) { + close( LOCK_FILE ); + exit -1; + } + } + } + close( LOCK_FILE ); + unlink( $pid_file ); + } + + # Try to open PID file + if (!sysopen(LOCK_FILE, $pid_file, O_WRONLY|O_CREAT|O_EXCL, 0644)) { + my($msg) = "Couldn't obtain lockfile '$pid_file' "; + if (open(LOCK_FILE, "<", $pid_file) && ($pid = )) { + chomp($pid); + $msg .= "(PID $pid)\n"; + } else { + $msg .= "(unable to read PID)\n"; + } + if ( ! $foreground ) { + daemon_log( $msg."\n"); + } else { + print( STDERR " $msg " ); + } + exit( -1 ); + } +} + +#=== FUNCTION ================================================================ +# NAME: read_configfile +# PURPOSE: read the configuration file and provide the programm with +# parameters +# PARAMETERS: none +# RETURNS: none +# DESCRIPTION: ???? +# THROWS: no exceptions +# COMMENTS: none +# SEE ALSO: n/a +#=============================================================================== +sub read_configfile { + my $log_time = localtime(time); + my $cfg; + if( defined( $cfg_file) && ( length($cfg_file) > 0 )) { + if( -r $cfg_file ) { + $cfg = Config::IniFiles->new( -file => $cfg_file ); + } else { + usage( "Couldn't read config file: $cfg_file \n" ); + } + } else { + $cfg = Config::IniFiles->new() ; + } + + foreach my $section (keys %cfg_defaults) { # "Parse" config into values + foreach my $param (keys %{$cfg_defaults{ $section }}) { + my $pinfo = $cfg_defaults{ $section }{ $param }; + ${@$pinfo[ 0 ]} = $cfg->val( $section, $param, @$pinfo[ 1 ] ); + } + } + + if(-e $log_file ) { unlink $log_file } + daemon_log("$log_time: config file read\n"); +} + +#=== FUNCTION ================================================================ +# NAME: daemon_log +# PURPOSE: log messages to specified logfile +# PARAMETERS: $msg, $level +# RETURNS: ???? +# DESCRIPTION: Takes a message ($msg) and append it to the logfile. The +# standard log-level ($level) is 1. Messages whith higher level +# than the verbosity-level (defined by commandline) are printed +# out to commandline. Messages with log-level lower than 2 are +# not logged to logfile! +# THROWS: no exceptions +# COMMENTS: none +# SEE ALSO: n/a +#=============================================================================== +sub daemon_log { + my( $msg, $level ) = @_; + if(not defined $msg) { return } + if(not defined $level) { $level = 1 } + open(LOG_HANDLE, ">>$log_file"); + if(not defined open( LOG_HANDLE, ">>$log_file" ) ) { return } + chomp($msg); + #if( $verbose >= $level ) { print "$msg"."\n" } + if( $level <= 1 ) { print LOG_HANDLE $msg."\n" } + if( $foreground ) { print $msg."\n" } + close( LOG_HANDLE ); + } + +#=== FUNCTION ================================================================ +# NAME: signal handler +# PURPOSE: catches signals from the programm and do diffrent things +# than default +# PARAMETERS: none +# RETURNS: none +# DESCRIPTION: sighandler +# THROWS: no exceptions +# COMMENTS: none +# SEE ALSO: n/a +#=============================================================================== +sub sigINT { + my $log_time = localtime(time); + print "INT\n"; + if( -p $fifo_path ) { + close FIFO ; + unlink($fifo_path) ; + daemon_log( "$log_time: FIFO closed after signal INT!\n") ; + } + if(defined($ldap)) { + $ldap->unbind; + } + $SIG{INT} = "DEFAULT" ; + kill INT => $$ ; +} +$SIG{INT} = \&sigINT ; + +#=== FUNCTION ================================================================ +# NAME: usage +# PURPOSE: +# PARAMETERS: none +# RETURNS: none +# DESCRIPTION: print out the usage of the program +# THROWS: no exceptions +# COMMENTS: none +# SEE ALSO: n/a +#=============================================================================== +sub usage { + my( $text, $help ) = @_; + $text = undef if( "h" eq $text ); + (defined $text) && print STDERR "\n$text\n"; + if( (defined $help && $help) || (!defined $help && !defined $text) ) { + print STDERR << "EOF" ; +usage: $0 [-hvf] [-c config, -l logfile, -p pidfile] + + -h : this (help) message + -c : config file + -l : log file (example: /var/log/sps/sps.log) + -p : pid file (example: /var/run/sps/sps.pid) + -f : foreground (don"t fork) + -v : be verbose (multiple to increase verbosity) +EOF + } + print "\n" ; +} + + +#=== FUNCTION ================================================================ +# NAME: open_fifo +# PURPOSE: +# PARAMETERS: $fifo_path +# RETURNS: 0: FIFO couldn"t be setup, 1: FIFO setup correctly +# DESCRIPTION: creates a FIFO at $fifo_path +# THROWS: no exceptions +# COMMENTS: none +# SEE ALSO: n/a +#=============================================================================== +sub open_fifo { + my ($fifo_path) = @_ ; + my $log_time = localtime( time ); + if( -p $fifo_path ) { + daemon_log("$log_time: FIFO at $fifo_path already exists\n"); + return 0; + } + POSIX::mkfifo($fifo_path, 0666) or die "can't mkfifo $fifo_path: $!"; + daemon_log( "$log_time: FIFO started at $fifo_path\n" ) ; + return 1; + } + + +#=== FUNCTION ================================================================ +# NAME: add_ldap_entry +# PURPOSE: adds an element to ldap-tree +# PARAMETERS: +# RETURNS: none +# DESCRIPTION: ???? +# THROWS: no exceptions +# COMMENTS: none +# SEE ALSO: n/a +#=============================================================================== +sub add_ldap_entry { + my ($ldap_tree, $ldap_base, $mac, $gotoSysStatus, $ip, $interface, $desc) = @_; + my $dn = "cn=$mac,ou=incoming,$ldap_base"; + my $s_res = &search_ldap_entry($ldap_tree, $ldap_base, "(|(macAddress=$mac)(dhcpHWAddress=ethernet $mac))"); + my $c_res = $s_res->count; + if($c_res == 1) { + daemon_log("WARNING: macAddress $mac already in LDAP", 1); + return; + } elsif($c_res > 0) { + daemon_log("ERROR: macAddress $mac exists $c_res times in LDAP", 1); + return; + } + + # create LDAP entry + my $entry = Net::LDAP::Entry->new( $dn ); + $entry->dn($dn); + $entry->add("objectClass" => "goHard"); + $entry->add("cn" => $mac); + $entry->add("macAddress" => $mac); + if(defined $gotoSysStatus) {$entry->add("gotoSysStatus" => $gotoSysStatus)} + if(defined $ip) {$entry->add("ipHostNumber" => $ip) } + #if(defined $interface) { } + if(defined $desc) {$entry->add("description" => $desc) } + + # submit entry to LDAP + my $result = $entry->update ($ldap_tree); + + # for $result->code constants please look at Net::LDAP::Constant + my $log_time = localtime( time ); + if($result->code == 68) { # entry already exists + daemon_log("WARNING: $log_time: $dn ".$result->error, 3); + } elsif($result->code == 0) { # everything went fine + daemon_log("$log_time: add entry $dn to ldap", 1); + } else { # if any other error occur + daemon_log("ERROR: $log_time: $dn, ".$result->code.", ".$result->error, 1); + } + return; +} + + +#=== FUNCTION ================================================================ +# NAME: change_ldap_entry +# PURPOSE: ???? +# PARAMETERS: ???? +# RETURNS: ???? +# DESCRIPTION: ???? +# THROWS: no exceptions +# COMMENTS: none +# SEE ALSO: n/a +#=============================================================================== +sub change_ldap_entry { + my ($ldap_tree, $ldap_base, $mac, $gotoSysStatus ) = @_; + + # check if ldap_entry exists or not + my $s_res = &search_ldap_entry($ldap_tree, $ldap_base, "(|(macAddress=$mac)(dhcpHWAddress=ethernet $mac))"); + my $c_res = $s_res->count; + if($c_res == 0) { + daemon_log("WARNING: macAddress $mac not in LDAP", 1); + return; + } elsif($c_res > 1) { + daemon_log("ERROR: macAddress $mac exists $c_res times in LDAP", 1); + return; + } + + my $s_res_entry = $s_res->pop_entry(); + my $dn = $s_res_entry->dn(); + my $result = $ldap->modify( $dn, replace => {'gotoSysStatus' => $gotoSysStatus } ); + + # for $result->code constants please look at Net::LDAP::Constant + my $log_time = localtime( time ); + if($result->code == 32) { # entry doesnt exists + &add_ldap_entry($mac, $gotoSysStatus); + } elsif($result->code == 0) { # everything went fine + daemon_log("$log_time: entry $dn changed successful", 1); + } else { # if any other error occur + daemon_log("ERROR: $log_time: $dn, ".$result->code.", ".$result->error, 1); + } + + return; +} + +#=== FUNCTION ================================================================ +# NAME: search_ldap_entry +# PURPOSE: ???? +# PARAMETERS: [Net::LDAP] $ldap_tree - object of an ldap-tree +# string $sub_tree - dn of the subtree the search is performed +# string $search_string - either a string or a Net::LDAP::Filter object +# RETURNS: [Net::LDAP::Search] $msg - result object of the performed search +# DESCRIPTION: ???? +# THROWS: no exceptions +# COMMENTS: none +# SEE ALSO: n/a +#=============================================================================== +sub search_ldap_entry { + my ($ldap_tree, $sub_tree, $search_string) = @_; + my $msg = $ldap_tree->search( # perform a search + base => $sub_tree, + filter => $search_string, + ) or daemon_log("cannot perform search at ldap: $@", 1); +# if(defined $msg) { +# print $sub_tree."\t".$search_string."\t"; +# print $msg->count."\n"; +# foreach my $entry ($msg->entries) { $entry->dump; }; +# } + + return $msg; +} + + + +#========= MAIN = main ======================================================== +daemon_log( "####### START DAEMON ######\n", 1 ); +&check_cmdline_param ; +&check_pid; +&open_fifo($fifo_path); + +# Just fork, if we"re not in foreground mode +if( ! $foreground ) { $pid = fork(); } +else { $pid = $$; } + +# Do something useful - put our PID into the pid_file +if( 0 != $pid ) { + open( LOCK_FILE, ">$pid_file" ); + print LOCK_FILE "$pid\n"; + close( LOCK_FILE ); + if( !$foreground ) { exit( 0 ) }; +} + + +if( not -p $fifo_path ) { die "fifo file disappeared\n" } +sysopen(FIFO, $fifo_path, O_RDONLY) or die "can't read from $fifo_path: $!" ; + +while( 1 ) { + # checke alle prozesse im hash daemon_children ob sie noch aktiv sind, wenn + # nicht, dann entferne prozess aus hash + while( (my $key, my $val) = each( %daemon_children) ) { + my $status = waitpid( $key, &WNOHANG) ; + if( $status == -1 ) { + delete $daemon_children{$key} ; + daemon_log("childprocess finished: $key", 3) ; + } + } + + # ist die max_process anzahl von prozesskindern erreicht, dann warte und + # prüfe erneut, ob in der zwischenzeit prozesse fertig geworden sind + if( keys( %daemon_children ) >= $max_process ) { + sleep($max_process_timeout) ; + next ; + } + + my $msg = ; + if( not defined( $msg )) { next ; } + + chomp( $msg ); + if( length( $msg ) == 0 ) { next ; } + + my $forked_pid = fork(); +#=== PARENT = parent ========================================================== + if ( $forked_pid != 0 ) { + daemon_log("childprocess forked: $forked_pid", 3) ; + $daemon_children{$forked_pid} = 0 ; + } +#=== CHILD = child ============================================================ + else { + # parse the incoming message from arp, split the message and return + # the values in an array. not defined values are set to "none" + #my ($mac, $ip, $interface, $arp_sig, $desc) = &parse_input( $msg ) ; + daemon_log( "childprocess read from arp: $fifo_path\nline: $msg", 3); + my ($mac, $ip, $interface, $arp_sig, $desc) = split('\s', $msg, 5); + + # create connection to LDAP + $ldap = Net::LDAP->new( "localhost" ) or die "$@"; + $ldap->bind($bind_phrase, + password => $password, + ) ; + + switch($arp_sig) { + case 0 {&change_ldap_entry($ldap, $ldap_base, + $mac, "ip-changed", + )} + case 1 {&change_ldap_entry($ldap, $ldap_base, + $mac, "mac-not-whitelisted", + )} + case 2 {&change_ldap_entry($ldap, $ldap_base, + $mac, "mac-in-blacklist", + )} + case 3 {&add_ldap_entry($ldap, $ldap_base, + $mac, "new-mac-address", $ip, + $interface, $desc, + )} + case 4 {&change_ldap_entry($ldap, $ldap_base, + $mac, "unauthorized-arp-request", + )} + case 5 {&change_ldap_entry($ldap, $ldap_base, + $mac, "abusive-number-of-arp-requests", + )} + case 6 {&change_ldap_entry($ldap, $ldap_base, + $mac, "ether-and-arp-mac-differs", + )} + case 7 {&change_ldap_entry($ldap, $ldap_base, + $mac, "flood-detected", + )} + case 8 {&add_ldap_entry($ldap, $ldap_base, + $mac, $ip, "new-system", + )} + case 9 {&change_ldap_entry($ldap, $ldap_base, + $mac, "mac-changed", + )} + } + + + # ldap search +# my $base_phrase = "dc=gonicus,dc=de"; +# my $filter_phrase = "cn=keinesorge"; +# my $attrs_phrase = "cn macAdress"; +# my $msg_search = $ldap->search( base => $base_phrase, +# filter => $filter_phrase, +# attrs => $attrs_phrase, +# ); +# $msg_search->code && die $msg_search->error; +# +# my @entries = $msg_search->entries; +# my $max = $msg_search->count; +# print "anzahl der entries: $max\n"; +# my $i; +# for ( $i = 0 ; $i < $max ; $i++ ) { +# my $entry = $msg_search->entry ( $i ); +# foreach my $attr ( $entry->attributes ) { +# if( not $attr eq "cn") { +# next; +# } +# print join( "\n ", $attr, $entry->get_value( $attr ) ), "\n\n"; +# } +# } + + # ldap add + + + $ldap->unbind; + exit; + } + +} + + diff --git a/gosa-si/arp-handler-d.cfg b/gosa-si/arp-handler-d.cfg new file mode 100644 index 000000000..36c24a35b --- /dev/null +++ b/gosa-si/arp-handler-d.cfg @@ -0,0 +1,14 @@ +[Allgemein] +timeout = 1000 +mailto = root@localhost +mailfrom = gosa-sd@localhost +user = rettenbe +group = usr +fifo_path = /home/rettenbe/gonicus/projekte/gosa-trunk/contrib/daemon/fifo +log_file = /home/rettenbe/gonicus/projekte/gosa-trunk/contrib/daemon/gosa-sd.log +pid_file = /home/rettenbe/gonicus/projekte/gosa-trunk/contrib/daemon/gosa-sd.pid +loglevel = 1 + +[LDAP] +bind = cn=ldapadmin,dc=gonicus,dc=de +password = tester diff --git a/gosa-si/bus.conf b/gosa-si/bus.conf new file mode 100644 index 000000000..7ca56e906 --- /dev/null +++ b/gosa-si/bus.conf @@ -0,0 +1,13 @@ +[general] +log_file = /var/log/gosa-si-bus.log +pid_file = /var/run/gosa-si-bus.pid +child_max = 10 +child_min = 2 +child_timeout = 10 + +[bus] +bus_activ = on +bus_passwd = secret-bus-password +bus_ip = 127.0.0.1 +bus_port = 20080 + diff --git a/gosa-si/client.conf b/gosa-si/client.conf new file mode 100644 index 000000000..0c65e2cad --- /dev/null +++ b/gosa-si/client.conf @@ -0,0 +1,13 @@ +[general] +log_file = /var/log/gosa-si-client.log +pid_file = /var/run/gosa-si-client.pid + +[client] +client_port = 20083 + +[server] +server_ip = 127.0.0.1 +server_port = 20081 +server_passwd = secret-server-password +server_timeout = 5 +server_domain = intranet.gonicus.de diff --git a/gosa-si/debian/README.debian b/gosa-si/debian/README.debian new file mode 100644 index 000000000..100bd2d6d --- /dev/null +++ b/gosa-si/debian/README.debian @@ -0,0 +1,11 @@ +README.Debian for GOto 3.0 +-------------------------- + +* Configuring GOto 3.0 + +You need a proper LDAP/FAI/GOsa setup to make this run. More +text will follow later. Sorry. + +---- +Cajus Pollmeier Fri 02 Jun 2006 16:23:50 +0200 + diff --git a/gosa-si/debian/changelog b/gosa-si/debian/changelog new file mode 100644 index 000000000..5412238b3 --- /dev/null +++ b/gosa-si/debian/changelog @@ -0,0 +1,6 @@ +gosa-si (1.0-1) unstable; urgency=low + + * Initial release + + -- Cajus Pollmeier Fri, 7 Dec 2007 11:37:45 +0100 + diff --git a/gosa-si/debian/compat b/gosa-si/debian/compat new file mode 100644 index 000000000..7ed6ff82d --- /dev/null +++ b/gosa-si/debian/compat @@ -0,0 +1 @@ +5 diff --git a/gosa-si/debian/control b/gosa-si/debian/control new file mode 100644 index 000000000..fd596d22d --- /dev/null +++ b/gosa-si/debian/control @@ -0,0 +1,40 @@ +Source: gosa-si +Section: utils +Priority: optional +Maintainer: Cajus Pollmeier +Standards-Version: 3.7.2.2 +Build-Depends: debhelper(>= 4.2.32), dpatch + +Package: gosa-si-common +Architecture: any +Depends: libconfig-inifiles-perl, libcrypt-rijndael-perl, libxml-simple-perl, libipc-shareable-perl, libdata-dumper-simple-perl, libmime-perl, libdbd-sqlite3-perl, libnet-ldap-perl, libnetaddr-ip-perl +Suggests: gosa-si-server, gosa-si-client +Description: GOsa support infrastructure + This package provides common library functionality used by the + infrastructure server and client packages. + . + GOsa is a combination of system-administrator and end-user web + interface, designed to handle LDAP based setups. + +Package: gosa-si-server +Architecture: any +Depends: gosa-si-common +Suggests: gosa +Description: GOsa support infrastructure server + This package provides everything you need in order to deploy a simple + or distributed GOsa support infrastructure. It can be used to trigger + certain actions or retrieve information from clients. + . + GOsa is a combination of system-administrator and end-user web + interface, designed to handle LDAP based setups. + +Package: gosa-si-client +Architecture: any +Depends: gosa-si-common +Suggests: gosa +Description: GOsa support infrastructure client + This package lets you join to a GOsa support infrastructure as a + client in order to provide information or to act on events. + . + GOsa is a combination of system-administrator and end-user web + interface, designed to handle LDAP based setups. diff --git a/gosa-si/debian/copyright b/gosa-si/debian/copyright new file mode 100644 index 000000000..d7463efe4 --- /dev/null +++ b/gosa-si/debian/copyright @@ -0,0 +1,8 @@ +This package was debianized by Cajus Pollmeier + on Mon, 25 Jun 2007 12:57:35 +0100. + +Copyright: GPL2 + +This code is released under the terms of the GPLv2 license. + +See /usr/share/common-licenses/GPL-2 for the full license. diff --git a/gosa-si/debian/gosa-si b/gosa-si/debian/gosa-si new file mode 100644 index 000000000..10df929a0 --- /dev/null +++ b/gosa-si/debian/gosa-si @@ -0,0 +1,2 @@ +# /etc/default/gosa-si - configure the init script +START_BUS=0 diff --git a/gosa-si/debian/gosa-si-client.dirs b/gosa-si/debian/gosa-si-client.dirs new file mode 100644 index 000000000..2f6b7067d --- /dev/null +++ b/gosa-si/debian/gosa-si-client.dirs @@ -0,0 +1,3 @@ +etc/gosa-si +usr/sbin +usr/lib/gosa-si/client/events diff --git a/gosa-si/debian/gosa-si-client.install b/gosa-si/debian/gosa-si-client.install new file mode 100644 index 000000000..e5544c641 --- /dev/null +++ b/gosa-si/debian/gosa-si-client.install @@ -0,0 +1,2 @@ +gosa-si-client usr/sbin +client.conf etc/gosa-si diff --git a/gosa-si/debian/gosa-si-client.postinst b/gosa-si/debian/gosa-si-client.postinst new file mode 100644 index 000000000..0747c6a3d --- /dev/null +++ b/gosa-si/debian/gosa-si-client.postinst @@ -0,0 +1,15 @@ +#!/bin/sh + +#DEBHELPER# + +# We exit unless the package is being configured +case "$1" in + abort*upgrade) exit 0;; + abort*remove) exit 0;; + abort*deconfigure) exit 0;; + configure) ;; + *) exit 0; +esac + +[ ! -d /usr/lib/gosa-si/client/events ] && install -d -o root -g root -m 750 /usr/lib/gosa-si/client/events + diff --git a/gosa-si/debian/gosa-si-common.dirs b/gosa-si/debian/gosa-si-common.dirs new file mode 100644 index 000000000..2d13e8f10 --- /dev/null +++ b/gosa-si/debian/gosa-si-common.dirs @@ -0,0 +1,2 @@ +/etc/default +/usr/share/perl5/GOSA diff --git a/gosa-si/debian/gosa-si-common.install b/gosa-si/debian/gosa-si-common.install new file mode 100644 index 000000000..3db70042e --- /dev/null +++ b/gosa-si/debian/gosa-si-common.install @@ -0,0 +1,3 @@ +modules/GosaSupportDaemon.pm usr/share/perl5/GOSA +modules/DBsqlite.pm usr/share/perl5/GOSA +debian/gosa-si etc/default diff --git a/gosa-si/debian/gosa-si-common.postinst b/gosa-si/debian/gosa-si-common.postinst new file mode 100644 index 000000000..3d2b7723d --- /dev/null +++ b/gosa-si/debian/gosa-si-common.postinst @@ -0,0 +1,15 @@ +#!/bin/sh + +#DEBHELPER# + +# We exit unless the package is being configured +case "$1" in + abort*upgrade) exit 0;; + abort*remove) exit 0;; + abort*deconfigure) exit 0;; + configure) ;; + *) exit 0; +esac + +[ -d /var/lib/gosa-si ] || install -d -o root -g root -m 750 /var/lib/gosa-si + diff --git a/gosa-si/debian/gosa-si-server.dirs b/gosa-si/debian/gosa-si-server.dirs new file mode 100644 index 000000000..be099ffcf --- /dev/null +++ b/gosa-si/debian/gosa-si-server.dirs @@ -0,0 +1,4 @@ +usr/sbin +usr/lib/gosa-si/modules +usr/lib/gosa-si/server/events +etc/gosa-si diff --git a/gosa-si/debian/gosa-si-server.init b/gosa-si/debian/gosa-si-server.init new file mode 100755 index 000000000..18e68aefc --- /dev/null +++ b/gosa-si/debian/gosa-si-server.init @@ -0,0 +1,91 @@ +#!/bin/sh +# Start/stop the GOsa support daemon infrastructure. +# +### BEGIN INIT INFO +# Provides: gosa-si +# Required-Start: $syslog $time +# Required-Stop: $syslog $time +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: GOsa message bus and server component +# Description: gosa-si establishes the communication between a couple of +# GOsa hosting servers and optionally clients to do event +# signaling for all communication partners. +### END INIT INFO + +# Sanity checks +test -f /usr/sbin/gosa-si-server || exit 0 +test -f /usr/sbin/gosa-si-bus || exit 0 + +# Load defaults +START_BUS=0 +[ -r /etc/default/gosa-si ] && . /etc/default/gosa-si + +# Load LSB support functions +. /lib/lsb/init-functions + + +start_bus() { + start-stop-daemon --start --quiet --pidfile /var/run/gosa-si-bus.pid --name gosa-si-bus --startas /usr/sbin/gosa-si-bus -- +} + + +start_server() { + start-stop-daemon --start --quiet --pidfile /var/run/gosa-si-server.pid --name gosa-si-server --startas /usr/sbin/gosa-si-server -- -vvvvv $1 +} + + +stop_bus() { + start-stop-daemon --stop --retry 5 --quiet --pidfile /var/run/gosa-si-bus.pid --name gosa-si-bus +} + + +stop_server() { + start-stop-daemon --stop --retry 5 --quiet --pidfile /var/run/gosa-si-server.pid --name gosa-si-server +} + + +case "$1" in +start) log_daemon_msg "Starting GOsa support infrastructure" + if [ "$START_BUS" == "1" ]; then + log_progress_msg "bus" + start_bus + log_progress_msg "daemon" + start_server + else + log_progress_msg "daemon" + start_server --no-bus + fi + log_end_msg $? + ;; +stop) log_daemon_msg "Stopping GOsa support infrastructure" + if [ "$START_BUS" == "1" ]; then + log_progress_msg "daemon" + stop_server + log_progress_msg "bus" + stop_bus + else + log_progress_msg "daemon" + stop_server + fi + log_end_msg $? + ;; +reload|force-reload|restart) log_daemon_msg "Restarting GOsa support infrastructure" + if [ "$START_BUS" == "1" ]; then + stop_server + stop_bus + start_bus + start_server --no-bus + log_progress_msg "done" + else + stop_server + start_server --no-bus + log_progress_msg "done" + fi + log_end_msg $? + ;; +*) log_action_msg "Usage: /etc/init.d/gosa-si {start|stop|restart|reload|force-reload}" + exit 2 + ;; +esac +exit 0 diff --git a/gosa-si/debian/gosa-si-server.install b/gosa-si/debian/gosa-si-server.install new file mode 100644 index 000000000..b7c600f74 --- /dev/null +++ b/gosa-si/debian/gosa-si-server.install @@ -0,0 +1,7 @@ +gosa-si-server usr/sbin +gosa-si-bus usr/sbin +server.conf etc/gosa-si +bus.conf etc/gosa-si +modules/ServerPackages.pm usr/lib/gosa-si/modules +modules/GosaPackages.pm usr/lib/gosa-si/modules +server/events/ping usr/lib/gosa-si/server/events diff --git a/gosa-si/debian/rules b/gosa-si/debian/rules new file mode 100755 index 000000000..f54d5592a --- /dev/null +++ b/gosa-si/debian/rules @@ -0,0 +1,83 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. GNU copyright 1997 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +build: patch + #******************************************************** + #* Building ltsp-goto into a Debian/GNU Linux Package * + #* please stand by * + #******************************************************** + +clean: clean-patched unpatch +clean-patched: + dh_testdir + rm -f install-stamp + -rm -f debian/files + -rm -rf debian/tmp + -rm -f debian/substvars + dh_clean + +unpatch: + dpatch deapply-all + rm -rf patch-stamp debian/patched + +install: install-stamp +install-stamp: + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Create a copy, remove svn stuff + -mkdir debian/tmp + -for i in *; do \ + cp -R $$i debian/tmp ; \ + done + -find debian/tmp -name '*.svn' -type d -exec rm -rf {} \; 2> /dev/null + + -for i in gosa-si-client gosa-si-server modules/GosaPackages.pm modules/ServerPackages.pm modules/TestModule.pm server/events/*; do sed -i 's/use GosaSupportDaemon;/use GOSA::GosaSupportDaemon;/g;s/use DBsqlite;/use GOSA::DBsqlite;/g' debian/tmp/$$i; done + + -sed -i 's!"/etc/gosa-si/modules";!use lib "/usr/lib/gosa-si/modules";!g' debian/tmp/gosa-si-server + + -sed -i 's!"/etc/gosa-si/server/events";!"/usr/lib/gosa-si/server/events";!g' debian/tmp/modules/GosaPackages.pm + + touch install-stamp + +patch: patch-stamp +patch-stamp: + dpatch apply-all + dpatch cat-all >patch-stamp + +binary-indep: install + dh_testdir + dh_testroot + + dh_install --sourcedir=debian/tmp + dh_installdocs + dh_installcron + dh_installexamples + dh_installchangelogs + #dh_installdebconf + dh_installinit -pgosa-si-server --init-script=gosa-si + dh_link + dh_strip + dh_compress + dh_fixperms + dh_perl + dh_installdeb + dh_shlibdeps + + dh_gencontrol + dh_md5sums + dh_builddeb + +source diff: + @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false + +binary: binary-indep +.PHONY: build install clean binary-indep binary + +binary-arch: + diff --git a/gosa-si/gosa-si-bus b/gosa-si/gosa-si-bus new file mode 100755 index 000000000..a5d50f1d2 --- /dev/null +++ b/gosa-si/gosa-si-bus @@ -0,0 +1,1362 @@ +#!/usr/bin/perl +#=============================================================================== +# +# FILE: gosa-server +# +# USAGE: ./gosa-server +# +# DESCRIPTION: +# +# OPTIONS: --- +# REQUIREMENTS: --- +# BUGS: --- +# NOTES: +# AUTHOR: (Andreas Rettenberger), +# COMPANY: +# VERSION: 1.0 +# CREATED: 12.09.2007 08:54:41 CEST +# REVISION: --- +#=============================================================================== + +use strict; +use warnings; +use Getopt::Long; +use Config::IniFiles; +use POSIX; +use Time::HiRes qw( gettimeofday ); + +use IO::Socket::INET; +use Crypt::Rijndael; +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_passwd, $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 ; + +%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/bus_known_server.db"] + }, +"bus" => + {"bus_activ" => [\$bus_activ, "on"], + "bus_passwd" => [\$bus_passwd, ""], + "bus_ip" => [\$bus_ip, "0.0.0.0"], + "bus_port" => [\$bus_port, "20080"], + } + ); + +#=== FUNCTION ================================================================ +# NAME: read_configfile +# PARAMETERS: cfg_file - string - +# RETURNS: nothing +# DESCRIPTION: read cfg_file and set variables +#=============================================================================== +sub read_configfile { + my $cfg; + if( defined( $cfg_file) && ( length($cfg_file) > 0 )) { + if( -r $cfg_file ) { + $cfg = Config::IniFiles->new( -file => $cfg_file ); + } else { + print STDERR "Couldn't read config file!"; + } + } else { + $cfg = Config::IniFiles->new() ; + } + foreach my $section (keys %cfg_defaults) { + foreach my $param (keys %{$cfg_defaults{ $section }}) { + my $pinfo = $cfg_defaults{ $section }{ $param }; + ${@$pinfo[ 0 ]} = $cfg->val( $section, $param, @$pinfo[ 1 ] ); + } + } +} + +#=== 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 $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 +# PARAMETERS: nothing +# RETURNS: nothing +# DESCRIPTION: handels pid processing +#=============================================================================== +sub check_pid { + $pid = -1; + # Check, if we are already running + if( open(LOCK_FILE, "<$pid_file") ) { + $pid = ; + if( defined $pid ) { + chomp( $pid ); + if( -f "/proc/$pid/stat" ) { + my($stat) = `cat /proc/$pid/stat` =~ m/$pid \((.+)\).*/; + if( $0 eq $stat ) { + close( LOCK_FILE ); + exit -1; + } + } + } + close( LOCK_FILE ); + unlink( $pid_file ); + } + + # create a syslog msg if it is not to possible to open PID file + if (not sysopen(LOCK_FILE, $pid_file, O_WRONLY|O_CREAT|O_EXCL, 0644)) { + my($msg) = "Couldn't obtain lockfile '$pid_file' "; + if (open(LOCK_FILE, '<', $pid_file) + && ($pid = )) + { + chomp($pid); + $msg .= "(PID $pid)\n"; + } else { + $msg .= "(unable to read PID)\n"; + } + if( ! ($foreground) ) { + openlog( $0, "cons,pid", "daemon" ); + syslog( "warning", $msg ); + closelog(); + } + else { + print( STDERR " $msg " ); + } + exit( -1 ); + } +} + + +#=== FUNCTION ================================================================ +# NAME: usage +# PARAMETERS: nothing +# RETURNS: nothing +# DESCRIPTION: print out usage text to STDERR +#=============================================================================== +sub usage { + print STDERR << "EOF" ; +usage: $0 [-hvf] [-c config] + + -h : this (help) message + -c : config file + -f : foreground, process will not be forked to background + -v : be verbose (multiple to increase verbosity) +EOF + print "\n" ; +} + + +#=== FUNCTION ================================================================ +# NAME: sig_int_handler +# PARAMETERS: signal - string - signal arose from system +# RETURNS: noting +# DESCRIPTION: handels tasks to be done befor signal becomes active +#=============================================================================== +sub sig_int_handler { + my ($signal) = @_; + if($bus){ + close($bus); + print "$bus closed\n"; + } + print "$signal\n"; + exit(1); +} +$SIG{INT} = \&sig_int_handler; + +#=== FUNCTION ================================================================ +# NAME: get_interface_for_ip +# PARAMETERS: ip address (i.e. 192.168.0.1) +# RETURNS: array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else +# 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; + } + } + } + } + return $result; +} + +#=== FUNCTION ================================================================ +# NAME: get_interfaces +# PARAMETERS: none +# RETURNS: (list of interfaces) +# DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. +#=============================================================================== +sub get_interfaces { + my @result; + my $PROC_NET_DEV= ('/proc/net/dev'); + + open(PROC_NET_DEV, "<$PROC_NET_DEV") + or die "Could not open $PROC_NET_DEV"; + + my @ifs = ; + + close(PROC_NET_DEV); + + # 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; + } + + return @result; +} + +#=== FUNCTION ================================================================ +# NAME: get_mac +# PARAMETERS: interface name (i.e. eth0) +# RETURNS: (mac address) +# DESCRIPTION: Uses ioctl to get mac address directly from system. +#=============================================================================== +sub get_mac { + my $ifreq= shift; + my $result; + if ($ifreq && length($ifreq) > 0) { + if($ifreq eq "all") { + $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; + } + + socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip') + or die "socket: $!"; + + 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; + } + } + } + } + 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 +#=============================================================================== +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; +} + + +#=== FUNCTION ================================================================ +# NAME: get_processing_child +# 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 +#=============================================================================== +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; + } + } + + 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); + + # 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; + } + } +} + + +#=== FUNCTION ================================================================ +# NAME: process_incoming_msg +# PARAMETERS: crypted_msg - string - incoming crypted message +# RETURNS: nothing +# DESCRIPTION: handels the proceeded distribution to the appropriated functions +#=============================================================================== +sub process_incoming_msg { + my ($crypted_msg) = @_; + if(not defined $crypted_msg) { + daemon_log("function 'process_incoming_msg': got no msg", 7); + 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); + + 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_passwd; + daemon_log("process_incoming_msg: host_name: $host_name", 7); + daemon_log("process_incoming_msg: host_key: $host_key", 7); + eval{ + my $key_cipher = &create_ciphering($host_key); + $msg = &decrypt_msg($crypted_msg, $key_cipher); + $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; + } + + # check wether incoming msg is from a bus_known_server + if( not defined $msg ) { + my $query_res = $bus_known_server_db->select_dbentry( {table=>'bus_known_server'} ); + 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{ + my $key_cipher = &create_ciphering($host_key); + $msg = &decrypt_msg($crypted_msg, $key_cipher); + $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; + } + } + } + + 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]; + + daemon_log("header from msg: $header", 1); + daemon_log("msg to process:", 5); + daemon_log($msg, 5); + + my @targets = @{$msg_hash->{target}}; + my $len_targets = @targets; + + if ($len_targets == 0){ + daemon_log("ERROR: no target specified for msg $header", 1); + + } elsif ($len_targets == 1){ + # we have only one target symbol + my $target = $targets[0]; + daemon_log("msg is for: $target", 7); + + 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 $query_res = $bus_known_server_db->select_dbentry( {table=>'known_server'} ); + 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; + } + + } else { + # a list of targets is specified + my $target_address; + foreach $target_address (@targets) { + + my $query_res = $bus_known_server_db->select_dbentry( {table=>'known_server', hostname=>$target_address} ); + if( 1 == keys %{$query_res} ) { + $host_key = $query_res->{1}->{hostkey}; + &send_msg_hash2address($msg_hash, $target_address, $host_key); + next; + + } else { + $query_res = $bus_known_server_db->select_dbentry( {table=>'known_server'} ); + 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; + } + } + } + } + } + + return; +} + + +#=== FUNCTION ================================================================ +# NAME: get_content_of_known_daemons +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +#sub get_content_of_known_daemons { +# my ($host, $content) = @_; +# 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))] + } + return $new_passwd; +} + + +#=== FUNCTION ================================================================ +# NAME: create_ciphering +# PARAMETERS: passwd - string - used to create ciphering +# RETURNS: cipher - object +# DESCRIPTION: creates a Crypt::Rijndael::MODE_CBC object with passwd as key +#=============================================================================== +#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; +#} + + +#=== FUNCTION ================================================================ +# NAME: encrypt_msg +# PARAMETERS: msg - string - message to encrypt +# my_cipher - ref - reference to a Crypt::Rijndael object +# RETURNS: crypted_msg - string - crypted message +# DESCRIPTION: crypts the incoming message with the Crypt::Rijndael module +#=============================================================================== +#sub encrypt_msg { +# my ($msg, $my_cipher) = @_; +# if(not defined $my_cipher) { print "no cipher object\n"; } +# $msg = "\0"x(16-length($msg)%16).$msg; +# my $crypted_msg = $my_cipher->encrypt($msg); +# chomp($crypted_msg = &encode_base64($crypted_msg)); +# return $crypted_msg; +#} + + +#=== FUNCTION ================================================================ +# NAME: decrypt_msg +# PARAMETERS: crypted_msg - string - message to decrypt +# my_cipher - ref - reference to a Crypt::Rijndael object +# RETURNS: msg - string - decrypted message +# DESCRIPTION: decrypts the incoming message with the Crypt::Rijndael module +#=============================================================================== +#sub decrypt_msg { +# my ($crypted_msg, $my_cipher) = @_ ; +# $crypted_msg = &decode_base64($crypted_msg); +# my $msg = $my_cipher->decrypt($crypted_msg); +# $msg =~ s/^\0*//g; +# return $msg; +#} + + +#=== FUNCTION ================================================================ +# NAME: create_xml_hash +# PARAMETERS: header - string - message header (required) +# source - string - where the message come from (required) +# target - string - where the message should go to (required) +# [header_value] - string - something usefull (optional) +# RETURNS: hash - hash - nomen est omen +# DESCRIPTION: creates a key-value hash, all values are stored in a array +#=============================================================================== +#sub create_xml_hash { +# my ($header, $source, $target, $header_value) = @_ ; +# +# if (not defined $header || not defined $source || not defined $target) { +# daemon_log("ERROR: create_xml_hash function is invoked with uncompleted parameters", 7); +# } +# +# my $hash = { +# header => [$header], +# source => [$source], +# target => [$target], +# $header => [$header_value], +# }; +# #daemon_log("create_xml_hash:", 7), +# #chomp(my $tmp = Dumper $hash); +# #daemon_log("\t$tmp\n", 7); +# return $hash +#} + + +#=== FUNCTION ================================================================ +# NAME: create_xml_string +# PARAMETERS: xml_hash - hash - hash from function create_xml_hash +# RETURNS: xml_string - string - xml string representation of the hash +# DESCRIPTION: transform the hash to a string using XML::Simple module +#=============================================================================== +#sub create_xml_string { +# my ($xml_hash) = @_ ; +# my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml'); +# #$xml_string =~ s/[\n]+//g; +# return $xml_string; +#} + + +#=== FUNCTION ================================================================ +# NAME: add_content2xml_hash +# PARAMETERS: xml_ref - ref - reference to a hash from function create_xml_hash +# element - string - key for the hash +# content - string - value for the hash +# RETURNS: nothing +# DESCRIPTION: add key-value pair to xml_ref, if key alread exists, then append value to list +#=============================================================================== +#sub add_content2xml_hash { +# my ($xml_ref, $element, $content) = @_; +# if(not exists $$xml_ref{$element} ) { +# $$xml_ref{$element} = []; +# } +# my $tmp = $$xml_ref{$element}; +# push(@$tmp, $content); +# return; +#} + + +#=== FUNCTION ================================================================ +# NAME: get_content_from_xml_hash +# PARAMETERS: xml_ref - ref - reference of the xml hash +# element - string - key of the value you want +# RETURNS: value - string - if key is either header, target or source +# value - list - for all other keys in xml hash +# DESCRIPTION: +#=============================================================================== +#sub get_content_from_xml_hash { +# my ($xml_ref, $element) = @_; +# my $result = $xml_ref->{$element}; +# if( $element eq "header" || $element eq "target" || $element eq "source") { +# return @$result[0]; +# } +# return @$result; +#} + + +#=== 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, +# Reuse => 1, +# Timeout => 5, +# ); +# if(not defined $socket) { +# return; +# } +# return $socket; +#} + + +#=== 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: send_msg_hash2address +# PARAMETERS: msg_hash - hash - xml_hash created with function create_xml_hash +# PeerAddr string - socket address to send msg +# PeerPort string - socket port, if not included in socket address +# RETURNS: nothing +# DESCRIPTION: ???? +#=============================================================================== +#sub send_msg_hash2address { +# my ($msg_hash, $address) = @_ ; +# +# # fetch header for logging +# my $header = &get_content_from_xml_hash($msg_hash, "header"); +# +# # generate xml string +# my $msg_xml = &create_xml_string($msg_hash); +# +# # fetch the appropriated passwd from hash +# my $passwd = $known_daemons->{$address}->{passwd}; +# +# # create a ciphering object +# my $act_cipher = &create_ciphering($passwd); +# +# # encrypt xml msg +# my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher); +# +# # open socket +# my $socket = &open_socket($address); +# if(not defined $socket){ +# daemon_log("ERROR: cannot send '$header'-msg to $address , server not reachable", 1); +# return; +# } +# +# # send xml msg +# print $socket $crypted_msg."\n"; +# +# close $socket; +# daemon_log("send '$header'-msg to $address", 5); +# daemon_log("crypted_msg:\n\t$crypted_msg", 7); +# return; +#} + + +#=== FUNCTION ================================================================ +# NAME: send_msg_hash2all +# PARAMETERS: msg_hash - hash - xml_hash created with function create_xml_hash +# RETURNS: nothing +# DESCRIPTION: send msg_hash to all registered daemons +#=============================================================================== +#sub send_msg_hash2all { +# my ($msg_hash) = @_; +# +# # fetch header for logging +# my $header = &get_content_from_xml_hash($msg_hash, "header"); +# +# # generate xml string +# my $msg_xml = &create_xml_string($msg_hash); +# +# # fetch a list of all target addresses +# my @targets = keys(%$known_daemons); +# +# # itterates through the list an send each the msg +# foreach my $target (@targets) { +# if($target eq $bus_address) {next}; # do not send msg to bus +# +# # fetch the appropriated passwd +# my $passwd = $known_daemons->{$target}->{passwd}; +# +# # create ciphering object +# my $act_cipher = &create_ciphering($passwd); +# +# # encrypt xml msg +# my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher); +# +# # open socket +# my $socket = &open_socket($target); +# if(not defined $socket){ +# daemon_log("ERROR: cannot open socket to $target , server not reachable", 1); +# &update_known_daemons_entry(hostname=>$target, status=>"down"); +# next; +# } +# +# # send xml msg +# print $socket $crypted_msg."\n"; +# +# close $socket; +# daemon_log("send '$header'-msg to $target", 5); +# daemon_log("crypted_msg:\n\t$crypted_msg", 7); +# } +# return; +#} + + +#=== 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 $new_key = &create_passwd(); + + # create bus_known_server entry + my $add_hash = { + table=>"bus_known_server", + primkey=>"hostname", + hostname=>$source, + status=>"registered", + hostkey=>$bus_passwd, + clients=>"", + }; + $bus_known_server_db->add_dbentry($add_hash); + + # create outgoing msg + my $out_hash = &create_xml_hash("new_passwd", $bus_address, $source, $new_key); + &send_msg_hash2address($out_hash, $source, $bus_passwd); + + # change hostkey, reason + my $update_hash = { table=>'bus_known_server' }; + $update_hash->{where} = [ { hostname=>[$source] } ]; + $update_hash->{update} = [ { hostkey=>[$new_key] } ]; + $bus_known_server_db->update_dbentry($update_hash); + + 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 $update_hash = { table=>'bus_known_server' }; + $update_hash->{where} = [ { hostname=>[$source] } ]; + $update_hash->{update} = [ { status=>['key_confirmed'] } ]; + $bus_known_server_db->update_dbentry($update_hash); + + return; +} + + +#=== 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 $update_hash = { table=>'bus_known_server', + where=> [ { hostname=>[$source] } ], + update=> [ { status=>$header } ], + }; + $bus_known_server_db->update_dbentry($update_hash); + + my $out_hash = &create_xml_hash("got_ping", $bus_address, $source); + + my $res = $bus_known_server_db->select_dbentry( { table=>'bus_known_server', hostname=>$source } ); + my $hostkey = $res->{1}->{hostkey}; + &send_msg_hash2address($out_hash, $source, $hostkey); + + return; +} + + +#=== FUNCTION ================================================================ +# NAME: make ping +# PARAMETERS: address - string - address which should be pinged +# RETURNS: nothing +# DESCRIPTION: send ping message to address +#=============================================================================== +#sub make_ping { +# my ($address) = @_; +# daemon_log("ping:$address\n", 1); +# my $out_hash = &create_xml_hash("ping", "$bus_ip:$bus_port", $address); +# &send_msg_hash2address($out_hash, $address); +# return; +#} + + +#=== 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 $update_hash = { table=>'bus_known_server', + where=> [ { hostname=>[$source] } ], + update=> [ { status=>'got_ping' } ], + }; + $bus_known_server_db->update_dbentry($update_hash); + + 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 $res = $bus_known_server_db->select_dbentry( { table=>'bus_known_server', hostname=>$source } ); + my $clients = $res->{1}->{clients}; + + # if host has alread more clients, than just append + if( length($clients) != 0 ) { + $clients .= ",$new_client"; + } else { + $clients = $new_client; + } + + my $update_hash = { table=>'bus_known_server', + where=>[ {hostname=>[$source] } ], + update=>[ {clients=>[$clients] } ], + }; + + $bus_known_server_db->update_dbentry( $update_hash ); + return; +} + + +#=== FUNCTION ================================================================ +# NAME: delete_client +# PARAMETERS: msg_hash - hash - hash from function create_xml_hash +# RETURNS: nothing +# DESCRIPTION: process this incoming message +#=============================================================================== +#sub delete_client { +# my ($msg_hash) = @_ ; +# my $source = &get_content_from_xml_hash($msg_hash, "source"); +# my $header = &get_content_from_xml_hash($msg_hash, "header"); +# my $del_client = (&get_content_from_xml_hash($msg_hash, $header))[0]; +# +# if (not exists $known_daemons->{$source}->{$del_client}) { +# daemon_log +# } +# delete $known_daemons->{$source}->{$del_client}; +# +# return; +#} + + +#=== FUNCTION ================================================================ +# NAME: print_known_daemons_hash +# PARAMETERS: nothing +# RETURNS: nothing +# DESCRIPTION: nome est omen +#=============================================================================== +#sub print_known_daemons_hash { +# my ($tmp) = @_; +# print "####################################\n"; +# print "# status of known_daemons\n"; +# my $hosts; +# my $host_hash; +# $shmkh->shlock(LOCK_EX); +# my @hosts = keys %$known_daemons; +# foreach my $host (@hosts) { +# my $status = $known_daemons->{$host}->{status} ; +# my $passwd = $known_daemons->{$host}->{passwd}; +# my $timestamp = $known_daemons->{$host}->{timestamp}; +# my @clients = keys %{$known_daemons->{$host}->{clients}}; +# my $client_string = join(", ", @clients); +# print "$host\n"; +# print "\tstatus: $status\n"; +# print "\tpasswd: $passwd\n"; +# print "\ttimestamp: $timestamp\n"; +# print "\tclients: $client_string\n"; +# +# } +# $shmkh->shunlock(LOCK_EX); +# print "####################################\n\n"; +# return; +#} + + +#=== FUNCTION ================================================================ +# NAME: create_known_daemons_entry +# PARAMETERS: hostname - string - ip address and port of host +# RETURNS: nothing +# DESCRIPTION: nome est omen +#=============================================================================== +#sub create_known_daemons_entry { +# my ($hostname) = @_; +# $shmkh->shlock(LOCK_EX); +# $known_daemons->{$hostname} = {}; +# $known_daemons->{$hostname}->{status} = "none"; +# $known_daemons->{$hostname}->{passwd} = "none"; +# $known_daemons->{$hostname}->{timestamp} = "none"; +# $known_daemons->{$hostname}->{clients} = {}; +# $shmkh->shunlock(LOCK_EX); +# return; +#} + + +#=== FUNCTION ================================================================ +# NAME: update_known_daemons_entry +# PARAMETERS: hostname - string - ip address and port of host (required) +# status - string - (optional) +# passwd - string - (optional) +# client - string - ip address and port of client (optional) +# RETURNS: nothing +# DESCRIPTION: nome est omen and updates each time the timestamp of hostname +#=============================================================================== +#sub update_known_daemons_entry { +# my $arg = { +# hostname => undef, status => undef, passwd => undef, +# client => undef, +# @_ }; +# my $hostname = $arg->{hostname}; +# my $status = $arg->{status}; +# my $passwd = $arg->{passwd}; +# my $client = $arg->{client}; +# +# if (not defined $hostname) { +# daemon_log("ERROR: function add_content2known_daemons is not invoked with requiered parameter 'hostname'", 1); +# return; +# } +# +# 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; +# $month+=1; +# $month = $month < 10 ? $month = "0".$month : $month; +# $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; +# $year+=1900; +# my $t = "$year$month$monthday$hours$minutes$seconds"; +# +# $shmkh->shlock(LOCK_EX); +# if (defined $status) { +# $known_daemons->{$hostname}->{status} = $status; +# } +# if (defined $passwd) { +# $known_daemons->{$hostname}->{passwd} = $passwd; +# } +# if (defined $client) { +# $known_daemons->{$hostname}->{clients}->{$client} = ""; +# } +# $known_daemons->{$hostname}->{timestamp} = $t; +# $shmkh->shunlock(LOCK_EX); +# return; +#} + + +#==== MAIN = main ============================================================== + +# parse commandline options +Getopt::Long::Configure( "bundling" ); +GetOptions("h|help" => \&usage, + "c|config=s" => \$cfg_file, + "f|foreground" => \$foreground, + "v|verbose+" => \$verbose, + ); + +# read and set config parameters +&check_cmdline_param ; +&read_configfile; +&check_pid; + +$SIG{CHLD} = 'IGNORE'; + +# restart daemon log file +if(-e $log_file ) { unlink $log_file } +daemon_log(" ", 1); +daemon_log("$0 started!", 1); + +# forward error messages to logfile +if( ! $foreground ) { + open(STDERR, '>>', $log_file); + open(STDOUT, '>>', $log_file); +} + +# 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 { $pid = $$; } + +# Do something useful - put our PID into the pid_file +if( 0 != $pid ) { + open( LOCK_FILE, ">$pid_file" ); + print LOCK_FILE "$pid\n"; + close( LOCK_FILE ); + 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"; + +# setup xml parser +$xml = new XML::Simple(); + +# create cipher object +$bus_cipher = &create_ciphering($bus_passwd); +$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_passwd); + + +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); + } + +} + + diff --git a/gosa-si/gosa-si-client b/gosa-si/gosa-si-client new file mode 100755 index 000000000..69a5f7ffd --- /dev/null +++ b/gosa-si/gosa-si-client @@ -0,0 +1,1363 @@ +#!/usr/bin/perl +#=============================================================================== +# +# FILE: gosa-server +# +# USAGE: gosa-si-client +# +# DESCRIPTION: +# +# OPTIONS: --- +# REQUIREMENTS: libnetaddr-ip-perl +# BUGS: --- +# NOTES: +# AUTHOR: (Andreas Rettenberger), +# COMPANY: +# VERSION: 1.0 +# CREATED: 12.09.2007 08:54:41 CEST +# REVISION: --- +#=============================================================================== + +use strict; +use warnings; +use Getopt::Long; +use Config::IniFiles; +use POSIX; +use Time::HiRes qw( gettimeofday ); + +use Fcntl; +use IO::Socket::INET; +use Crypt::Rijndael; +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 File::Spec; +use Cwd; +use NetAddr::IP; +use GOSA::GosaSupportDaemon; + + +my ($cfg_file, %cfg_defaults, $foreground, $verbose, $pid_file, $procid, $pid, $log_file); +my ($server_address, $server_ip, $server_port, $server_domain, $server_passwd, $server_cipher, $server_timeout); +my ($client_address, $client_ip, $client_port, $client_mac_address, $network_interface, $ldap_config, $pam_config, $nss_config); +my ($input_socket, $rbits, $wbits, $ebits, $xml, $known_hosts, $ldap_enabled); +my (@events); + +# default variables +my $event_dir = "/usr/lib/gosa-si/client/events"; +$known_hosts = {}; +$foreground = 0 ; +%cfg_defaults = +("general" => + {"log_file" => [\$log_file, "/var/run/".$0.".log"], + "pid_file" => [\$pid_file, "/var/run/".$0.".pid"], + }, +"client" => + {"client_port" => [\$client_port, "20083"], + "client_ip" => [\$client_ip, "0.0.0.0"], + "ldap" => [\$ldap_enabled, 1], + "ldap_config" => [\$ldap_config, "/etc/ldap/ldap.conf"], + "pam_config" => [\$pam_config, "/etc/pam_ldap.conf"], + "nss_config" => [\$nss_config, "/etc/libnss_ldap.conf"], + }, +"server" => + {"server_ip" => [\$server_ip, ""], + "server_port" => [\$server_port, "20081"], + "server_passwd" => [\$server_passwd, ""], + "server_timeout" => [\$server_timeout, 10], + "server_domain" => [\$server_domain, ""], + }, + ); + + +#=== FUNCTION ================================================================ +# NAME: read_configfile +# PARAMETERS: cfg_file - string - +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub read_configfile { + my $cfg; + if( defined( $cfg_file) && ( length($cfg_file) > 0 )) { + if( -r $cfg_file ) { + $cfg = Config::IniFiles->new( -file => $cfg_file ); + } else { + print STDERR "Couldn't read config file!"; + } + } else { + $cfg = Config::IniFiles->new() ; + } + foreach my $section (keys %cfg_defaults) { + foreach my $param (keys %{$cfg_defaults{ $section }}) { + my $pinfo = $cfg_defaults{ $section }{ $param }; + ${@$pinfo[ 0 ]} = $cfg->val( $section, $param, @$pinfo[ 1 ] ); + } + } +} + + +#=== FUNCTION ================================================================ +# NAME: logging +# PARAMETERS: level - string - default 'info' +# msg - string - +# facility - string - default 'LOG_DAEMON' +# RETURNS: +# DESCRIPTION: +#=============================================================================== +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){ + print LOG_HANDLE $msg."\n"; + if(defined $foreground) { print $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: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub check_cmdline_param () { + my $err_config; + my $err_counter = 0; + if( not defined( $cfg_file)) { + #$err_config = "please specify a config file"; + #$err_counter += 1; + my $cwd = getcwd; + my $name = "/etc/gosa-si/client.conf"; + $cfg_file = File::Spec->catfile( $cwd, $name ); + print STDERR "no conf file specified\n try to use default: $cfg_file\n"; + } + if( $err_counter > 0 ) { + &usage( "", 1 ); + if( defined( $err_config)) { print STDERR "$err_config\n"} + print STDERR "\n"; + exit( -1 ); + } +} + + +#=== FUNCTION ================================================================ +# NAME: check_pid +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub check_pid { + $pid = -1; + # Check, if we are already running + if( open(LOCK_FILE, "<$pid_file") ) { + $pid = ; + if( defined $pid ) { + chomp( $pid ); + if( -f "/proc/$pid/stat" ) { + my($stat) = `cat /proc/$pid/stat` =~ m/$pid \((.+)\).*/; + if( $0 eq $stat ) { + close( LOCK_FILE ); + exit -1; + } + } + } + close( LOCK_FILE ); + unlink( $pid_file ); + } + + # create a syslog msg if it is not to possible to open PID file + if (not sysopen(LOCK_FILE, $pid_file, O_WRONLY|O_CREAT|O_EXCL, 0644)) { + my($msg) = "Couldn't obtain lockfile '$pid_file' "; + if (open(LOCK_FILE, '<', $pid_file) + && ($pid = )) + { + chomp($pid); + $msg .= "(PID $pid)\n"; + } else { + $msg .= "(unable to read PID)\n"; + } + if( ! ($foreground) ) { + openlog( $0, "cons,pid", "daemon" ); + syslog( "warning", $msg ); + closelog(); + } + else { + print( STDERR " $msg " ); + } + exit( -1 ); + } +} + +#=== FUNCTION ================================================================ +# NAME: get_interface_for_ip +# PARAMETERS: ip address (i.e. 192.168.0.1) +# RETURNS: array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else +# 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; + last; + } + } + } + } + return $result; +} + +#=== FUNCTION ================================================================ +# NAME: get_interfaces +# PARAMETERS: none +# RETURNS: (list of interfaces) +# DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. +#=============================================================================== +sub get_interfaces { + my @result; + my $PROC_NET_DEV= ('/proc/net/dev'); + + open(PROC_NET_DEV, "<$PROC_NET_DEV") + or die "Could not open $PROC_NET_DEV"; + + my @ifs = ; + + close(PROC_NET_DEV); + + # 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; + } + + return @result; +} + +#=== FUNCTION ================================================================ +# NAME: get_mac +# PARAMETERS: interface name (i.e. eth0) +# RETURNS: (mac address) +# DESCRIPTION: Uses ioctl to get mac address directly from system. +#=============================================================================== +sub get_mac { + my $ifreq= shift; + my $result; + if ($ifreq && length($ifreq) > 0) { + if($ifreq eq "all") { + if(defined($server_ip)) { + $result = &get_local_mac_for_remote_ip($server_ip); + } 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 ($client_mac_address and length($client_mac_address) > 0) { + $result= $client_mac_address; + } + + socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip') + or die "socket: $!"; + + 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; + } + } + } + } + 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: 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 get_local_mac_for_remote_ip { + my $ifreq= shift; + my $result= "00:00:00:00:00:00"; + 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; + } + } + + + return $result; +} + +#=== FUNCTION ================================================================ +# NAME: usage +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub usage { + my( $text, $help ) = @_; + $text = undef if( "h" eq $text ); + (defined $text) && print STDERR "\n$text\n"; + if( (defined $help && $help) || (!defined $help && !defined $text) ) { + print STDERR << "EOF" ; +usage: $0 [-hvf] [-c config] + + -h : this (help) message + -c : config file + -f : foreground, process will not be forked to background + -v : be verbose (multiple to increase verbosity) +EOF + } + print "\n" ; +} + +#=== FUNCTION ================================================================ +# NAME: get_server_addresses +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub get_server_addresses { + my $domain= shift; + my @result; + my $dig_cmd= 'dig +nocomments srv _gosad._tcp.'.$domain; + + my $output= `$dig_cmd 2>&1`; + open (PIPE, "$dig_cmd 2>&1 |"); + while() { + chomp $_; + # If it's not a comment + if($_ =~ m/^[^;]/) { + my @matches= split /\s+/; + + # Push hostname with port + if($matches[3] eq 'SRV') { + push @result, $matches[7].':'.$matches[6]; + } elsif ($matches[3] eq 'A') { + my $i=0; + + # Substitute the hostname with the ip address of the matching A record + foreach my $host (@result) { + if ((split /\:/, $host)[0] eq $matches[0]) { + $result[$i]= $matches[4].':'.(split /\:/, $host)[1]; + } + $i++; + } + } + } + } + close(PIPE); + return @result; +} + + +#=== FUNCTION ================================================================ +# NAME: register_at_server +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub register_at_server { + my ($tmp) = @_; + + # create new passwd and ciphering object for client-server communication + my $new_server_passwd = &create_passwd(); + my $new_server_cipher; + + # detect all client accepted events + opendir(DIR, $event_dir) + or daemon_log("cannot find directory $event_dir!\ngosa-si-client starts without any accepting events!", 1); + my $file_name; + my @events_list = (); + while(defined($file_name = readdir(DIR))){ + if ($file_name eq "." || $file_name eq "..") { + next; + } + push(@events_list, $file_name); + } + my $events = join(",", @events_list); + daemon_log("found events: $events", 1); + + # fill in all possible servers + my @servers; + if (defined $server_domain) { + my @tmp_servers = &get_server_addresses($server_domain); + foreach my $server (@tmp_servers) { unshift(@servers, $server); } + } + # add server address from config file at first position of server list + if (defined $server_address) { + unshift(@servers, $server_address); + } + daemon_log("found servers in configuration file and via DNS:", 5); + foreach my $server (@servers) { + daemon_log("\t$server", 5); + } + + my ($rout, $wout, $reg_server); + foreach my $server (@servers) { + + # create msg hash + my $register_hash = &create_xml_hash("here_i_am", $client_address, $server); + &add_content2xml_hash($register_hash, "new_passwd", $new_server_passwd); + &add_content2xml_hash($register_hash, "mac_address", $client_mac_address); + &add_content2xml_hash($register_hash, "events", $events); + + my $tmp = print Dumper $register_hash; + + # send xml hash to server with general server passwd + my $answer = &send_msg_hash2address($register_hash, $server, $server_passwd); + + if ($answer != 0) { next; } + + # waiting for response + daemon_log("waiting for response...\n", 5); + my $nf = select($rout=$rbits, $wout=$wbits, undef, $server_timeout); + + # something is coming in + if(vec $rout, fileno $input_socket, 1) { + my $crypted_msg; + my $client = $input_socket->accept(); + my $other_end = getpeername($client); + if(not defined $other_end) { + daemon_log("client cannot be identified: $!\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){ + chomp($in_msg); + $crypted_msg = $in_msg; + } else { + daemon_log("cannot read from $actual_ip\n", 5); + } + } + close($client); + + # validate acknowledge msg from server + $new_server_cipher = &create_ciphering($new_server_passwd); + my $msg_hash; + eval { + my $decrypted_msg = &decrypt_msg($crypted_msg, $new_server_cipher); + daemon_log("decrypted register msg: $decrypted_msg", 5); + $msg_hash = $xml->XMLin($decrypted_msg, ForceArray=>1); + }; + if($@) { + daemon_log("ERROR: do not understand the incoming message:" , 5); + daemon_log("$@", 7); + } else { + my $header = @{$msg_hash->{header}}[0]; + if($header eq "registered") { + $reg_server = $server; + last; + } elsif($header eq "denied") { + my $reason = (&get_content_from_xml_hash($msg_hash, "denied"))[0]; + daemon_log("registration at $server denied: $reason", 1); + } else { + daemon_log("cannot register at $server", 1); + } + } + } + # if no answer arrive, try next server in list + + } + + if(defined $reg_server) { + daemon_log("registered at $reg_server", 1); + } else { + daemon_log("cannot register at any server", 1); + daemon_log("exiting!!!", 1); + exit(1); + } + + # update the global available variables + $server_address = $reg_server; + $server_passwd = $new_server_passwd; + $server_cipher = $new_server_cipher; + return; +} + + +#=== FUNCTION ================================================================ +# NAME: create_xml_hash +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +#sub create_xml_hash { +# my ($header, $source, $target, $header_value) = @_; +# my $hash = { +# header => [$header], +# source => [$source], +# target => [$target], +# $header => [$header_value], +# }; +# daemon_log("create_xml_hash:", 7), +# chomp(my $tmp = Dumper $hash); +# daemon_log("\t$tmp\n", 7); +# return $hash +#} + + +#=== FUNCTION ================================================================ +# NAME: create_xml_string +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +#sub create_xml_string { +# my ($xml_hash) = @_ ; +# my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml'); +# $xml_string =~ s/[\n]+//g; +# daemon_log("create_xml_string:\n\t$xml_string\n", 7); +# return $xml_string; +#} + + +#=== FUNCTION ================================================================ +# NAME: add_content2xml_hash +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +#sub add_content2xml_hash { +# my ($xml_ref, $element, $content) = @_; +# if(not exists $$xml_ref{$element} ) { +# $$xml_ref{$element} = []; +# } +# my $tmp = $$xml_ref{$element}; +# push(@$tmp, $content); +# return; +#} + + +#=== FUNCTION ================================================================ +# NAME: get_content_from_xml_hash +# PARAMETERS: ref : reference to the xml hash +# string: key of the value you want +# RETURNS: STRING AND ARRAY +# DESCRIPTION: if key of the hash is either 'header', 'target' or 'source' the +# function returns a string cause it is expected that these keys +# do just have one value, all other keys returns an array!!! +#=============================================================================== +#sub get_content_from_xml_hash { +# my ($xml_ref, $element) = @_; +# my $result = $xml_ref->{$element}; +# if( $element eq "header" || $element eq "target" || $element eq "source") { +# return @$result[0]; +# } +# return @$result; +#} + +# my ($xml_ref, $element) = @_; +# if (exists $xml_ref->{$element}) { +# my $result = $xml_ref->{$element}; +# if( $element eq "header" || $element eq "target" || $element eq "source") { +# return @$result[0]; +# } else { +# return @$result; +# } +# +# } else { +# my $result = (); +# return @$result; +# } +#} + + +#=== FUNCTION ================================================================ +# NAME: encrypt_msg +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +#sub encrypt_msg { +# my ($msg, $my_cipher) = @_; +# if(not defined $my_cipher) { print "no cipher object\n"; } +# $msg = "\0"x(16-length($msg)%16).$msg; +# my $crypted_msg = $my_cipher->encrypt($msg); +# chomp($crypted_msg = &encode_base64($crypted_msg)); +# return $crypted_msg; +#} + + +#=== FUNCTION ================================================================ +# NAME: decrypt_msg +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +#sub decrypt_msg { +# my ($crypted_msg, $my_cipher) = @_ ; +# $crypted_msg = &decode_base64($crypted_msg); +# my $msg = $my_cipher->decrypt($crypted_msg); +# $msg =~ s/\0*//g; +# return $msg; +#} + + +#=== FUNCTION ================================================================ +# NAME: create_ciphering +# PARAMETERS: +# RETURNS: cipher object +# DESCRIPTION: +#=============================================================================== +#sub create_ciphering { +# my ($passwd) = @_; +# $passwd = substr(md5_hex("$passwd") x 32, 0, 32); +# my $iv = substr(md5_hex('GONICUS GmbH'),0, 16); +# +# #daemon_log("iv: $iv", 7); +# #daemon_log("key: $passwd", 7); +# my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC()); +# $my_cipher->set_iv($iv); +# return $my_cipher; +#} + + +#=== FUNCTION ================================================================ +# NAME: create_passwd +# PARAMETERS: +# RETURNS: cipher object +# DESCRIPTION: +#=============================================================================== +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; +} + + +#=== FUNCTION ================================================================ +# NAME: send_msg_hash2address +# PARAMETERS: msg string - xml message +# PeerAddr string - socket address to send msg +# PeerPort string - socket port, if not included in socket address +# RETURNS: nothing +# DESCRIPTION: ???? +#=============================================================================== +#sub send_msg_hash2address { +# my ($msg_hash, $address, $passwd) = @_ ; +# +# # fetch header for logging +# my $header = @{$msg_hash->{header}}[0]; +# +# # generiere xml string +# my $msg_xml = &create_xml_string($msg_hash); +# +# # hole das entsprechende passwd aus dem hash +# if(not defined $passwd) { +# if(exists $known_hosts->{$address}) { +# $passwd = $known_hosts->{$address}->{passwd}; +# } elsif ($address eq $server_address) { +# $passwd = $server_passwd; +# } else { +# daemon_log("$address not known, neither as server nor as client", 1); +# return "failed"; +# } +# } +# +# # erzeuge ein ciphering object +# my $act_cipher = &create_ciphering($passwd); +# +# # encrypt xml msg +# my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher); +# +# # öffne socket +# my $socket = &open_socket($address); +# if(not defined $socket){ +# daemon_log("cannot open socket to $address, server not reachable", 1); +# daemon_log("cannot send '$header'-msg", 1); +# return "failed"; +# } +# +# # versende xml msg +# print $socket $crypted_msg."\n"; +# +# # schließe socket +# close $socket; +# +# daemon_log("send '$header'-msg to $address", 5); +# daemon_log("crypted_msg:\n\t$crypted_msg", 7); +# +# return "done"; +#} + + +#=== 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: +#=============================================================================== +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) { + #daemon_log("cannot connect to socket at $PeerAddr, $@\n"); + return; + } + daemon_log("open_socket:\n\t$PeerAddr", 7); + return $socket; +} + + +#=== FUNCTION ================================================================ +# NAME: read_from_socket +# PARAMETERS: socket fh - +# RETURNS: result string - readed characters from socket +# DESCRIPTION: reads data from socket in 16 byte steps +#=============================================================================== +sub read_from_socket { + my ($socket) = @_; + my $result = ""; + + $socket->blocking(1); + $result = <$socket>; + + $socket->blocking(0); + while ( my $char = <$socket> ) { + if (not defined $char) { last } + $result .= $char; + } + return $result; + + + +# my ($socket) = @_; +# 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: print_known_hosts_hash +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub print_known_hosts_hash { + my ($tmp) = @_; + print "####################################\n"; + print "# status of known_hosts\n"; + my $hosts; + my $host_hash; + my @hosts = keys %$known_hosts; + foreach my $host (@hosts) { + #my @elements = keys %$known_hosts->{$host}; + my $status = $known_hosts->{$host}->{status} ; + my $passwd = $known_hosts->{$host}->{passwd}; + my $timestamp = $known_hosts->{$host}->{timestamp}; + print "$host\n"; + print "\t$status\n"; + print "\t$passwd\n"; + print "\t$timestamp\n"; + } + print "####################################\n"; + return; +} + +#=== FUNCTION ================================================================ +# NAME: +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub create_known_hosts_entry { + my ($hostname) = @_; + $known_hosts->{$hostname} = {}; + $known_hosts->{$hostname}->{status} = "none"; + $known_hosts->{$hostname}->{passwd} = "none"; + $known_hosts->{$hostname}->{timestamp} = "none"; + return; +} + + +#=== FUNCTION ================================================================ +# NAME: +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub update_known_hosts_entry { + my ($hostname, $status, $passwd, $timestamp) = @_; + 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; + $month+=1; + $month = $month < 10 ? $month = "0".$month : $month; + $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; + $year+=1900; + my $t = "$year$month$monthday$hours$minutes$seconds"; + + if($status) { + $known_hosts->{$hostname}->{status} = $status; + } + if($passwd) { + $known_hosts->{$hostname}->{passwd} = $passwd; + } + if($timestamp) { + $t = $timestamp; + } + $known_hosts->{$hostname}->{timestamp} = $t; + return; +} + + +#=== FUNCTION ================================================================ +# NAME: +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub add_content2known_hosts { + my ($hostname, $element, $content) = @_; + 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; + $month+=1; + $month = $month < 10 ? $month = "0".$month : $month; + $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; + $year+=1900; + my $t = "$year$month$monthday$hours$minutes$seconds"; + + $known_hosts->{$hostname}->{$element} = $content; + $known_hosts->{$hostname}->{timestamp} = $t; + return; +} + + +#=== FUNCTION ================================================================ +# NAME: +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub process_incoming_msg { + my ($crypted_msg) = @_; + if(not defined $crypted_msg) { + daemon_log("function 'process_incoming_msg': got no msg", 7); + } + $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("msg from host:", 1); + daemon_log("\t$host", 1); + daemon_log("crypted msg:", 7); + daemon_log("\t$crypted_msg", 7); + + my $act_cipher = &create_ciphering($server_passwd); + + # try to decrypt incoming msg + my ($msg, $msg_hash); + eval{ + $msg = &decrypt_msg($crypted_msg, $act_cipher); + $msg_hash = $xml->XMLin($msg, ForceArray=>1); + }; + if($@) { + daemon_log("ERROR: incoming msg cannot be decrypted with server passwd", 1); + return; + } + + my $header = @{$msg_hash->{header}}[0]; + + daemon_log("receive '$header' from $host", 1); +# daemon_log("header from msg:", 1); +# daemon_log("\t$header", 1); +# daemon_log("msg to process:", 7); +# daemon_log("\t$msg", 7); + + #check whether msg to process is a event + opendir(DIR, $event_dir) + or daemon_log("cannot find directory $event_dir, no events specified", 5); + my $file_name; + while(defined($file_name = readdir(DIR))){ + if ($file_name eq "." || $file_name eq "..") { + next; + } + if ($file_name eq $header) { + my $cmd = "$event_dir/$file_name '$msg'"; + my $result_xml = ""; + open(PIPE, "$cmd 2>&1 |"); + while() { + $result_xml.=$_; + last; + } + close(PIPE); + my $res_hash = &transform_msg2hash($result_xml); + my $res_target = @{$res_hash->{target}}[0]; + &send_msg_hash2address($res_hash, $server_address); + + return; + } + } + close(DIR); + daemon_log("could not assign the msg $header to an event", 5); + + if ($header eq 'new_ldap_config') { if ($ldap_enabled == 1) {&new_ldap_config($msg_hash)}} + elsif ($header eq 'ping') { &got_ping($msg_hash) } + elsif ($header eq 'wake_up') { &execute_event($msg_hash)} + elsif ($header eq 'new_passwd') { &new_passwd()} + else { daemon_log("ERROR: no function assigned to msg $header", 5) } + + return; +} + + +#=== FUNCTION ================================================================ +# NAME: +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub update_status { + my ($new_status) = @_ ; + my $out_hash = &create_xml_hash("update_status", $client_address, $server_address); + &add_content2xml_hash($out_hash, "update_status", $new_status); + &send_msg_hash2address($out_hash, $server_address); + return; +} + + +#=== FUNCTION ================================================================ +# NAME: +# PARAMETERS: +# RETURNS: +# DESCRIPTION: +#=============================================================================== +sub server_leaving { + my ($msg_hash) = @_ ; + my $source = &get_content_from_xml_hash("source"); + my $header = &get_content_from_xml_hash("header"); + + daemon_log("gosa daemon $source is going down, cause registration procedure", 1); + my $server_address = "none"; + my $server_passwd = "none"; + my $server_cipher = "none"; + + # reinitialization of default values in config file + &read_configfile; + + # registrated at new daemon + ®ister_at_server(); + + return; +} + + +sub got_ping { + my ($msg_hash) = @_ ; + + my $source = &get_content_from_xml_hash($msg_hash, 'source'); + my $target = &get_content_from_xml_hash($msg_hash, 'target'); + my $header = &get_content_from_xml_hash($msg_hash, 'header'); + + &add_content2known_hosts(hostname=>$target, status=>$header); + + my $out_hash = &create_xml_hash("got_ping", $target, $source); + &send_msg_hash2address($out_hash, $source, $server_passwd); + + return; +} + + +sub new_ldap_config { + my ($msg_hash) = @_ ; + my $element; + my @ldap_uris; + my $ldap_base; + my @ldap_options; + my @pam_options; + my @nss_options; + my $goto_admin; + my $goto_secret; + + # Transform input into array + while ( my ($key, $value) = each(%$msg_hash) ) { + if ($key =~ /^(source|target|header)$/) { + next; + } + + foreach $element (@$value) { + if ($key =~ /^ldap_uri$/) { + push (@ldap_uris, $element); + next; + } + if ($key =~ /^ldap_base$/) { + $ldap_base= $element; + next; + } + if ($key =~ /^goto_admin$/) { + $goto_admin= $element; + next; + } + if ($key =~ /^goto_secret$/) { + $goto_secret= $element; + next; + } + if ($key =~ /^ldap_cfg$/) { + push (@ldap_options, "$element"); + next; + } + if ($key =~ /^pam_cfg$/) { + push (@pam_options, "$element"); + next; + } + if ($key =~ /^nss_cfg$/) { + push (@nss_options, "$element"); + next; + } + } + } + + # Setup ldap.conf + my $file1; + my $file2; + open(file1, "> $ldap_config"); + print file1 "# This file was automatically generated by gosa-si-client. Do not change.\n"; + print file1 "URI"; + foreach $element (@ldap_uris) { + print file1 " $element"; + } + print file1 "\nBASE $ldap_base\n"; + foreach $element (@ldap_options) { + print file1 "$element\n"; + } + close (file1); + daemon_log("wrote $ldap_config", 5); + + # Setup pam_ldap.conf / libnss_ldap.conf + open(file1, "> $pam_config"); + open(file2, "> $nss_config"); + print file1 "# This file was automatically generated by gosa-si-client. Do not change.\n"; + print file2 "# This file was automatically generated by gosa-si-client. Do not change.\n"; + print file1 "uri"; + print file2 "uri"; + foreach $element (@ldap_uris) { + print file1 " $element"; + print file2 " $element"; + } + print file1 "\nbase $ldap_base\n"; + print file2 "\nbase $ldap_base\n"; + foreach $element (@pam_options) { + print file1 "$element\n"; + } + foreach $element (@nss_options) { + print file2 "$element\n"; + } + close (file2); + daemon_log("wrote $nss_config", 5); + close (file1); + daemon_log("wrote $pam_config", 5); + + # Create goto.secrets if told so + if (defined $goto_admin){ + open(file1, "> /etc/goto/secret"); + close(file1); + chown(0,0, "/etc/goto/secret"); + chmod(0600, "/etc/goto/secret"); + open(file1, "> /etc/goto/secret"); + print file1 $goto_admin.":".$goto_secret."\n"; + close(file1); + daemon_log("wrote /etc/goto/secret", 5); + } + + return; + +} + + +sub execute_event { + my ($msg_hash)= @_; + my $configdir= '/etc/gosa-si/client/events/'; + my $result; + + my $header = &get_content_from_xml_hash($msg_hash, 'header'); + my $source = &get_content_from_xml_hash($msg_hash, 'source'); + my $target = &get_content_from_xml_hash($msg_hash, 'target'); + + + if((not defined $source) + && (not defined $target) + && (not defined $header)) { + daemon_log("ERROR: Entries missing in XML msg for gosa events under $configdir"); + } else { + my $parameters=""; + my @params = &get_content_from_xml_hash($msg_hash, $header); + my $params = join(", ", @params); + daemon_log("execute_event: got parameters: $params", 5); + + if (@params) { + foreach my $param (@params) { + my $param_value = (&get_content_from_xml_hash($msg_hash, $param))[0]; + daemon_log("execute_event: parameter -> value: $param -> $param_value", 7); + $parameters.= " ".$param_value; + } + } + + my $cmd= $configdir.$header."$parameters"; + daemon_log("execute_event: executing cmd: $cmd", 7); + $result= ""; + open(PIPE, "$cmd 2>&1 |"); + while() { + $result.=$_; + } + close(PIPE); + } + + # process the event result + + + return; +} + + +sub new_passwd { + # my ($msg_hash) = @_ ; + my $new_server_passwd = &create_passwd(); + my $new_server_cipher = &create_ciphering($new_server_passwd); + + my $out_hash = &create_xml_hash("new_passwd", $client_address, $server_address, $new_server_passwd); + + &send_msg_hash2address($out_hash, $server_address, $server_passwd); + + $server_passwd = $new_server_passwd; + $server_cipher = $new_server_cipher; + return; +} + + + + +#==== MAIN = main ============================================================== + +# parse commandline options +Getopt::Long::Configure( "bundling" ); +GetOptions("h|help" => \&usage, + "c|config=s" => \$cfg_file, + "f|foreground" => \$foreground, + "v|verbose+" => \$verbose, + ); + +# read and set config parameters +&check_cmdline_param ; +&read_configfile; +&check_pid; + +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: $!"; +} + + +# restart daemon log file +if(-e $log_file ) { unlink $log_file } +daemon_log(" ", 1); +daemon_log("$0 started!", 1); + +# Just fork, if we"re not in foreground mode +if( ! $foreground ) { $pid = fork(); } +else { $pid = $$; } + +# Do something useful - put our PID into the pid_file +if( 0 != $pid ) { + open( LOCK_FILE, ">$pid_file" ); + print LOCK_FILE "$pid\n"; + close( LOCK_FILE ); + if( !$foreground ) { exit( 0 ) }; +} + +# detect own ip and mac address +$network_interface= &get_interface_for_ip($client_ip); +$client_mac_address= &get_mac($network_interface); + +# ($client_ip, $client_mac_address) = &get_ip_and_mac(); +#if (not defined $client_ip) { +# die "EXIT: ip address of $0 could not be detected"; +#} +daemon_log("client ip address detected: $client_ip", 1); +daemon_log("client mac address detected: $client_mac_address", 1); + +# prepare variables +if (defined $server_ip && defined $server_port) { + $server_address = $server_ip.":".$server_port; +} +$client_address = $client_ip.":".$client_port; + +# setup xml parser +$xml = new XML::Simple(); + +# create input socket +daemon_log(" ", 1); +$rbits = $wbits = $ebits = ""; +$input_socket = IO::Socket::INET->new(LocalPort => $client_port, + Type => SOCK_STREAM, + Reuse => 1, + Listen => 20, + ); +if(not defined $input_socket){ + daemon_log("cannot be a tcp server at $client_port : $@\n"); +} else { + daemon_log("start client at $client_address",1) ; + vec($rbits, fileno $input_socket, 1) = 1; + vec($wbits, fileno $input_socket, 1) = 1; +} + +# register at server +daemon_log(" ", 1); +®ister_at_server(); + + +############## +# Debugging +############# +#sleep(2); +#&update_status("ich_bin_ein_neuer_status"); + +################################### +#everything ready, okay, lets start +################################### +while(1) { + my ($rout, $wout); + my $nf = select($rout=$rbits, $wout=$wbits, undef, undef); + + # error handling + if($nf < 0 ) { + } + + # something is coming in + if(vec $rout, fileno $input_socket, 1) { + my $client = $input_socket->accept(); + my $other_end = getpeername($client); + + if(not defined $other_end) { + daemon_log("client cannot be identified: $!"); + } else { + my ($port, $iaddr) = unpack_sockaddr_in($other_end); + my $actual_ip = inet_ntoa($iaddr); + daemon_log("accept client from $actual_ip", 5); + my $in_msg = &read_from_socket($client); + if(defined $in_msg){ + chomp($in_msg); + $in_msg = $in_msg.".".$actual_ip; + &process_incoming_msg($in_msg); + + } + } + } +} + + + + diff --git a/gosa-si/gosa-si-server b/gosa-si/gosa-si-server new file mode 100755 index 000000000..19fdc07d1 --- /dev/null +++ b/gosa-si/gosa-si-server @@ -0,0 +1,731 @@ +#!/usr/bin/perl +#=============================================================================== +# +# FILE: gosa-sd +# +# USAGE: ./gosa-sd +# +# DESCRIPTION: +# +# OPTIONS: --- +# REQUIREMENTS: libconfig-inifiles-perl libcrypt-rijndael-perl libxml-simple-perl +# libdata-dumper-simple-perl libdbd-sqlite3-perl libnet-ldap-perl +# libpoe-perl +# BUGS: --- +# NOTES: +# AUTHOR: (Andreas Rettenberger), +# COMPANY: +# VERSION: 1.0 +# CREATED: 12.09.2007 08:54:41 CEST +# REVISION: --- +#=============================================================================== + +use strict; +use warnings; +use Getopt::Long; +use Config::IniFiles; +use POSIX; +use Time::HiRes qw( gettimeofday ); + +use Fcntl; +use IO::Socket::INET; +use IO::Handle; +use IO::Select; +use Symbol qw(qualify_to_ref); +use Crypt::Rijndael; +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; +use POE qw(Component::Server::TCP); + +my $modules_path = "/usr/lib/gosa-si/modules"; +use lib "/usr/lib/gosa-si/modules"; + +my (%cfg_defaults, $foreground, $verbose, $ping_timeout); +my ($bus, $msg_to_bus, $bus_cipher); +my ($server, $server_mac_address, $server_events); +my ($gosa_server, $job_queue_timeout, $job_queue_table_name, $job_queue_file_name,$job_queue_loop_delay); +my ($known_modules, $known_clients_file_name, $known_server_file_name); +my ($max_clients); +my ($pid_file, $procid, $pid, $log_file); +my (%free_child, %busy_child, $child_max, $child_min, %child_alive_time, $child_timeout); +my ($arp_activ, $arp_fifo, $arp_fifo_path); + +# variables declared in config file are always set to 'our' +our (%cfg_defaults, $log_file, $pid_file, + $bus_activ, $bus_passwd, $bus_ip, $bus_port, + $server_activ, $server_ip, $server_port, $server_passwd, $max_clients, + $arp_activ, $arp_fifo_path, + $gosa_activ, $gosa_passwd, $gosa_ip, $gosa_port, $gosa_timeout, +); + +# additional variable which should be globaly accessable +our $xml; +our $server_address; +our $bus_address; +our $gosa_address; +our $no_bus; +our $no_arp; +our $verbose; +our $forground; +our $cfg_file; + +# specifies the verbosity of the daemon_log +$verbose = 0 ; + +# if foreground is not null, script will be not forked to background +$foreground = 0 ; + +# specifies the timeout seconds while checking the online status of a registrating client +$ping_timeout = 5; + +$no_bus = 0; + +$no_arp = 0; + +# name of table for storing gosa jobs +our $job_queue_table_name = 'jobs'; +our $job_db; + +# holds all other gosa-sd as well as the gosa-sd-bus +our $known_server_db; + +# holds all registrated clients +our $known_clients_db; + +%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], + "job_queue_timeout" => [\$job_queue_timeout, undef], + "job_queue_file_name" => [\$job_queue_file_name, '/var/lib/gosa-si/jobs.db'], + "job_queue_loop_delay" => [\$job_queue_loop_delay, 3], + "known_clients_file_name" => [\$known_clients_file_name, '/var/lib/gosa-si/known_clients.db' ], + "known_server_file_name" => [\$known_server_file_name, '/var/lib/gosa-si/known_server.db'], + }, +"bus" => + {"bus_activ" => [\$bus_activ, "on"], + "bus_passwd" => [\$bus_passwd, ""], + "bus_ip" => [\$bus_ip, "0.0.0.0"], + "bus_port" => [\$bus_port, "20080"], + }, +"server" => + {"server_activ" => [\$server_activ, "on"], + "server_ip" => [\$server_ip, "0.0.0.0"], + "server_port" => [\$server_port, "20081"], + "server_passwd" => [\$server_passwd, ""], + "max_clients" => [\$max_clients, 100], + }, +"arp" => + {"arp_activ" => [\$arp_activ, "on"], + "arp_fifo_path" => [\$arp_fifo_path, "/var/run/gosa-si/arp-notify"], + }, +"gosa" => + {"gosa_activ" => [\$gosa_activ, "on"], + "gosa_ip" => [\$gosa_ip, "0.0.0.0"], + "gosa_port" => [\$gosa_port, "20082"], + "gosa_passwd" => [\$gosa_passwd, "none"], + }, + ); + + +#=== FUNCTION ================================================================ +# NAME: usage +# PARAMETERS: nothing +# RETURNS: nothing +# DESCRIPTION: print out usage text to STDERR +#=============================================================================== +sub usage { + print STDERR << "EOF" ; +usage: $0 [-hvf] [-c config] + + -h : this (help) message + -c : config file + -f : foreground, process will not be forked to background + -v : be verbose (multiple to increase verbosity) + -no-bus : starts $0 without connection to bus + -no-arp : starts $0 without connection to arp module + +EOF + print "\n" ; +} + + +#=== FUNCTION ================================================================ +# NAME: read_configfile +# PARAMETERS: cfg_file - string - +# RETURNS: nothing +# DESCRIPTION: read cfg_file and set variables +#=============================================================================== +sub read_configfile { + my $cfg; + if( defined( $cfg_file) && ( length($cfg_file) > 0 )) { + if( -r $cfg_file ) { + $cfg = Config::IniFiles->new( -file => $cfg_file ); + } else { + print STDERR "Couldn't read config file!\n"; + } + } else { + $cfg = Config::IniFiles->new() ; + } + foreach my $section (keys %cfg_defaults) { + foreach my $param (keys %{$cfg_defaults{ $section }}) { + my $pinfo = $cfg_defaults{ $section }{ $param }; + ${@$pinfo[ 0 ]} = $cfg->val( $section, $param, @$pinfo[ 1 ] ); + } + } +} + + +#=== FUNCTION ================================================================ +# NAME: logging +# PARAMETERS: level - string - default 'info' +# msg - string - +# facility - string - default 'LOG_DAEMON' +# RETURNS: nothing +# DESCRIPTION: function for logging +#=============================================================================== +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", "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 ); + } +#log into syslog +# 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)) { + $cfg_file = "/etc/gosa-si/server.conf"; + if(! -r $cfg_file) { + $err_config = "please specify a config file"; + $err_counter += 1; + } + } + if( $err_counter > 0 ) { + &usage( "", 1 ); + if( defined( $err_config)) { print STDERR "$err_config\n"} + print STDERR "\n"; + exit( -1 ); + } +} + + +#=== FUNCTION ================================================================ +# NAME: check_pid +# PARAMETERS: nothing +# RETURNS: nothing +# DESCRIPTION: handels pid processing +#=============================================================================== +sub check_pid { + $pid = -1; + # Check, if we are already running + if( open(LOCK_FILE, "<$pid_file") ) { + $pid = ; + if( defined $pid ) { + chomp( $pid ); + if( -f "/proc/$pid/stat" ) { + my($stat) = `cat /proc/$pid/stat` =~ m/$pid \((.+)\).*/; + if( $0 eq $stat ) { + close( LOCK_FILE ); + exit -1; + } + } + } + close( LOCK_FILE ); + unlink( $pid_file ); + } + + # create a syslog msg if it is not to possible to open PID file + if (not sysopen(LOCK_FILE, $pid_file, O_WRONLY|O_CREAT|O_EXCL, 0644)) { + my($msg) = "Couldn't obtain lockfile '$pid_file' "; + if (open(LOCK_FILE, '<', $pid_file) + && ($pid = )) + { + chomp($pid); + $msg .= "(PID $pid)\n"; + } else { + $msg .= "(unable to read PID)\n"; + } + if( ! ($foreground) ) { + openlog( $0, "cons,pid", "daemon" ); + syslog( "warning", $msg ); + closelog(); + } + else { + print( STDERR " $msg " ); + } + exit( -1 ); + } +} + +#=== FUNCTION ================================================================ +# NAME: import_modules +# PARAMETERS: module_path - string - abs. path to the directory the modules +# are stored +# RETURNS: nothing +# DESCRIPTION: each file in module_path which ends with '.pm' is imported by +# "require 'file';" +#=============================================================================== +sub import_modules { + daemon_log(" ", 1); + + if (not -e $modules_path) { + daemon_log("ERROR: cannot find directory or directory is not readable: $modules_path", 1); + } + + opendir (DIR, $modules_path) or die "ERROR while loading modules from directory $modules_path : $!\n"; + while (defined (my $file = readdir (DIR))) { + if (not $file =~ /(\S*?).pm$/) { + next; + } + eval { require $file; }; + if ($@) { + daemon_log("ERROR: gosa-si-server could not load module $file", 1); + daemon_log("$@", 5); + } else { + my $mod_name = $1; + my $info = eval($mod_name.'::get_module_info()'); + my ($input_address, $input_key, $input, $input_active, $input_type) = @{$info}; + $known_modules->{$mod_name} = $info; + + daemon_log("module $mod_name loaded", 1); + } + } + + # for debugging + #while ( my ($module, $tag_hash) = each(%$known_modules)) { + # print "\tmodule: $module"."\n"; + # print "\ttags: ".join(", ", keys(%$tag_hash))."\n"; + #} + close (DIR); +} + + +#=== FUNCTION ================================================================ +# NAME: sig_int_handler +# PARAMETERS: signal - string - signal arose from system +# RETURNS: noting +# DESCRIPTION: handels tasks to be done befor signal becomes active +#=============================================================================== +sub sig_int_handler { + my ($signal) = @_; + + daemon_log("shutting down gosa-si-server", 1); + exit(1); +} +$SIG{INT} = \&sig_int_handler; + + +#=== FUNCTION ================================================================ +# NAME: create_known_client +# PARAMETERS: hostname - string - key for the hash known_clients +# RETURNS: nothing +# DESCRIPTION: creates a dummy entry for hostname in known_clients +#=============================================================================== +sub create_known_client { + my ($hostname) = @_; + + my $entry = { table=>'known_clients', + hostname=>$hostname, + status=>'none', + hostkey=>'none', + timestamp=>'none', + macaddress=>'none', + events=>'none', + }; + my $res = $known_clients_db->add_dbentry($entry); + if ($res > 0) { + daemon_log("ERROR: cannot add entry to known_clients.db: $res", 1); + } + + return; +} + +#==== MAIN = main ============================================================== +# parse commandline options +Getopt::Long::Configure( "bundling" ); +GetOptions("h|help" => \&usage, + "c|config=s" => \$cfg_file, + "f|foreground" => \$foreground, + "v|verbose+" => \$verbose, + "no-bus+" => \$no_bus, + "no-arp+" => \$no_arp, + ); + +# read and set config parameters +&check_cmdline_param ; +&read_configfile; +&check_pid; + +$SIG{CHLD} = 'IGNORE'; + +# forward error messages to logfile +if( ! $foreground ) { + open(STDERR, '>>', $log_file); + open(STDOUT, '>>', $log_file); +} + +# 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 = $$; +} + +# Do something useful - put our PID into the pid_file +if( 0 != $pid ) { + open( LOCK_FILE, ">$pid_file" ); + print LOCK_FILE "$pid\n"; + close( LOCK_FILE ); + if( !$foreground ) { + exit( 0 ) + }; +} + +daemon_log(" ", 1); +daemon_log("$0 started!", 1); + +# delete old DBsqlite lock files +system('rm -f /tmp/gosa_si_lock*'); + +# connect to gosa-si job queue +my @job_col_names = ("id", "timestamp", "status", "result", "headertag", "targettag", "xmlmessage", "macaddress"); +$job_db = GOSA::DBsqlite->new($job_queue_file_name); +$job_db->create_table('jobs', \@job_col_names); + +# connect to known_clients_db +my @clients_col_names = ('hostname', 'status', 'hostkey', 'timestamp', 'macaddress', 'events'); +$known_clients_db = GOSA::DBsqlite->new($known_clients_file_name); +$known_clients_db->create_table('known_clients', \@clients_col_names); + +# connect to known_server_db +my @server_col_names = ('hostname', 'status', 'hostkey', 'timestamp'); +$known_server_db = GOSA::DBsqlite->new($known_server_file_name); +$known_server_db->create_table('known_server', \@server_col_names); + +# import all modules +&import_modules; + +# check wether all modules are gosa-si valid passwd check + +# create reading and writing vectors +my $rbits = my $wbits = my $ebits = ""; + +# add all module inputs to listening vector +# while( my ($mod_name, $info) = each %$known_modules ) { +# my ($input_address, $input_key, $input, $input_activ, $input_type) = @{$info}; +# vec($rbits, fileno $input, 1) = 1; +# +# } + + +## start arp fifo +#if ($no_arp > 0) { +# $arp_activ = "off"; +#} +#my $my_fifo; +#if($arp_activ eq "on") { +# daemon_log(" ", 1); +# $my_fifo = &open_fifo($arp_fifo_path); +# if($my_fifo == 0) { die "fifo file disappeared\n" } +# sysopen($arp_fifo, $arp_fifo_path, O_RDWR) or die "can't read from $arp_fifo: $!" ; +# +# vec($rbits, fileno $arp_fifo, 1) = 1; +#} +# + +################################### +##everything ready, okay, lets start +################################### +#while(1) { +# +# # add all handles from the childs +# while ( my ($pid, $child_hash) = each %busy_child ) { +# +# # check whether process still exists +# my $exitus_pid = waitpid($pid, WNOHANG); +# if($exitus_pid != 0) { +# delete $busy_child{$pid}; +# next; +# } +# +# # add child fhd to the listener +# my $fhd = $$child_hash{'pipe_rd'}; +# vec($rbits, fileno $fhd, 1) = 1; +# } +# +# my ($rout, $wout); +# my $nf = select($rout=$rbits, $wout=$wbits, undef, $job_queue_timeout); +# +# # error handling +# if($nf < 0 ) { +# } +# +# +## if($arp_activ eq "on" && vec($rout, fileno $arp_fifo, 1)) { +## my $in_msg = <$arp_fifo>; +## chomp($in_msg); +## print "arp_activ: msg: $in_msg\n"; +## my $act_passwd = $known_daemons->{$bus_address}->{passwd}; +## print "arp_activ: arp_passwd: $act_passwd\n"; +## +## my $in_msg_hash = $xml->XMLin($in_msg, ForceArray=>1); +## +## my $target = &get_content_from_xml_hash($in_msg_hash, 'target'); +## +## if ($target eq $server_address) { +## print "arp_activ: forward to server\n"; +## my $arp_cipher = &create_ciphering($act_passwd); +## my $crypted_msg = &encrypt_msg($in_msg, $arp_cipher); +## &activating_child($crypted_msg, $server_ip); +## } else { +## print "arp_activ: send to bus\n"; +## &send_msg_hash2address($in_msg_hash, $bus_address); +## } +## print "\n"; +## } +# +# +# # check input fhd of all modules +# while ( my ($mod_name, $info) = each %$known_modules) { +# my $input_fhd = @{$info}[2]; +# my $input_activ = @{$info}[3]; +# if (vec($rout, fileno $input_fhd, 1) && $input_activ eq 'on') { +# daemon_log(" ", 1); +# my $client = $input_fhd->accept(); +# my $other_end = getpeername($client); +# if(not defined $other_end) { +# daemon_log("client cannot be identified: $!"); +# } else { +# my ($port, $iaddr) = unpack_sockaddr_in($other_end); +# my $actual_ip = inet_ntoa($iaddr); +# daemon_log("accept client at daemon socket from $actual_ip", 5); +# my $in_msg = &read_from_socket($client); +# if(defined $in_msg){ +# chomp($in_msg); +# &activating_child($in_msg, $actual_ip, $client); +# } else { +# daemon_log("cannot read from $actual_ip", 5); +# } +# } +# } +# } +# +# # check all processing childs whether they are finished ('done') or +# while ( my ($pid, $child_hash) = each %busy_child ) { +# my $fhd = $$child_hash{'pipe_rd'}; +# +# if (vec($rout, fileno $fhd, 1) ) { +# daemon_log("process child $pid is ready to read", 5); +# +# my $in_msg; +# while (1) { +# my $part_in_msg = <$fhd>; +# if( $part_in_msg eq "ENDMESSAGE\n") { +# last; +# } +# $in_msg .= $part_in_msg; +# } +# chomp($in_msg); +# +# if (not defined $in_msg) { +# next; +# } elsif ($in_msg =~ "done") { +# daemon_log("process child read: $in_msg", 7); +# delete $busy_child{$pid}; +# $free_child{$pid} = $child_hash; +# +# } else { +# daemon_log("process child read:", 7); +# daemon_log("\n$in_msg", 8); +# # send computed answer back to connected client +# my $act_client = $busy_child{$pid}{client_ref}; +# print $act_client $in_msg."\n"; +# delete $busy_child{$pid}; +# $free_child{$pid} = $child_hash; +# +# } +# } +# } +# +# +# } +# +# +#} + +POE::Session->create +( + inline_states => { + _start => \&trigger_db_loop, + watch_for_new_jobs => \&watch_for_new_jobs, + } +); + +POE::Component::Server::TCP->new +( + Port => $server_port, + ClientInput => \&client_input, +); + +POE::Kernel->run(); +exit; + +sub client_input { + my ($heap,$input,$wheel) = @_[HEAP, ARG0, ARG1]; + ###################################### + # forward msg to all imported modules + no strict "refs"; + my $answer; + my %act_modules = %$known_modules; + while( my ($module, $info) = each(%act_modules)) { + daemon_log("Processing module ".$module, 3); + my $tmp = &{ $module."::process_incoming_msg" }($input.".".$heap->{remote_ip}."\n"); + if (defined $tmp) { + $answer = $tmp; + } + daemon_log("Got answer from module ".$module.": ".$answer,3); + } + daemon_log("processing of msg finished", 5); + + if (defined $answer) { + $heap->{client}->put($answer); + } else { + $heap->{client}->put("done\n"); + } +} + +sub trigger_db_loop { + my ($kernel) = $_[KERNEL]; + $kernel->delay_set('watch_for_new_jobs',3); +} + +sub watch_for_new_jobs { + my ($kernel,$heap) = @_[KERNEL, HEAP]; + + # check gosa job queue for jobs with executable timestamp + 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; + $month+=1; + $month = $month < 10 ? $month = "0".$month : $month; + $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; + $year+=1900; + my $timestamp = "$year$month$monthday$hours$minutes$seconds"; + + my $res = $job_db->select_dbentry( { table=>$job_queue_table_name, status=>'waiting', timestamp=>$timestamp } ); + + while( my ($id, $hit) = each %{$res} ) { + + my $jobdb_id = $hit->{id}; + my $macaddress = $hit->{macaddress}; + my $job_msg_hash = &transform_msg2hash($hit->{xmlmessage}); + my $out_msg_hash = $job_msg_hash; + my $res_hash = $known_clients_db->select_dbentry( {table=>'known_clients', macaddress=>$macaddress} ); + # expect macaddress is unique!!!!!! + my $target = $res_hash->{1}->{hostname}; + + if (not defined $target) { + &daemon_log("ERROR: no host found for mac address: $job_msg_hash->{mac}[0]", 1); + &daemon_log("xml message: $hit->{xmlmessage}", 5); + my $update_hash = { table=>$job_queue_table_name, + update=> [ { status=>['error'], result=>["no host found for mac address"] } ], + where=> [ { id=>[$jobdb_id] } ], + }; + my $res = $job_db->update_dbentry($update_hash); + + next; + } + + # add target + &add_content2xml_hash($out_msg_hash, "target", $target); + + # add new header + my $out_header = $job_msg_hash->{header}[0]; + $out_header =~ s/job_/gosa_/; + delete $out_msg_hash->{header}; + &add_content2xml_hash($out_msg_hash, "header", $out_header); + + # add sqlite_id + &add_content2xml_hash($out_msg_hash, "jobdb_id", $jobdb_id); + + my $out_msg = &create_xml_string($out_msg_hash); + + # encrypt msg as a GosaPackage module + my $cipher = &create_ciphering($gosa_passwd); + my $crypted_out_msg = &encrypt_msg($out_msg, $cipher); + + my $error = &send_msg_hash2address($out_msg_hash, "$gosa_ip:$gosa_port", $gosa_passwd); + + if ($error == 0) { + my $sql = "UPDATE '$job_queue_table_name' SET status='processing', targettag='$target' WHERE id='$jobdb_id'"; + my $res = $job_db->exec_statement($sql); + } else { + my $update_hash = { table=>$job_queue_table_name, + update=> [ { status=>'error' } ], + where=> [ { id=>$jobdb_id } ], + }; + my $res = $job_db->update_dbentry($update_hash); + } + } + + $kernel->delay_set('watch_for_new_jobs',3); +} diff --git a/gosa-si/modules/DBsqlite.pm b/gosa-si/modules/DBsqlite.pm new file mode 100644 index 000000000..20463d782 --- /dev/null +++ b/gosa-si/modules/DBsqlite.pm @@ -0,0 +1,377 @@ +package GOSA::DBsqlite; + + +use strict; +use warnings; +use DBI; +use Data::Dumper; +use threads; +use Time::HiRes qw(usleep); + +my $col_names = {}; + +sub new { + my $class = shift; + my $db_name = shift; + + my $lock='/tmp/gosa_si_lock'; + my $_lock = $db_name; + $_lock =~ tr/\//_/; + $lock.=$_lock; + my $self = {dbh=>undef,db_name=>undef,db_lock=>undef,db_lock_handle=>undef}; + my $dbh = DBI->connect("dbi:SQLite:dbname=$db_name"); + $self->{dbh} = $dbh; + $self->{db_name} = $db_name; + $self->{db_lock} = $lock; + bless($self,$class); + + return($self); +} + +sub lock_exists : locked { + my $self=shift; + my $funcname=shift; + my $lock = $self->{db_lock}; + my $result=(-f $lock); + if($result) { + #print STDERR "(".((defined $funcname)?$funcname:"").") Lock (PID ".$$.") $lock gefunden\n"; + usleep 100; + } + return $result; +} + +sub create_lock : locked { + my $self=shift; + my $funcname=shift; + #print STDERR "(".((defined $funcname)?$funcname:"").") Erzeuge Lock (PID ".$$.") ".($self->{db_lock})."\n"; + + my $lock = $self->{db_lock}; + while( -f $lock ) { + #print STDERR "(".((defined $funcname)?$funcname:"").") Lock (PID ".$$.") $lock gefunden\n"; + sleep 1; + } + + open($self->{db_lock_handle},'>',$self->{db_lock}); +} + +sub remove_lock : locked { + my $self=shift; + my $funcname=shift; + #print STDERR "(".((defined $funcname)?$funcname:"").") Entferne Lock (PID ".$$.") ".$self->{db_lock}."\n"; + close($self->{db_lock_handle}); + unlink($self->{db_lock}); +} + +sub create_table { + my $self = shift; + my $table_name = shift; + my $col_names_ref = shift; + $col_names->{ $table_name } = $col_names_ref; + my $col_names_string = join(', ', @{$col_names_ref}); + my $sql_statement = "CREATE TABLE IF NOT EXISTS $table_name ( $col_names_string )"; + &create_lock($self,'create_table'); + $self->{dbh}->do($sql_statement); + &remove_lock($self,'create_table'); + return 0; +} + + + +sub add_dbentry { + my $self = shift; + my $arg = shift; + + # if dbh not specified, return errorflag 1 + my $table = $arg->{table}; + if( not defined $table ) { + return 1 ; + } + + # specify primary key in table + if (not exists $arg->{primkey}) { + return 2; + } + my $primkey = $arg->{primkey}; + + # if primkey is id, fetch max id from table and give new job id= max(id)+1 + if ($primkey eq 'id') { + my $id; + my $sql_statement = "SELECT MAX(id) FROM $table"; + &create_lock($self,'add_dbentry'); + my $max_id = @{ @{ $self->{dbh}->selectall_arrayref($sql_statement) }[0] }[0]; + &remove_lock($self,'add_dbentry'); + if( defined $max_id) { + $id = $max_id + 1; + } else { + $id = 1; + } + $arg->{id} = $id; + } + + # check wether value to primary key is specified + if ( not exists $arg->{ $primkey } ) { + return 3; + } + + # if timestamp is not provided, add timestamp + if( not exists $arg->{timestamp} ) { + $arg->{timestamp} = &get_time; + } + + # check wether primkey is unique in table, otherwise return errorflag + my $sql_statement = "SELECT * FROM $table WHERE $primkey='$arg->{$primkey}'"; + &create_lock($self,'add_dbentry'); + my $res = @{ $self->{dbh}->selectall_arrayref($sql_statement) }; + &remove_lock($self,'add_dbentry'); + if ($res == 0) { + # fetch column names of table + my $col_names = &get_table_columns("",$table); + + # assign values to column name variables + my @add_list; + foreach my $col_name (@{$col_names}) { + # use function parameter for column values + if (exists $arg->{$col_name}) { + push(@add_list, $arg->{$col_name}); + } + } + + my $sql_statement = "INSERT INTO $table VALUES ('".join("', '", @add_list)."')"; + print STDERR $sql_statement; + &create_lock($self,'add_dbentry'); + my $db_res = $self->{dbh}->do($sql_statement); + &remove_lock($self,'add_dbentry'); + if( $db_res != 1 ) { + return 4; + } else { + return 0; + } + + } else { + my $update_hash = { table=>$table }; + $update_hash->{where} = [ { $primkey=>[ $arg->{$primkey} ] } ]; + $update_hash->{update} = [ {} ]; + while( my ($pram, $val) = each %{$arg} ) { + if( $pram eq 'table' ) { next; } + if( $pram eq 'primkey' ) { next; } + $update_hash->{update}[0]->{$pram} = [$val]; + } + my $db_res = &update_dbentry( $self, $update_hash ); + if( $db_res != 1 ) { + return 5; + } else { + return 0; + } + + } +} + + +# error-flags +# 1 no table ($table) defined +# 2 no restriction parameter ($restric_pram) defined +# 3 no restriction value ($restric_val) defined +# 4 column name not known in table +# 5 no column names to change specified +sub update_dbentry { + my $self = shift; + my $arg = shift; + + + # check completeness of function parameter + # extract table statement from arg hash + my $table = $arg->{table}; + if (not defined $table) { + return 1; + } else { + delete $arg->{table}; + } + + # extract where parameter from arg hash + my $where_statement = ""; + if( exists $arg->{where} ) { + my $where_hash = @{ $arg->{where} }[0]; + if( 0 < keys %{ $where_hash } ) { + my @where_list; + while( my ($rest_pram, $rest_val) = each %{ $where_hash } ) { + my $statement; + if( $rest_pram eq 'timestamp' ) { + $statement = "$rest_pram<'@{ $rest_val }[0]'"; + } else { + $statement = "$rest_pram='@{ $rest_val }[0]'"; + } + push( @where_list, $statement ); + } + $where_statement .= "WHERE ".join('AND ', @where_list); + } + } + + # extract update parameter from arg hash + my $update_hash = @{ $arg->{update} }[0]; + my $update_statement = ""; + if( 0 < keys %{ $update_hash } ) { + my @update_list; + while( my ($rest_pram, $rest_val) = each %{ $update_hash } ) { + my $statement = "$rest_pram='@{ $rest_val }[0]'"; + push( @update_list, $statement ); + } + $update_statement .= join(', ', @update_list); + } + + my $sql_statement = "UPDATE $table SET $update_statement $where_statement"; + &create_lock($self,'update_dbentry'); + my $db_answer = $self->{dbh}->do($sql_statement); + &remove_lock($self,'update_dbentry'); + return $db_answer; +} + + +sub del_dbentry { + my $self = shift; + my $arg = shift; + + + # check completeness of function parameter + # extract table statement from arg hash + my $table = $arg->{table}; + if (not defined $table) { + return 1; + } else { + delete $arg->{table}; + } + + # collect select statements + my @del_list; + while (my ($pram, $val) = each %{$arg}) { + if ( $pram eq 'timestamp' ) { + push(@del_list, "$pram < '$val'"); + } else { + push(@del_list, "$pram = '$val'"); + } + } + + my $where_statement; + if( not @del_list ) { + $where_statement = ""; + } else { + $where_statement = "WHERE ".join(' AND ', @del_list); + } + + my $sql_statement = "DELETE FROM $table $where_statement"; + &create_lock($self,'del_dbentry'); + my $db_res = $self->{dbh}->do($sql_statement); + &remove_lock($self,'del_dbentry'); + return $db_res; +} + + +sub get_table_columns { + my $self = shift; + my $table = shift; + my @column_names; + + if(exists $col_names->{$table}) { + @column_names = @{$col_names->{$table}}; + } else { + &create_lock($self,'get_table_columns'); + my @res = @{$self->{dbh}->selectall_arrayref("pragma table_info('$table')")}; + &remove_lock($self,'get_table_columns'); + foreach my $column (@res) { + push(@column_names, @$column[1]); + } + } + return \@column_names; + +} + +sub select_dbentry { + my $self = shift; + my $arg = shift; + + + # check completeness of function parameter + # extract table statement from arg hash + my $table = $arg->{table}; + if (not defined $table) { + return 1; + } else { + delete $arg->{table}; + } + + # collect select statements + my @select_list; + my $sql_statement; + while (my ($pram, $val) = each %{$arg}) { + if ( $pram eq 'timestamp' ) { + push(@select_list, "$pram < '$val'"); + } else { + push(@select_list, "$pram = '$val'"); + } + } + + if (@select_list == 0) { + $sql_statement = "SELECT * FROM '$table'"; + } else { + $sql_statement = "SELECT * FROM '$table' WHERE ".join(' AND ', @select_list); + } + + # query db + &create_lock($self,'select_dbentry'); + my $query_answer = $self->{dbh}->selectall_arrayref($sql_statement); + &remove_lock($self,'select_dbentry'); + + # fetch column list of db and create a hash with column_name->column_value of the select query + my $column_list = &get_table_columns($self, $table); + my $list_len = @{ $column_list } ; + my $answer = {}; + my $hit_counter = 0; + + foreach my $hit ( @{ $query_answer }) { + $hit_counter++; + for ( my $i = 0; $i < $list_len; $i++) { + $answer->{ $hit_counter }->{ @{ $column_list }[$i] } = @{ $hit }[$i]; + } + } + + return $answer; +} + + +sub show_table { + my $self = shift; + my $table_name = shift; + &create_lock($self,'show_table'); + my @res = @{$self->{dbh}->selectall_arrayref( "SELECT * FROM $table_name")}; + &remove_lock($self,'show_table'); + my @answer; + foreach my $hit (@res) { + push(@answer, "hit: ".join(', ', @{$hit})); + } + return join("\n", @answer); +} + + +sub exec_statement { + my $self = shift; + my $sql_statement = shift; + &create_lock($self,'exec_statement'); + my @res = @{$self->{dbh}->selectall_arrayref($sql_statement)}; + &remove_lock($self, 'exec_statement'); + return \@res; +} + +sub get_time { + 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; + $month+=1; + $month = $month < 10 ? $month = "0".$month : $month; + $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; + $year+=1900; + return "$year$month$monthday$hours$minutes$seconds"; +} + + +1; diff --git a/gosa-si/modules/GosaPackages.pm b/gosa-si/modules/GosaPackages.pm new file mode 100644 index 000000000..86895caeb --- /dev/null +++ b/gosa-si/modules/GosaPackages.pm @@ -0,0 +1,610 @@ +package GosaPackages; + +use Exporter; +@ISA = ("Exporter"); + +use strict; +use warnings; +use GOSA::GosaSupportDaemon; +use IO::Socket::INET; +use XML::Simple; +use File::Spec; +use Data::Dumper; +use GOSA::DBsqlite; +use MIME::Base64; + +BEGIN{} +END{} + +my ($server_activ, $server_ip, $server_mac_address, $server_port, $server_passwd, $max_clients, $server_event_dir); +my ($bus_activ, $bus_passwd, $bus_ip, $bus_port); +my ($gosa_activ, $gosa_ip, $gosa_mac_address, $gosa_port, $gosa_passwd, $network_interface); +my ($job_queue_timeout, $job_queue_file_name); + +my $gosa_server; + +my %cfg_defaults = +("general" => + {"job_queue_file_name" => [\$job_queue_file_name, '/var/lib/gosa-si/jobs.db'], + }, +"server" => + {"server_activ" => [\$server_activ, "on"], + "server_ip" => [\$server_ip, "0.0.0.0"], + "server_port" => [\$server_port, "20081"], + "server_passwd" => [\$server_passwd, ""], + "max_clients" => [\$max_clients, 100], + "server_event_dir" => [\$server_event_dir, '/usr/lib/gosa-si/server/events'], + }, +"bus" => + {"bus_activ" => [\$bus_activ, "on"], + "bus_passwd" => [\$bus_passwd, ""], + "bus_ip" => [\$bus_ip, "0.0.0.0"], + "bus_port" => [\$bus_port, "20080"], + }, +"gosa" => + {"gosa_activ" => [\$gosa_activ, "on"], + "gosa_ip" => [\$gosa_ip, "0.0.0.0"], + "gosa_port" => [\$gosa_port, "20082"], + "gosa_passwd" => [\$gosa_passwd, "none"], + }, +); + + +## START ########################## + +# read configfile and import variables +&read_configfile(); +$network_interface= &get_interface_for_ip($server_ip); +$gosa_mac_address= &get_mac($network_interface); + +# complete addresses +my $server_address = "$server_ip:$server_port"; +my $bus_address = "$bus_ip:$bus_port"; +my $gosa_address = "$gosa_ip:$gosa_port"; + +# create general settings for this module +my $gosa_cipher = &create_ciphering($gosa_passwd); +my $xml = new XML::Simple(); + +# open gosa socket +if ($gosa_activ eq "on") { + &main::daemon_log(" ",1); + $gosa_server = IO::Socket::INET->new(LocalPort => $gosa_port, + Type => SOCK_STREAM, + Reuse => 1, + Listen => 1, + ); + if (not defined $gosa_server) { + &main::daemon_log("cannot start tcp server at $gosa_port for communication to gosa: $@", 1); + die; + } else { + &main::daemon_log("start server for communication to gosa: $gosa_address", 1); + + } +} + +# create gosa job queue as a SQLite DB +my $table_name = "jobs"; +my $sqlite = GOSA::DBsqlite->new($job_queue_file_name); + + + + +## FUNCTIONS ################################################################# + +sub get_module_info { + my @info = ($gosa_address, + $gosa_passwd, + $gosa_server, + $gosa_activ, + "socket", + ); + return \@info; +} + + +#=== FUNCTION ================================================================ +# NAME: read_configfile +# PARAMETERS: cfg_file - string - +# RETURNS: nothing +# DESCRIPTION: read cfg_file and set variables +#=============================================================================== +sub read_configfile { + my $cfg; + if( defined( $main::cfg_file) && ( length($main::cfg_file) > 0 )) { + if( -r $main::cfg_file ) { + $cfg = Config::IniFiles->new( -file => $main::cfg_file ); + } else { + print STDERR "Couldn't read config file!"; + } + } else { + $cfg = Config::IniFiles->new() ; + } + foreach my $section (keys %cfg_defaults) { + foreach my $param (keys %{$cfg_defaults{ $section }}) { + my $pinfo = $cfg_defaults{ $section }{ $param }; + ${@$pinfo[0]} = $cfg->val( $section, $param, @$pinfo[1] ); + } + } +} + +#=== FUNCTION ================================================================ +# NAME: get_interface_for_ip +# PARAMETERS: ip address (i.e. 192.168.0.1) +# RETURNS: array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else +# 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; + } + } + } + } + return $result; +} + +#=== FUNCTION ================================================================ +# NAME: get_interfaces +# PARAMETERS: none +# RETURNS: (list of interfaces) +# DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. +#=============================================================================== +sub get_interfaces { + my @result; + my $PROC_NET_DEV= ('/proc/net/dev'); + + open(PROC_NET_DEV, "<$PROC_NET_DEV") + or die "Could not open $PROC_NET_DEV"; + + my @ifs = ; + + close(PROC_NET_DEV); + + # 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; + } + + return @result; +} + +#=== FUNCTION ================================================================ +# NAME: get_mac +# PARAMETERS: interface name (i.e. eth0) +# RETURNS: (mac address) +# DESCRIPTION: Uses ioctl to get mac address directly from system. +#=============================================================================== +sub get_mac { + my $ifreq= shift; + my $result; + if ($ifreq && length($ifreq) > 0) { + if($ifreq eq "all") { + $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 ($gosa_mac_address and length($gosa_mac_address) > 0) { + $result= $gosa_mac_address; + } + + socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip') + or die "socket: $!"; + + 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; + } + } + } + } + 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: 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; + } + &main::daemon_log("open_socket to: $PeerAddr", 7); + return $socket; +} + + +#=== FUNCTION ================================================================ +# NAME: process_incoming_msg +# PARAMETERS: crypted_msg - string - incoming crypted message +# RETURNS: nothing +# DESCRIPTION: handels the proceeded distribution to the appropriated functions +#=============================================================================== +sub process_incoming_msg { + my ($crypted_msg) = @_ ; + &main::daemon_log("Got message $crypted_msg", 5); + if( (not(defined($crypted_msg))) || (length($crypted_msg) <= 0)) { + &main::daemon_log("function 'process_incoming_msg': got no msg", 7); + 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); + + # collect addresses from possible incoming clients + # only gosa is allowd as incoming client + &main::daemon_log("GosaPackages: host_key: $host", 7); + &main::daemon_log("GosaPackages: key_passwd: $gosa_passwd", 7); + + $gosa_cipher = &create_ciphering($gosa_passwd); + + # determine the correct passwd for deciphering of the incoming msgs + my $msg = ""; + my $msg_hash; + eval{ + $msg = &decrypt_msg($crypted_msg, $gosa_cipher); + &main::daemon_log("GosaPackages: decrypted_msg: \n$msg", 7); + + $msg_hash = $xml->XMLin($msg, ForceArray=>1); + }; + if($@) { + &main::daemon_log("WARNING: GosaPackages do not understand the message:", 5); + &main::daemon_log("$@", 7); + return; + } + + my $header = @{$msg_hash->{header}}[0]; + + &main::daemon_log("GosaPackages: receive '$header' from $host", 1); + + my $out_msg; + if ($header =~ /^job_/) { + $out_msg = &process_job_msg($msg, $msg_hash); + } elsif ($header =~ /^gosa_/) { + $out_msg = &process_gosa_msg($msg, $header); + } else { + &main::daemon_log("ERROR: $header is not a valid GosaPackage-header, need a 'job_' or a 'gosa_' prefix"); + } + + if (not defined $out_msg) { + return; + } + + if ($out_msg =~ /(\d*?)<\/jobdb_id>/) { + my $job_id = $1; + my $sql = "BEGIN TRANSATION; UPDATE '".$main::job_queue_table_name. + "' SET status='done', result='".$out_msg. + "' WHERE id='$job_id'; COMMIT;"; + my $res = $main::job_db->exec_statement($sql); + return; + + } else { + + my $out_cipher = &create_ciphering($gosa_passwd); + $out_msg = &encrypt_msg($out_msg, $out_cipher); + return $out_msg; + } + +} + +sub process_gosa_msg { + my ($msg, $header) = @_ ; + my $out_msg; + $header =~ s/gosa_//; + + # decide wether msg is a core function or a event handler + if ( $header eq 'query_jobdb') { $out_msg = &query_jobdb } + elsif ($header eq 'delete_jobdb_entry') { $out_msg = &delete_jobdb_entry } + elsif ($header eq 'clear_jobdb') { $out_msg = &clear_jobdb } + elsif ($header eq 'update_status_jobdb_entry' ) { $out_msg = &update_status_jobdb_entry } + elsif ($header eq 'update_timestamp_jobdb_entry' ) { $out_msg = &update_timestamp_jobdb_entry } + else { + # msg could not be assigned to core function + # fetch all available eventhandler under $server_event_dir + opendir (DIR, $server_event_dir) or &main::daemon_log("ERROR cannot open $server_event_dir: $!\n", 1) and return; + while (defined (my $file = readdir (DIR))) { + if (not $file eq $header) { + next; + } + # try to deliver incoming msg to eventhandler + my $cmd = File::Spec->join($server_event_dir, $header)." '$msg'"; + &main::daemon_log("GosaPackages: execute event_handler $header", 3); + &main::daemon_log("GosaPackages: cmd: $cmd", 7); + + $out_msg = ""; + open(PIPE, "$cmd 2>&1 |"); + while() { + $out_msg.=$_; + } + close(PIPE); + &main::daemon_log("GosaPackages: answer of cmd: $out_msg", 5); + last; + } + } + + # if delivery not possible raise error and return + if (not defined $out_msg) { + &main::daemon_log("ERROR: GosaPackages: no event handler or core function defined for $header", 1); + } elsif ($out_msg eq "") { + &main::daemon_log("ERROR: GosaPackages got not answer from event_handler $header", 1); + } + return $out_msg; + +} + + +sub process_job_msg { + my ($msg, $msg_hash)= @_ ; + + my $header = @{$msg_hash->{header}}[0]; + $header =~ s/job_//; + + # check wether mac address is already known in known_daemons or known_clients + my $target = 'none'; + + # add job to job queue + my $func_dic = {table=>$main::job_queue_table_name, + primkey=>'id', + timestamp=>@{$msg_hash->{timestamp}}[0], + status=>'waiting', + result=>'none', + headertag=>$header, + targettag=>$target, + xmlmessage=>$msg, + macaddress=>@{$msg_hash->{mac}}[0], + }; + my $res = $main::job_db->add_dbentry($func_dic); + if (not $res == 0) { + &main::daemon_log("ERROR: GosaPackages: process_job_msg: $res", 1); + } + + &main::daemon_log("GosaPackages: $header job successfully added to job queue", 3); + return "<1>$res"; + +} + + +sub db_res_2_xml { + my ($db_res) = @_ ; + + my $xml = ""; + + while ( my ($hit, $hash) = each %{ $db_res } ) { + $xml .= "\n"; + + while ( my ($column_name, $column_value) = each %{$hash} ) { + $xml .= "<$column_name>"; + my $xml_content; + if( $column_name eq "xmlmessage" ) { + $xml_content = &encode_base64($column_value); + } else { + $xml_content = $column_value; + } + $xml .= $xml_content; + $xml .= ""; + } + + $xml .= ""; + } + + $xml .= ""; + return $xml; +} + + +## CORE FUNCTIONS ############################################################ + +sub query_jobdb { + my ($msg) = @_; + my $msg_hash = &transform_msg2hash($msg); + + # prepare query sql statement + my @where = @{$msg_hash->{where}}; + my $where_hash = {table=>$main::job_queue_table_name }; + foreach my $where_pram (@where) { + my $where_val = @{$msg_hash->{$where_pram}}[0]; + if (defined $where_val) { + $where_hash->{$where_pram} = $where_val; + } + } + + # execute db query + my $res_hash = $main::job_db->select_dbentry($where_hash); + + my $out_xml = &db_res_2_xml($res_hash); + return $out_xml; +} + +sub delete_jobdb_entry { + my ($msg) = @_ ; + my $msg_hash = &transform_msg2hash($msg); + + # prepare query sql statement + my @where = @{$msg_hash->{where}}; + my $where_hash = {table=>$main::job_queue_table_name }; + foreach my $where_pram (@where) { + my $where_val = @{$msg_hash->{$where_pram}}[0]; + if (defined $where_val) { + $where_hash->{$where_pram} = $where_val; + } + } + + # execute db query + my $db_res = $main::job_db->del_dbentry($where_hash); + + my $res; + if( $db_res > 0 ) { + $res = 0 ; + } else { + $res = 1; + } + + # prepare xml answer + my $out_xml = "$res"; + return $out_xml; + +} + +sub clear_jobdb { + my ($msg) = @_ ; + my $msg_hash = &transform_msg2hash($msg); + + my $where_hash = {table=>$main::job_queue_table_name }; + + # execute db query + my $db_res = $main::job_db->del_dbentry($where_hash); + print STDERR "db_res=$db_res\n"; + my $res; + if( $db_res eq '0E0' ) { + $res = 0 ; + } else { + $res = 1; + } + + # prepare xml answer + my $out_xml = "$res"; + return $out_xml; +} + +sub update_status_jobdb_entry { + my ($msg) = @_ ; + my $msg_hash = &transform_msg2hash($msg); + + # prepare query sql statement + my $update_hash = {table=>$main::job_queue_table_name }; + if( exists $msg_hash->{where} ) { + $update_hash->{where} = $msg_hash->{where}; + } else { + $update_hash->{where} = []; + } + + if( not exists $msg_hash->{update}[0]->{status} ) { + return "1"; + } + $update_hash->{update} = [ { status=>$msg_hash->{update}[0]->{status} } ]; + + # execute db query + my $db_res = $main::job_db->update_dbentry($update_hash); + + # transform db answer to error returnment + my $res; + if( $db_res > 0 ) { + $res = 0 ; + } else { + $res = 1; + } + + # prepare xml answer + my $out_xml = "$res"; + return $out_xml; +} + +sub update_timestamp_jobdb_entry { + my ($msg) = @_ ; + my $msg_hash = &transform_msg2hash($msg); + + # prepare query sql statement + my $update_hash = {table=>$main::job_queue_table_name }; + if( exists $msg_hash->{where} ) { + $update_hash->{where} = $msg_hash->{where}; + } else { + $update_hash->{where} = []; + } + + if( not exists $msg_hash->{update}[0]->{timestamp} ) { + return "1"; + } + + $update_hash->{update} = [ { timestamp=>$msg_hash->{update}[0]->{timestamp} } ]; + + # execute db query + my $db_res = $main::job_db->update_dbentry($update_hash); + + # transform db answer to error returnment + my $res; + if( $db_res > 0 ) { + $res = 0 ; + } else { + $res = 1; + } + + # prepare xml answer + my $out_xml = "$res"; + return $out_xml; + +} + + +1; + + + + + + + + + + diff --git a/gosa-si/modules/GosaSupportDaemon.pm b/gosa-si/modules/GosaSupportDaemon.pm new file mode 100644 index 000000000..cf26ca49f --- /dev/null +++ b/gosa-si/modules/GosaSupportDaemon.pm @@ -0,0 +1,300 @@ +package GOSA::GosaSupportDaemon; + +use Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(create_xml_hash send_msg_hash2address get_content_from_xml_hash add_content2xml_hash create_xml_string encrypt_msg decrypt_msg create_ciphering transform_msg2hash get_time send_msg); + +use strict; +use warnings; +use IO::Socket::INET; +use Crypt::Rijndael; +use Digest::MD5 qw(md5 md5_hex md5_base64); +use MIME::Base64; +use XML::Simple; + + + +BEGIN {} + +END {} + +### Start ###################################################################### + +my $xml = new XML::Simple(); + +sub process_incoming_msg { + return; +} + +sub daemon_log { + my ($msg, $level) = @_ ; + &main::daemon_log($msg, $level); + return; +} + + +#=== FUNCTION ================================================================ +# NAME: create_xml_hash +# PARAMETERS: header - string - message header (required) +# source - string - where the message come from (required) +# target - string - where the message should go to (required) +# [header_value] - string - something usefull (optional) +# RETURNS: hash - hash - nomen est omen +# DESCRIPTION: creates a key-value hash, all values are stored in a array +#=============================================================================== +sub create_xml_hash { + my ($header, $source, $target, $header_value) = @_; + my $hash = { + header => [$header], + source => [$source], + target => [$target], + $header => [$header_value], + }; + return $hash +} + + +sub transform_msg2hash { + my ($msg) = @_ ; + my $hash = $xml->XMLin($msg, ForceArray=>1); + + # xml tags without a content are created as an empty hash + # substitute it with an empty list + while( my ($xml_tag, $xml_content) = each %{ $hash } ) { + if( 1 == @{ $xml_content } ) { + # there is only one element in xml_content list ... + my $element = @{ $xml_content }[0]; + if( ref($element) eq "HASH" ) { + # and this element is an hash ... + my $len_element = keys %{ $element }; + if( $len_element == 0 ) { + # and this hash is empty, then substitute the xml_content + # with an empty string in list + $hash->{$xml_tag} = [ "none" ]; + } + } + } + } + + return $hash; +} + + +#=== FUNCTION ================================================================ +# NAME: send_msg_hash2address +# PARAMETERS: msg_hash - hash - xml_hash created with function create_xml_hash +# PeerAddr string - socket address to send msg +# PeerPort string - socket port, if not included in socket address +# RETURNS: nothing +# DESCRIPTION: ???? +#=============================================================================== +sub send_msg_hash2address ($$$){ + my ($msg_hash, $address, $passwd) = @_ ; + + # fetch header for logging + my $header = @{$msg_hash->{header}}[0]; + + # generate xml string + my $msg_xml = &create_xml_string($msg_hash); + + # create ciphering object + my $act_cipher = &create_ciphering($passwd); + + # encrypt xml msg + my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher); + + # opensocket + my $socket = &open_socket($address); + if(not defined $socket){ + daemon_log("cannot send '$header'-msg to $address , server not reachable", 5); + return 1; + } + + # send xml msg + print $socket $crypted_msg."\n"; + + close $socket; + + daemon_log("send '$header'-msg to $address", 1); + daemon_log("message:\n$msg_xml", 8); + return 0; +} + + +#=== FUNCTION ================================================================ +# NAME: get_content_from_xml_hash +# PARAMETERS: xml_ref - ref - reference of the xml hash +# element - string - key of the value you want +# RETURNS: value - string - if key is either header, target or source +# value - list - for all other keys in xml hash +# DESCRIPTION: +#=============================================================================== +sub get_content_from_xml_hash { + my ($xml_ref, $element) = @_ ; + #my $result = $main::xml_ref->{$element}; + #if( $element eq "header" || $element eq "target" || $element eq "source") { + # return @$result[0]; + #} + my @result = $xml_ref->{$element}; + return \@result; +} + + +#=== FUNCTION ================================================================ +# NAME: add_content2xml_hash +# PARAMETERS: xml_ref - ref - reference to a hash from function create_xml_hash +# element - string - key for the hash +# content - string - value for the hash +# RETURNS: nothing +# DESCRIPTION: add key-value pair to xml_ref, if key alread exists, +# then append value to list +#=============================================================================== +sub add_content2xml_hash { + my ($xml_ref, $element, $content) = @_; + if(not exists $$xml_ref{$element} ) { + $$xml_ref{$element} = []; + } + my $tmp = $$xml_ref{$element}; + push(@$tmp, $content); + return; +} + + +#=== FUNCTION ================================================================ +# NAME: create_xml_string +# PARAMETERS: xml_hash - hash - hash from function create_xml_hash +# RETURNS: xml_string - string - xml string representation of the hash +# DESCRIPTION: transform the hash to a string using XML::Simple module +#=============================================================================== +sub create_xml_string { + my ($xml_hash) = @_ ; + my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml'); + #$xml_string =~ s/[\n]+//g; + #daemon_log("create_xml_string:",7); + #daemon_log("$xml_string\n", 7); + return $xml_string; +} + + +#=== FUNCTION ================================================================ +# NAME: encrypt_msg +# PARAMETERS: msg - string - message to encrypt +# my_cipher - ref - reference to a Crypt::Rijndael object +# RETURNS: crypted_msg - string - crypted message +# DESCRIPTION: crypts the incoming message with the Crypt::Rijndael module +#=============================================================================== +sub encrypt_msg { + my ($msg, $my_cipher) = @_; + if(not defined $my_cipher) { print "no cipher object\n"; } + $msg = "\0"x(16-length($msg)%16).$msg; + $msg = $my_cipher->encrypt($msg); + chomp($msg = &encode_base64($msg)); + return $msg; +} + + +#=== FUNCTION ================================================================ +# NAME: decrypt_msg +# PARAMETERS: crypted_msg - string - message to decrypt +# my_cipher - ref - reference to a Crypt::Rijndael object +# RETURNS: msg - string - decrypted message +# DESCRIPTION: decrypts the incoming message with the Crypt::Rijndael module +#=============================================================================== +sub decrypt_msg { + my ($msg, $my_cipher) = @_ ; + if(defined $msg && defined $my_cipher) { + $msg = &decode_base64($msg); + } + $msg = $my_cipher->decrypt($msg); + $msg =~ s/\0*//g; + return $msg; +} + + +#=== FUNCTION ================================================================ +# NAME: create_ciphering +# PARAMETERS: passwd - string - used to create ciphering +# RETURNS: cipher - object +# DESCRIPTION: creates a Crypt::Rijndael::MODE_CBC object with passwd as key +#=============================================================================== +sub create_ciphering { + my ($passwd) = @_; + $passwd = substr(md5_hex("$passwd") x 32, 0, 32); + my $iv = substr(md5_hex('GONICUS GmbH'),0, 16); + + #daemon_log("iv: $iv", 7); + #daemon_log("key: $passwd", 7); + my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC()); + $my_cipher->set_iv($iv); + return $my_cipher; +} + + +#=== 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 get_time { + 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; + $month+=1; + $month = $month < 10 ? $month = "0".$month : $month; + $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday; + $year+=1900; + return "$year$month$monthday$hours$minutes$seconds"; + +} + + +#=== FUNCTION ================================================================ +# NAME: send_msg +# DESCRIPTION: Send a message to a destination +# PARAMETERS: [header] Name of the header +# [from] sender ip +# [to] recipient ip +# [data] Hash containing additional attributes for the xml +# package +# RETURNS: nothing +#=============================================================================== +sub send_msg ($$$$$) { + my ($header, $from, $to, $data, $hostkey) = @_; + + my $out_hash = &create_xml_hash($header, $from, $to); + + while ( my ($key, $value) = each(%$data) ) { + if(ref($value) eq 'ARRAY'){ + map(&add_content2xml_hash($out_hash, $key, $_), @$value); + } else { + &add_content2xml_hash($out_hash, $key, $value); + } + } + + &send_msg_hash2address($out_hash, $to, $hostkey); +} + +1; diff --git a/gosa-si/modules/ServerPackages.pm b/gosa-si/modules/ServerPackages.pm new file mode 100644 index 000000000..95baac87a --- /dev/null +++ b/gosa-si/modules/ServerPackages.pm @@ -0,0 +1,890 @@ +package ServerPackages; + +use Exporter; +@ISA = ("Exporter"); + +# Each module has to have a function 'process_incoming_msg'. This function works as a interface to gosa-sd and receives the msg hash from gosa-sd. 'process_incoming_function checks, wether it has a function to process the incoming msg and forward the msg to it. + + +use strict; +use warnings; +use GOSA::GosaSupportDaemon; +use IO::Socket::INET; +use XML::Simple; +use Data::Dumper; +use Net::LDAP; +use Socket qw/PF_INET SOCK_DGRAM inet_ntoa sockaddr_in/; + +BEGIN{} +END {} + +my ($known_clients_file_name); +my ($server_activ, $server_ip, $server_mac_address, $server_port, $server_passwd, $max_clients, $ldap_uri, $ldap_base, $ldap_admin_dn, $ldap_admin_password); +my ($bus_activ, $bus_passwd, $bus_ip, $bus_port); +my $server; +my $network_interface; +my $no_bus; +my (@ldap_cfg, @pam_cfg, @nss_cfg, $goto_admin, $goto_secret); + + +my %cfg_defaults = +( +"server" => + {"server_activ" => [\$server_activ, "on"], + "server_ip" => [\$server_ip, "0.0.0.0"], + "server_mac_address" => [\$server_mac_address, ""], + "server_port" => [\$server_port, "20081"], + "server_passwd" => [\$server_passwd, ""], + "max_clients" => [\$max_clients, 100], + "ldap_uri" => [\$ldap_uri, ""], + "ldap_base" => [\$ldap_base, ""], + "ldap_admin_dn" => [\$ldap_admin_dn, ""], + "ldap_admin_password" => [\$ldap_admin_password, ""], + }, +"bus" => + {"bus_activ" => [\$bus_activ, "on"], + "bus_passwd" => [\$bus_passwd, ""], + "bus_ip" => [\$bus_ip, ""], + "bus_port" => [\$bus_port, "20080"], + }, +); + +### START ##################################################################### + +# read configfile and import variables +&read_configfile(); + +# detect interfaces and mac address +$network_interface= &get_interface_for_ip($server_ip); +$server_mac_address= &get_mac($network_interface); + +&main::daemon_log("server ip address detected: $server_ip", 1); +&main::daemon_log("server mac address detected: $server_mac_address", 1); + +# complete addresses +my $server_address = "$server_ip:$server_port"; +my $bus_address = "$bus_ip:$bus_port"; + +# create general settings for this module +my $xml = new XML::Simple(); + +## open server socket +#if($server_activ eq "on"){ +# &main::daemon_log(" ", 1); +# $server = IO::Socket::INET->new(LocalPort => $server_port, +# Type => SOCK_STREAM, +# Reuse => 1, +# Listen => 20, +# ); +# if(not defined $server){ +# &main::daemon_log("cannot be a tcp server at $server_port : $@"); +# die; +# } else { +# &main::daemon_log("start server: $server_address", 1); +# } +#} +# +# +## register at bus +#if ($main::no_bus > 0) { +# $bus_activ = "off" +#} +#if($bus_activ eq "on") { +# &main::daemon_log(" ", 1); +# ®ister_at_bus(); +#} + +### functions ################################################################# + + +sub get_module_info { + my @info = ($server_address, + $server_passwd, + $server, + $server_activ, + "socket", + ); + return \@info; +} + + +#=== FUNCTION ================================================================ +# NAME: read_configfile +# PARAMETERS: cfg_file - string - +# RETURNS: nothing +# DESCRIPTION: read cfg_file and set variables +#=============================================================================== +sub read_configfile { + my $cfg; + if( defined( $main::cfg_file) && ( length($main::cfg_file) > 0 )) { + if( -r $main::cfg_file ) { + $cfg = Config::IniFiles->new( -file => $main::cfg_file ); + } else { + print STDERR "Couldn't read config file!"; + } + } else { + $cfg = Config::IniFiles->new() ; + } + foreach my $section (keys %cfg_defaults) { + foreach my $param (keys %{$cfg_defaults{ $section }}) { + my $pinfo = $cfg_defaults{ $section }{ $param }; + ${@$pinfo[0]} = $cfg->val( $section, $param, @$pinfo[1] ); + } + } + + # Read non predefined sections + my $param; + if ($cfg->SectionExists('ldap')){ + foreach $param ($cfg->Parameters('ldap')){ + push (@ldap_cfg, "$param ".$cfg->val('ldap', $param)); + } + } + if ($cfg->SectionExists('pam_ldap')){ + foreach $param ($cfg->Parameters('pam_ldap')){ + push (@pam_cfg, "$param ".$cfg->val('pam_ldap', $param)); + } + } + if ($cfg->SectionExists('nss_ldap')){ + foreach $param ($cfg->Parameters('nss_ldap')){ + push (@nss_cfg, "$param ".$cfg->val('nss_ldap', $param)); + } + } + if ($cfg->SectionExists('goto')){ + $goto_admin= $cfg->val('goto', 'terminal_admin'); + $goto_secret= $cfg->val('goto', 'terminal_secret'); + } else { + $goto_admin= undef; + $goto_secret= undef; + } + +} + +#=== FUNCTION ================================================================ +# NAME: get_interface_for_ip +# PARAMETERS: ip address (i.e. 192.168.0.1) +# RETURNS: array: list of interfaces if ip=0.0.0.0, matching interface if found, undef else +# 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; + } + } + } + } + return $result; +} + +#=== FUNCTION ================================================================ +# NAME: get_interfaces +# PARAMETERS: none +# RETURNS: (list of interfaces) +# DESCRIPTION: Uses proc fs (/proc/net/dev) to get list of interfaces. +#=============================================================================== +sub get_interfaces { + my @result; + my $PROC_NET_DEV= ('/proc/net/dev'); + + open(PROC_NET_DEV, "<$PROC_NET_DEV") + or die "Could not open $PROC_NET_DEV"; + + my @ifs = ; + + close(PROC_NET_DEV); + + # 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; + } + + return @result; +} + +#=== FUNCTION ================================================================ +# NAME: get_mac +# PARAMETERS: interface name (i.e. eth0) +# RETURNS: (mac address) +# DESCRIPTION: Uses ioctl to get mac address directly from system. +#=============================================================================== +sub get_mac { + my $ifreq= shift; + my $result; + if ($ifreq && length($ifreq) > 0) { + if($ifreq eq "all") { + $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 ($server_mac_address and length($server_mac_address) > 0) { + $result= $server_mac_address; + } + + socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip') + or die "socket: $!"; + + 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; + } + } + } + } + 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: 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; +# } +# &main::daemon_log("open_socket to: $PeerAddr", 7); +# return $socket; +#} + +#=== FUNCTION ================================================================ +# NAME: register_at_bus +# PARAMETERS: nothing +# RETURNS: nothing +# DESCRIPTION: creates an entry in known_daemons and send a 'here_i_am' msg to bus +#=============================================================================== +sub register_at_bus { + + # add bus to known_server_db + my $res = $main::known_server_db->add_dbentry( {table=>'known_server', + primkey=>'hostname', + hostname=>$bus_address, + status=>'bus', + hostkey=>$bus_passwd, + timestamp=>&get_time, + } ); + my $msg_hash = &create_xml_hash("here_i_am", $server_address, $bus_address); + my $answer = ""; + $answer = &send_msg_hash2address($msg_hash, $bus_address, $bus_passwd); + if ($answer == 0) { + &main::daemon_log("register at bus: $bus_address", 1); + } else { + &main::daemon_log("unable to send 'register'-msg to bus '$bus_address': $answer", 1); + } + return; +} + +#=== FUNCTION ================================================================ +# NAME: process_incoming_msg +# PARAMETERS: crypted_msg - string - incoming crypted message +# RETURNS: nothing +# DESCRIPTION: handels the proceeded distribution to the appropriated functions +#=============================================================================== +sub process_incoming_msg { + my ($crypted_msg) = @_ ; + if(not defined $crypted_msg) { + &main::daemon_log("function 'process_incoming_msg': got no msg", 7); + } + + &main::daemon_log("ServerPackages: incoming msg: \n$crypted_msg", 8); + + $crypted_msg =~ /^([\s\S]*?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)\.(\d{1,3}?)$/; + $crypted_msg = $1; + my $host="0.0.0.0"; + if($1 && $2 && $3 && $4) { + $host = sprintf("%s.%s.%s.%s", $2, $3, $4, $5); + } + + my $msg; + my $msg_hash; + my $host_name; + my $host_key; + + # check wether incoming msg is a new msg + $host_name = $server_address; + $host_key = $server_passwd; + &main::daemon_log("ServerPackage: host_name: $host_name", 7); + &main::daemon_log("ServerPackage: host_key: $host_key", 7); + eval{ + my $key_cipher = &create_ciphering($host_key); + $msg = &decrypt_msg($crypted_msg, $key_cipher); + $msg_hash = &transform_msg2hash($msg); + }; + if($@) { + &main::daemon_log("ServerPackage: deciphering raise error", 7); + &main::daemon_log("$@", 8); + $msg = undef; + $msg_hash = undef; + $host_name = undef; + $host_key = undef; + } + + # check wether incoming msg is from a known_server + if( not defined $msg ) { + my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server'} ); + while( my ($hit_num, $hit) = each %{ $query_res } ) { + $host_name = $hit->{hostname}; + if( not $host_name =~ "^$host") { + next; + } + $host_key = $hit->{hostkey}; + &main::daemon_log("ServerPackage: host_name: $host_name", 7); + &main::daemon_log("ServerPackage: host_key: $host_key", 7); + eval{ + my $key_cipher = &create_ciphering($host_key); + $msg = &decrypt_msg($crypted_msg, $key_cipher); + $msg_hash = &transform_msg2hash($msg); + }; + if($@) { + &main::daemon_log("ServerPackage: deciphering raise error", 7); + &main::daemon_log("$@", 8); + $msg = undef; + $msg_hash = undef; + $host_name = undef; + $host_key = undef; + } else { + last; + } + } + } + + # check wether incoming msg is from a known_client + if( not defined $msg ) { + my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients'} ); + while( my ($hit_num, $hit) = each %{ $query_res } ) { + $host_name = $hit->{hostname}; + if( not $host_name =~ "^$host") { + next; + } + $host_key = $hit->{hostkey}; + &main::daemon_log("ServerPackage: host_name: $host_name", 7); + &main::daemon_log("ServerPackage: host_key: $host_key", 7); + eval{ + my $key_cipher = &create_ciphering($host_key); + $msg = &decrypt_msg($crypted_msg, $key_cipher); + $msg_hash = &transform_msg2hash($msg); + }; + if($@) { + &main::daemon_log("ServerPackage: deciphering raise error", 7); + &main::daemon_log("$@", 8); + $msg = undef; + $msg_hash = undef; + $host_name = undef; + $host_key = undef; + } else { + last; + } + } + } + + if( not defined $msg ) { + &main::daemon_log("WARNING: ServerPackage do not understand the message:", 5); + &main::daemon_log("$@", 7); + return; + } + + # process incoming msg + my $header = @{$msg_hash->{header}}[0]; + my $source = @{$msg_hash->{source}}[0]; + + &main::daemon_log("receive '$header' at ServerPackages from $host", 1); + &main::daemon_log("ServerPackages: msg to process: \n$msg", 5); + + my @targets = @{$msg_hash->{target}}; + my $len_targets = @targets; + if ($len_targets == 0){ + &main::daemon_log("ERROR: ServerPackages: no target specified for msg $header", 1); + + } elsif ($len_targets == 1){ + # we have only one target symbol + my $target = $targets[0]; + &main::daemon_log("SeverPackages: msg is for: $target", 7); + + # msg is for server + if ($header eq 'new_passwd'){ &new_passwd($msg_hash)} + elsif ($header eq 'here_i_am') { &here_i_am($msg_hash)} + elsif ($header eq 'who_has') { &who_has($msg_hash) } + elsif ($header eq 'who_has_i_do') { &who_has_i_do($msg_hash)} + elsif ($header eq 'update_status') { &update_status($msg_hash) } + elsif ($header eq 'got_ping') { &got_ping($msg_hash)} + elsif ($header eq 'get_load') { &execute_actions($msg_hash)} + else { + if ($target eq "*") { + # msg is for all clients + my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients'} ); + 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); + } + + } else { + # msg is for one host + my $host_key; + + + if( not defined $host_key ) { + my $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients', hostname=>$target} ); + if( 1 == keys %{$query_res} ) { + $host_key = $query_res->{1}->{host_key}; + } + } + + if( not defined $host_key ) { + my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server', hostname=>$target} ); + if( 1 == keys %{$query_res} ) { + $host_key = $query_res->{1}->{host_key}; + } + } + + if( not defined $host_key ) { + &main::daemon_log("ERROR: ServerPackages: target '".$target. + "' is not known neither in known_clients nor in known_server",1); + } else { + &send_msg_hash2address($msg_hash, $target, $host_key); + } + } + } + + } elsif ($len_targets > 1 ) { + # we have more than one target + # TODO to be implemented + } + + return ; +} + + +#=== 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 $target = @{$msg_hash->{target}}[0]; + my $header = @{$msg_hash->{header}}[0]; + + if(exists $main::known_daemons->{$source}) { + &main::add_content2known_daemons(hostname=>$source, status=>$header); + } else { + &main::add_content2known_clients(hostname=>$source, status=>$header); + } + + return; +} + + +#=== FUNCTION ================================================================ +# NAME: new_passwd +# PARAMETERS: msg_hash - ref - hash from function create_xml_hash +# RETURNS: nothing +# DESCRIPTION: process this incoming message +#=============================================================================== +sub new_passwd { + my ($msg_hash) = @_; + + my $header = @{$msg_hash->{header}}[0]; + my $source_name = @{$msg_hash->{source}}[0]; + my $source_key = @{$msg_hash->{new_passwd}}[0]; + my $query_res; + + # check known_clients_db + $query_res = $main::known_clients_db->select_dbentry( {table=>'known_clients', hostname=>$source_name} ); + if( 1 == keys %{$query_res} ) { + my $update_hash = { table=>'known_clients' }; + $update_hash->{where} = [ { hostname=>[$source_name] } ]; + $update_hash->{update} = [ { + hostkey=>[$source_key], + timestamp=>[&get_time], + } ]; + my $res = $main::known_clients_db->update_dbentry( $update_hash ); + + my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name); + &send_msg_hash2address($hash, $source_name, $source_key); + return; + } + + # check known_server_db + $query_res = $main::known_server_db->select_dbentry( {table=>'known_server', hostname=>$source_name } ); + if( 1 == keys %{$query_res} ) { + my $update_hash = { table=>'known_server' }; + $update_hash->{where} = [ { hostname=>[$source_name] } ]; + $update_hash->{update} = [ { + hostkey=>[$source_key], + timestamp=>[&get_time], + } ]; + my $res = $main::known_server_db->update_dbentry( $update_hash ); + + my $hash = &create_xml_hash("confirm_new_passwd", $server_address, $source_name); + &send_msg_hash2address($hash, $source_name, $source_key); + return; + } + + &main::daemon_log("ERROR: $source_name not known for '$header'-msg", 1); + return; +} + + +sub send_msg_hash { + my ($hash, $host_name, $host_key); + + + my $answer = &send_msg_hash2address($hash, $host_name, $host_key); + + return; +} + + +#=== FUNCTION ================================================================ +# NAME: here_i_am +# PARAMETERS: msg_hash - hash - hash from function create_xml_hash +# RETURNS: nothing +# DESCRIPTION: process this incoming message +#=============================================================================== +sub here_i_am { + my ($msg_hash) = @_; + + my $source = @{$msg_hash->{source}}[0]; + my $mac_address = @{$msg_hash->{mac_address}}[0]; + my $out_hash; + + # number of known clients + my $nu_clients = keys %{ $main::known_clients_db->select_dbentry( {table=>'known_clients'} ) }; + + # check wether client address or mac address is already known + if (exists $main::known_clients->{$source}) { + &main::daemon_log("WARNING: $source is already known as a client", 1); + &main::daemon_log("WARNING: values for $source are being overwritten", 1); + $nu_clients --; + } + + # number of actual activ clients + my $act_nu_clients = $nu_clients; + + &main::daemon_log("number of actual activ clients: $act_nu_clients", 5); + &main::daemon_log("number of maximal allowed clients: $max_clients", 5); + + if($max_clients <= $act_nu_clients) { + my $out_hash = &create_xml_hash("denied", $server_address, $source); + &add_content2xml_hash($out_hash, "denied", "I_cannot_take_any_more_clients!"); + my $passwd = @{$msg_hash->{new_passwd}}[0]; + &send_msg_hash2address($out_hash, $source, $passwd); + return; + } + + # new client accepted + my $new_passwd = @{$msg_hash->{new_passwd}}[0]; + + # create entry in known_clients + my $events = @{$msg_hash->{events}}[0]; + + # add entry to known_clients_db + my $res = $main::known_clients_db->add_dbentry( {table=>'known_clients', + primkey=>'hostname', + hostname=>$source, + events=>$events, + macaddress=>$mac_address, + status=>'registered', + hostkey=>$new_passwd, + timestamp=>&get_time, + } ); + + if ($res != 0) { + &main::daemon_log("ERROR: cannot add entry to known_clients: $res"); + return; + } + + # return acknowledgement to client + $out_hash = &create_xml_hash("registered", $server_address, $source); + &send_msg_hash2address($out_hash, $source, $new_passwd); + + # notify registered client to bus + if( $bus_activ eq "on") { + # fetch actual bus key + my $query_res = $main::known_server_db->select_dbentry( {table=>'known_server'} ); + my $hostkey = $query_res->{1}->{hostkey}; + + # send update msg to bus + $out_hash = &create_xml_hash("new_client", $server_address, $bus_address, $source); + &send_msg_hash2address($out_hash, $bus_address, $hostkey); + + &main::daemon_log("send bus msg that client '$source' has registerd at server '$server_address'", 3); + } + + # give the new client his ldap config + &new_ldap_config($source); + + return; +} + + +#=== FUNCTION ================================================================ +# NAME: who_has +# PARAMETERS: msg_hash - hash - hash from function create_xml_hash +# RETURNS: nothing +# DESCRIPTION: process this incoming message +#=============================================================================== +sub who_has { + my ($msg_hash) = @_ ; + + # what is your search pattern + my $search_pattern = @{$msg_hash->{who_has}}[0]; + my $search_element = @{$msg_hash->{$search_pattern}}[0]; + &main::daemon_log("who_has-msg looking for $search_pattern $search_element", 7); + + # scanning known_clients for search_pattern + my @host_addresses = keys %$main::known_clients; + my $known_clients_entries = length @host_addresses; + my $host_address; + foreach my $host (@host_addresses) { + my $client_element = $main::known_clients->{$host}->{$search_pattern}; + if ($search_element eq $client_element) { + $host_address = $host; + last; + } + } + + # search was successful + if (defined $host_address) { + my $source = @{$msg_hash->{source}}[0]; + my $out_msg = &create_xml_hash("who_has_i_do", $server_address, $source, "mac_address"); + &add_content2xml_hash($out_msg, "mac_address", $search_element); + &send_msg_hash2address($out_msg, $bus_address); + } + return; +} + + +sub who_has_i_do { + my ($msg_hash) = @_ ; + my $header = @{$msg_hash->{header}}[0]; + my $source = @{$msg_hash->{source}}[0]; + my $search_param = @{$msg_hash->{$header}}[0]; + my $search_value = @{$msg_hash->{$search_param}}[0]; + print "\ngot msg $header:\nserver $source has client with $search_param $search_value\n"; +} + + +#=== FUNCTION ================================================================ +# NAME: new_ldap_config +# PARAMETERS: address - string - ip address and port of a host +# RETURNS: nothing +# DESCRIPTION: send to address the ldap configuration found for dn gotoLdapServer +#=============================================================================== +sub new_ldap_config { + my ($address) = @_ ; + + my $res = $main::known_clients_db->select_dbentry( { table=>'known_clients', hostname=>$address } ); + + # check hit + my $hit_counter = keys %{$res}; + if( not $hit_counter == 1 ) { + &main::daemon_log("ERROR: more or no hit found in known_clients_db by query by '$address'", 1); + } + + my $macaddress = $res->{1}->{macaddress}; + my $hostkey = $res->{1}->{hostkey}; + + if (not defined $macaddress) { + &main::daemon_log("ERROR: no mac address found for client $address", 1); + return; + } + + # Build LDAP connection + my $ldap = Net::LDAP->new($ldap_uri); + if( not defined $ldap ) { + &main::daemon_log("ERROR: cannot connect to ldap: $ldap_uri", 1); + return; + } + + + # Bind to a directory with dn and password + my $mesg= $ldap->bind($ldap_admin_dn, $ldap_admin_password); + + # Perform search + $mesg = $ldap->search( base => $ldap_base, + scope => 'sub', + attrs => ['dn', 'gotoLdapServer'], + filter => "(&(objectClass=GOhard)(macaddress=$macaddress))"); + $mesg->code && die $mesg->error; + + # Sanity check + if ($mesg->count != 1) { + &main::daemon_log("WARNING: client mac address $macaddress not found/not unique in ldap search", 1); + &main::daemon_log("\tbase: $ldap_base", 1); + &main::daemon_log("\tscope: sub", 1); + &main::daemon_log("\tattrs: dn, gotoLdapServer", 1); + &main::daemon_log("\tfilter: (&(objectClass=GOhard)(macaddress=$macaddress))", 1); + return; + } + + my $entry= $mesg->entry(0); + my $dn= $entry->dn; + my @servers= $entry->get_value("gotoLdapServer"); + my @ldap_uris; + my $server; + my $base; + + # Do we need to look at an object class? + if ($#servers < 1){ + $mesg = $ldap->search( base => $ldap_base, + scope => 'sub', + attrs => ['dn', 'gotoLdapServer'], + filter => "(&(objectClass=gosaGroupOfNames)(member=$dn))"); + $mesg->code && die $mesg->error; + + # Sanity check + if ($mesg->count != 1) { + &main::daemon_log("WARNING: no LDAP information found for client mac $macaddress", 1); + return; + } + + $entry= $mesg->entry(0); + $dn= $entry->dn; + @servers= $entry->get_value("gotoLdapServer"); + } + + @servers= sort (@servers); + + foreach $server (@servers){ + $base= $server; + $server =~ s%^[^:]+:[^:]+:(ldap.*://[^/]+)/.*$%$1%; + $base =~ s%^[^:]+:[^:]+:ldap.*://[^/]+/(.*)$%$1%; + push (@ldap_uris, $server); + } + + # Unbind + $mesg = $ldap->unbind; + + # Assemble data package + my %data = ( 'ldap_uri' => \@ldap_uris, 'ldap_base' => $base, + 'ldap_cfg' => \@ldap_cfg, 'pam_cfg' => \@pam_cfg,'nss_cfg' => \@nss_cfg ); + + # Need to append GOto settings? + if (defined $goto_admin and defined $goto_secret){ + $data{'goto_admin'}= $goto_admin; + $data{'goto_secret'}= $goto_secret; + } + + # Send information + send_msg("new_ldap_config", $server_address, $address, \%data, $hostkey); + + return; +} + + +#=== FUNCTION ================================================================ +# NAME: execute_actions +# PARAMETERS: msg_hash - hash - hash from function create_xml_hash +# RETURNS: nothing +# DESCRIPTION: invokes the script specified in msg_hash which is located under +# /etc/gosad/actions +#=============================================================================== +sub execute_actions { + my ($msg_hash) = @_ ; + my $configdir= '/etc/gosad/actions/'; + my $result; + + my $header = @{$msg_hash->{header}}[0]; + my $source = @{$msg_hash->{source}}[0]; + my $target = @{$msg_hash->{target}}[0]; + + if((not defined $source) + && (not defined $target) + && (not defined $header)) { + &main::daemon_log("ERROR: Entries missing in XML msg for gosad actions under /etc/gosad/actions"); + } else { + my $parameters=""; + my @params = @{$msg_hash->{$header}}; + my $params = join(", ", @params); + &main::daemon_log("execute_actions: got parameters: $params", 5); + + if (@params) { + foreach my $param (@params) { + my $param_value = (&get_content_from_xml_hash($msg_hash, $param))[0]; + &main::daemon_log("execute_actions: parameter -> value: $param -> $param_value", 7); + $parameters.= " ".$param_value; + } + } + + my $cmd= $configdir.$header."$parameters"; + &main::daemon_log("execute_actions: executing cmd: $cmd", 7); + $result= ""; + open(PIPE, "$cmd 2>&1 |"); + while() { + $result.=$_; + } + close(PIPE); + } + + # process the event result + + + return; +} + + +1; diff --git a/gosa-si/modules/TestModule.pm b/gosa-si/modules/TestModule.pm new file mode 100644 index 000000000..90c8d6abb --- /dev/null +++ b/gosa-si/modules/TestModule.pm @@ -0,0 +1,76 @@ +package TestModule; + +use Exporter; +@ISA = ("Exporter"); + +use strict; +use warnings; +use GosaSupportDaemon; + +BEGIN{ +} + +END{} + +### START ########## + + +sub get_module_tags { + + # lese config file aus dort gibt es eine section Basic + # dort stehen drei packettypen, für die sich das modul anmelden kann, gosa-admin-packages, + # server-packages, client-packages + my %tag_hash = (gosa_admin_packages => "yes", + server_packages => "yes", + client_packages => "yes", + ); + return \%tag_hash; +} + + +sub process_incoming_msg { + my ($crypted_msg) = @_ ; + if(not defined $crypted_msg) { + &main::daemon_log("function 'process_incoming_msg': got no msg", 7); + } + &main::daemon_log("TestModule: crypted_msg:$crypted_msg", 7); + &main::daemon_log("TestModule: crypted_msg len:".length($crypted_msg), 7); + + + # chomp address from host who send the message + $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); + + my $gosa_passwd = $main::gosa_passwd; + my $gosa_cipher = &create_ciphering($gosa_passwd); + + my $in_msg; + my $in_hash; + eval{ + $in_msg = &decrypt_msg($crypted_msg, $gosa_cipher); + $in_hash = &transform_msg2hash($in_msg); + }; + if ($@) { + &main::daemon_log("TestModul konnte msg nicht entschlüsseln:", 5); + &main::daemon_log("$@", 7); + return; + } + + my $header = @{$in_hash->{header}}[0]; + my $ip_address = @{$in_hash->{target}}[0]; + + + # hier kommt die logik suche den entsprechenden daemon, der den client target hat + + my $out_hash = &create_xml_hash("halt", $main::server_address, $ip_address); + + &send_msg_hash2address($out_hash, $ip_address); + + &main::daemon_log("TestModul: ip $ip_address bekommt $header "); + return ; +} + + + + diff --git a/gosa-si/server.conf b/gosa-si/server.conf new file mode 100644 index 000000000..3386c00a6 --- /dev/null +++ b/gosa-si/server.conf @@ -0,0 +1,32 @@ +[general] +log_file = /var/log/gosa-si-server.log +pid_file = /var/run/gosa-si-server.pid +child_max = 10 +child_min = 2 +child_timeout = 10 +job_queue_timeout = 5 + +[bus] +bus_activ = on +bus_passwd = secret-bus-password +bus_ip = 127.0.0.1 +bus_port = 20080 + +[server] +server_activ = on +server_port = 20081 +server_passwd = secret-server-password +max_clients = 5 +server_event_dir = /usr/lib/gosa-si/server/events + +[arp] +arp_activ = off +arp_fifo_path = /var/run/gosa-si/arp-notify + +[gosa] +gosa_activ = on +gosa_ip = 127.0.0.1 +gosa_port = 20082 +gosa_passwd = secret-gosa-password +gosa_timeout = 5 + diff --git a/gosa-si/server/events/ping b/gosa-si/server/events/ping new file mode 100755 index 000000000..f8ae99606 --- /dev/null +++ b/gosa-si/server/events/ping @@ -0,0 +1,26 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use GosaSupportDaemon; + + +# transform msg to hash +my $hash = &transform_msg2hash($ARGV[0]); + +# extract from hash all what you need +my $header = @{$hash->{header}}[0]; +my $source = @{$hash->{source}}[0]; +my $target = @{$hash->{target}}[0]; +my $jobdb_id = @{$hash->{jobdb_id}}[0]; + +# and do what ever you want + + +my $out_hash = &create_xml_hash("got_ping", "10.89.1.155:10001", "10.89.1.155:10000"); +if (defined $jobdb_id) { + &add_content2xml_hash($out_hash, 'jobdb_id', $jobdb_id); +} +my $out_xml = &create_xml_string($out_hash); +print $out_xml; + diff --git a/gosa-si/tests/client.php b/gosa-si/tests/client.php new file mode 100755 index 000000000..8c715148d --- /dev/null +++ b/gosa-si/tests/client.php @@ -0,0 +1,43 @@ +#!/usr/bin/php5 -q +setEncryptionKey("secret-gosa-password"); + +if($sock->connected()){ + /* Prepare a hunge bunch of data to be send */ + +# add +#$data = "
gosa_ping
10.89.1.155:2008210.89.1.155:20080
"; +# $data = "
job_ping
10.89.1.155:2008300:1B:77:04:8A:6C 19700101000000
"; +# $data = "
job_sayHello
10.89.1.155:2008300:1B:77:04:8A:6C 20130102133900
"; +# $data = "
job_ping
10.89.1.155:2008300:1B:77:04:8A:6C 20130102133900
"; + +# delete + #$data = "
gosa_delete_jobdb_entry
headertag sayHello
"; + +# update + #$data = "
gosa_update_status_jobdb_entry
waiting processing
"; + #$data = "
gosa_update_status_jobdb_entry
waiting
"; + #$data = "
gosa_update_timestamp_jobdb_entry
20130123456789
"; + +# query +$data = "
gosa_query_jobdb
statuserror
"; + +# clear + #$data = "
gosa_clear_jobdb
"; + + $sock->write($data); + $answer = "nothing"; + $answer = $sock->read(); + echo ">>>$answer<<<\n"; + $sock->close(); +}else{ + echo "... FAILED!\n"; +} + +?> diff --git a/gosa-si/tests/sqlite-check.pl b/gosa-si/tests/sqlite-check.pl new file mode 100755 index 000000000..63f2ac6d8 --- /dev/null +++ b/gosa-si/tests/sqlite-check.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl +#=============================================================================== +# +# FILE: DBD-SQlite.pl +# +# USAGE: ./DBD-SQlite.pl +# +# DESCRIPTION: +# +# OPTIONS: --- +# REQUIREMENTS: --- +# BUGS: --- +# NOTES: --- +# AUTHOR: (), <> +# COMPANY: +# VERSION: 1.0 +# CREATED: 20.12.2007 08:54:52 CET +# REVISION: --- +#=============================================================================== + +use strict; +use warnings; +use GOSA::DBsqlite; + + +print "START\n"; +my $res; +my $db_name; + +$db_name = "/var/lib/gosa-si/jobs.db"; +if (-e $db_name) { + print "\n############################################################\n"; + $db_name =~ /\/([^\/]*?)\.db$/; + my $table_name = $1; + 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"; +} + + +$db_name = "/var/lib/gosa-si/known_clients.db"; +if (-e $db_name) { + print "\n############################################################\n"; + $db_name =~ /\/([^\/]*?)\.db$/; + my $table_name = $1; + + 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"; +} + + +$db_name = "/var/lib/gosa-si/known_server.db"; +if (-e $db_name) { + print "\n############################################################\n"; + $db_name =~ /\/([^\/]*?)\.db$/; + my $table_name = $1; + + 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"; +} + + +$db_name = "/var/lib/gosa-si/bus_known_server.db"; +if (-e $db_name) { + print "\n############################################################\n"; + $db_name =~ /\/([^\/]*?)\.db$/; + my $table_name = $1; + 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"; diff --git a/gosa-si/tests/testGOsa.pl b/gosa-si/tests/testGOsa.pl new file mode 100644 index 000000000..9ecb8f385 --- /dev/null +++ b/gosa-si/tests/testGOsa.pl @@ -0,0 +1,107 @@ +#!/usr/bin/perl +#=============================================================================== +# +# FILE: testGosa.pl +# +# USAGE: ./testGosa.pl +# +# DESCRIPTION: +# +# OPTIONS: --- +# REQUIREMENTS: --- +# BUGS: --- +# NOTES: --- +# AUTHOR: (), <> +# COMPANY: +# VERSION: 1.0 +# CREATED: 06.12.2007 14:31:37 CET +# REVISION: --- +#=============================================================================== + +use strict; +use warnings; +use IO::Socket::INET; +use Digest::MD5 qw(md5 md5_hex md5_base64); +use Crypt::Rijndael; +use MIME::Base64; + +sub create_ciphering { + my ($passwd) = @_; + + $passwd = substr(md5_hex("$passwd") x 32, 0, 32); + my $iv = substr(md5_hex('GONICUS GmbH'),0, 16); + print "iv: $iv\n"; + print "key: $passwd\n"; + + my $my_cipher = Crypt::Rijndael->new($passwd ,Crypt::Rijndael::MODE_CBC() ); + $my_cipher->set_iv($iv); + return $my_cipher; +} + +sub decrypt_msg { + my ($crypted_msg, $my_cipher) = @_ ; + $crypted_msg = &decode_base64($crypted_msg); + my $msg = $my_cipher->decrypt($crypted_msg); + return $msg; +} + +sub encrypt_msg { + my ($msg, $my_cipher) = @_; + if(not defined $my_cipher) { print "no cipher object\n"; } + $msg = "\0"x(16-length($msg)%16).$msg; + my $crypted_msg = $my_cipher->encrypt($msg); + chomp($crypted_msg = &encode_base64($crypted_msg)); + return $crypted_msg; +} + + + +my $gosa_server = IO::Socket::INET->new(LocalPort => "9999", + Type => SOCK_STREAM, + Reuse => 1, + Listen => 1, + ); + + + + + +my $client = $gosa_server->accept(); +my $other_end = getpeername($client); +if(not defined $other_end) { + print "client cannot be identified:"; +} else { + my ($port, $iaddr) = unpack_sockaddr_in($other_end); + my $actual_ip = inet_ntoa($iaddr); + print "accept client at gosa socket from $actual_ip\n"; + chomp(my $crypted_msg = <$client>); + print "crypted msg: <<<$crypted_msg<<<\n"; + + my $cipher = &create_ciphering("ferdinand_frost"); + + my $msg = &decrypt_msg($crypted_msg, $cipher); + print "msg: <<<$msg<<<\n"; + + print "\n#################################\n\n"; + + my $answer = "gosa answer: $msg"; + + print "answer: $answer\n"; + + my $out_cipher = &create_ciphering("ferdinand_frost"); + my $crypted_answer = &encrypt_msg($answer, $out_cipher); + + print $client $crypted_answer."\n"; + +} + +sleep(3); +close($client); + + + + + + + +