#################### main pod documentation begin ################### =head1 NAME Zymonic::Decryptor::MP - Zymonic Decryptor mod_perl Handler module =head1 SYNOPSIS TODO =head1 DESCRIPTION TODO =head1 INSTALLATION 1. When using ZymonicMP it's extremely important to make sure MaxClients is less than max number of connections allowed by Apache. =head1 USAGE =head1 BUGS None we're aware of... =head1 SUPPORT As in the license, Zymonic is provided without warranty or support unless purchased separately, however... If you email zymonic-support@zednax.com your issue will be noted and may receive a response. For security issues, please contact zymonic-security@zednax.com and someone will respond within 8 working hours. =head1 AUTHOR Alex Masidlover et al. CPAN ID: MODAUTHOR Zednax Limited alex.masidlover@zednax.com http://www.zednax.com =head1 COPYRIGHT This program is free software licensed under the... Zymonic Public License 1.0 The full text of the license can be found in the LICENSE file included with this module. Other licenses may be acceptable if including parts of Zymonic in larger projects, please contact Zednax for details. =head1 SEE ALSO perl(1). =cut #################### main pod documentation end ################### package Zymonic::Decryptor::MP; use Zymonic::ModPerl; use strict; use warnings; # ZYMONIC USE use Zymonic::Decryptor::Server; use Zymonic::Config; use Zymonic::Decryptor::Message; use Module::Reload; use Zymonic; use Zymonic::Utils qw(clean debug rethrow_exception clear_module_exists death_handler); use Storable qw(nfreeze); use JSON::XS; use IPC::MMA qw(:all); use IO::Handle; use POSIX qw(strftime); BEGIN { use Exporter (); use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = '0.01'; @ISA = qw(Exporter); # Give a hoot don't pollute, do not export more than needed by default @EXPORT = qw(); @EXPORT_OK = qw(); %EXPORT_TAGS = (); } our $MPhostname; our $MPfingerprint; #################### subroutine header begin #################### =head2 inner_handler Usage : ZymonicMP::inner_handler Purpose : Is a mod_perl response handler for Zymonic. The 'inner' version does the work and can be wrapped in an eval for exception handling purposes. Returns : a suitable response for mod_perl. Argument : a mod_perl reference Throws : nothing Comment : TODO See Also : =cut #################### subroutine header end #################### sub inner_handler : method { my ( $class, $r ) = @_; # Clear the globals $Zymonic::system = ''; $Zymonic::Utils::debug_function_nesting_level = 0; @Zymonic::Utils::debug_function_times = (); # something within the decryptor clears down the ENV which causes error on loading CGI::Apache2::Wrapper # see SR 11222 for more details on this # for now explicitly set the variables $Zymonic::ENV{MOD_PERL} = 2; $Zymonic::ENV{MOD_PERL_API_VERSION} = 2; # Create a cgi my $cgi = CGI::Apache2::Wrapper->new($r); # Config Vars my $saxon = 0; # XML out my $xmlout; # Global objects my $db; my $auth; # Clear @HISTORY first... Zymonic::Utils::clear_history(); my $protocol = ( ( defined( $Zymonic::ENV{HTTPS} ) and $Zymonic::ENV{HTTPS} eq 'on' ) ? 'https' : 'http' ); # Clean path $ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/sbin:/usr/sbin"; # set binmode for STDOUT and STDERR to handle unicode binmode STDOUT, ':utf8'; binmode STDERR, ':utf8'; # enable cache for table includes and relationship permissions $Zymonic::object_cache = { 'Zymonic::TableInclude' => {}, 'Zymonic::RelationshipPermissions' => {}, }; # Get $Zymonic::system and hostname; $Zymonic::system = clean( $cgi->param('ZZsystem') || $cgi->param('zzsystem'), "-_" ); my $hostname = clean( $r->hostname, "-_" ); debug("Zymonic starting... system: $Zymonic::system"); if ( ref( $Zymonic::ZCONFIG{$Zymonic::system} ) =~ /Config/ ) { $Zymonic::ZCONFIG{$Zymonic::system}->load_system_definition(); $Zymonic::ZCONFIG{$Zymonic::system}->load(); } else { $Zymonic::ZCONFIG{$Zymonic::system} = Zymonic::Config->new( parent => $class, system_name => $Zymonic::system, config_dir => "/etc/zymonic", ); } unless ( ref( $Zymonic::ZDECRYPTOR{$Zymonic::system} ) =~ /Decryptor/ ) { $Zymonic::ZDECRYPTOR{$Zymonic::system} = Zymonic::Decryptor::Server->new( config => $Zymonic::ZCONFIG{$Zymonic::system}, db => $Zymonic::ZCONFIG{$Zymonic::system}->{DB}, hostname => $hostname, ); } my $log_id = $Zymonic::ZDECRYPTOR{$Zymonic::system}->connection_start( clean( $ENV{REMOTE_ADDR}, "-_" ) ); my $in = ''; eval { local $SIG{__DIE__} = sub { death_handler( $_[0] ); }; # Get the data $in = $Zymonic::ZDECRYPTOR{$Zymonic::system}->receive($cgi); # Pass to the message handler Module::Reload->check; clear_module_exists(); my $mh = Zymonic::Decryptor::Message->new( xmldef => { class => $in->{messagetype} }, zname => $in->{messagetype}, decryptor_server => $Zymonic::ZDECRYPTOR{$Zymonic::system}, ); my $response = $mh->respond($in); # return the response. $r->print( encode_json($response) ); 1; } or do { my $exception = $@; my $error = ''; if ( ref($exception) and $exception->isa('Zymonic::Exception::Decryptor::Server::NoKey') ) { $error = 'Replacement failed - no key.'; } elsif ( ref($exception) and $exception->isa('Zymonic::Exception::Decryptor::Server::DataNotFound') ) { $error = 'Replacement failed - not found (id ' . $exception->{encrypted_id} . ')'; } elsif ( ref($exception) and $exception->isa('Zymonic::Exception::Decryptor::Server::DecryptFailed') ) { $error = 'Replacement failed - decrypt failed ' . "- error: $exception->{enc_error} - id: $exception->{encrypted_id} - data: $exception->{encrypted_data}"; } elsif ( ref($exception) and $exception->isa('Zymonic::Exception::Decryptor::Server::InvalidSystem') ) { $error = 'Replacement failed - system not recognised.'; } else { rethrow_exception($exception); } $Zymonic::ZDECRYPTOR{$Zymonic::system}->connection_log($error); $r->print( encode_json( { DSO_error => $error } ) ); }; $Zymonic::ZDECRYPTOR{$Zymonic::system}->connection_close($log_id); $Zymonic::system = ''; return Apache2::Const::OK; } #################### subroutine header begin #################### =head2 handler Usage : ZymonicMP::handler Purpose : Is a mod_perl response handler for Zymonic. Returns : a suitable response for mod_perl. Argument : a mod_perl reference Throws : nothing Comment : TODO See Also : =cut #################### subroutine header end #################### sub handler : method { open my $fh, ">>/var/log/decryptors/decryptor.$MPhostname.$$." . strftime( "%Y%m%d", localtime ) . ".log"; my $old_DEBUG_AS_SQLITE = $Zymonic::Utils::DEBUG_AS_SQLITE; $Zymonic::Utils::DEBUG_AS_SQLITE = ''; $fh->autoflush(1); $Zymonic::Utils::debugfile = $fh; my $resp = Zymonic::ModPerl::handler(@_); close($fh); $Zymonic::Utils::debugfile = ''; $Zymonic::Utils::DEBUG_AS_SQLITE = $old_DEBUG_AS_SQLITE; return $resp; } #################### subroutine header begin #################### =head2 post_config Usage : post_config() Purpose : Does post_config routines before apache children fork, specifically creating an MM segment. Returns : a suitable response for mod_perl. Argument : nothing Throws : nothing Comment : TODO See Also : =cut #################### subroutine header end #################### sub post_config : method { my $class = shift; die "No host name detected - $ENV{ZZhostname}" unless ( clean( $ENV{ZZhostname}, "-_" ) ); $MPhostname = clean( $ENV{ZZhostname}, "-_" ); $MPfingerprint = clean( $ENV{ZZfingerprint}, "\$:" ); die "No systems detected - $ENV{ZZStartSystems}" unless ( clean( $ENV{ZZStartSystems}, "_-" ) ); my $size = clean( $ENV{SharedMemSize} ) || 32768; open my $fh, ">>/var/log/decryptors/decryptor.$MPhostname.$$.parent.log"; $Zymonic::Utils::debugfile = $fh; my $old_DEBUG_AS_SQLITE = $Zymonic::Utils::DEBUG_AS_SQLITE; $Zymonic::Utils::DEBUG_AS_SQLITE = ''; Zymonic::ModPerl::post_config(); foreach my $system ( split( /,/, clean( $ENV{ZZStartSystems}, "_-" ) ) ) { # use system name as extra key, so the field refs don't overlap between systems my $zzd_tab = $Zymonic::ZCONFIG{$system}->get_table( 'zz_decryptors', { config => $Zymonic::ZCONFIG{$system} }, $system ); $zzd_tab->insert( { hostname => { value => $MPhostname }, d_posix_process_id => { value => $$ }, in_use => { value => 0 }, fingerprint => { value => $MPfingerprint || '' }, } ); } # setup the field factory $Zymonic::field_factory = Zymonic::FieldFactory->new(); debug("Creating shared memory segment, size: $size"); $Zymonic::ZMM = mm_create( $size, "/etc/zymonic/mm_apache_lockfile" ) or die "can't create shared memory: $! " . mm_error; my $kek_hash = mm_make_hash($Zymonic::ZMM) or die "Can't make KEK hash: " . mm_error; tie %Zymonic::ZKEK, "IPC::MM::Hash", $kek_hash or die "Can't tie KEK hash: $!" . mm_error; my $sim_hash = mm_make_hash($Zymonic::ZMM) or die "Can't make SIM hash: " . mm_error; tie %Zymonic::SIM, "IPC::MM::Hash", $sim_hash or die "Can't tie SIM hash: $!" . mm_error; $Zymonic::SIM{'count'} = 0; $Zymonic::SIM{'last_check'} = 0; $Zymonic::ZKEK{'parent_pid'} = $$; debug("post_config complete."); close($fh); $Zymonic::Utils::DEBUG_AS_SQLITE = $old_DEBUG_AS_SQLITE; return Apache2::Const::OK; } END { if ( $Zymonic::ZKEK{'parent_pid'} == $$ ) { open my $fh, ">>/var/log/decryptors/decryptor.$MPhostname.$$.parent.log"; $Zymonic::Utils::debugfile = $fh; my $old_DEBUG_AS_SQLITE = $Zymonic::Utils::DEBUG_AS_SQLITE; $Zymonic::Utils::DEBUG_AS_SQLITE = ''; debug("Detected apache shutdown"); foreach my $system ( split( /,/, clean( $ENV{ZZStartSystems}, "_-" ) ) ) { $Zymonic::ZCONFIG{$system}->{DB}->run_statement( { string => "DELETE FROM zz_decryptors WHERE hostname = ?", params => [ clean( $ENV{ZZhostname}, "-_" ) ] } ); } $Zymonic::ZDECRYPTOR{$_}->shutdown foreach ( keys(%Zymonic::ZDECRYPTOR) ); debug("Decryptor shutdown complete"); close($fh); $Zymonic::Utils::DEBUG_AS_SQLITE = $old_DEBUG_AS_SQLITE; } } 1;