############################################################################# ## Name: Compartment.pm ## Purpose: Safe::World::Compartment -> Based in the Safe module. ## Author: Graciliano M. P. ## Modified by: ## Created: 04/12/2003 ## RCS-ID: ## Copyright: (c) 2003 Graciliano M. P. ## Licence: This program is free software; you can redistribute it and/or ## modify it under the same terms as Perl itself ############################################################################# package Safe::World::Compartment ; use strict qw(vars) ; no warnings ; ########## # SCOPES # ########## use vars qw($Safe_World_EVALX) ; *Safe_World_EVALX = \$Safe::World::EVALX ; ######### *** Don't declare any lexicals above this point *** sub reval { my $__EVALCODE__ = $_[1] ; no strict ; $Safe_World_EVALX += 2 ; return Opcode::_safe_call_sv( $_[0]->{Root}, $_[0]->{Mask}, eval("package ". $_[0]->{Root} ."; sub { \@_=(); my \$EVALX = $Safe_World_EVALX; eval \$__EVALCODE__; }") ); } ############################################################################# use vars qw($VERSION @ISA) ; $VERSION = '0.02' ; use Opcode 1.01, qw( opset opset_to_ops opmask_add empty_opset full_opset invert_opset verify_opset opdesc opcodes opmask define_optag opset_to_hex ); *ops_to_opset = \&opset ; # Temporary alias for old Penguins *Opcode_safe_pkg_prep = \&Opcode::_safe_pkg_prep ; my $default_share = ['*_'] ; my $SCALAR_R ; tie( $SCALAR_R , 'Safe::World::Compartment::SCALAR_R') ; ############################################################################# sub new { my($class, $root) = @_; my $obj = bless({} , $class) ; $obj->{Root} = $root ; return undef if !defined($root) ; $obj->permit_only(':default') ; $obj->share_from('main', $default_share) ; { ## (See Safe::World::Compartment::SCALAR_R at the end of this file). ## Set the tied $^R to fix behavior: my $tmp = $_ ; $_ = \$SCALAR_R ; $obj->reval('*^R = $_') ; $_ = $tmp ; $^R = undef ; ## Ensure that is reseted. } Opcode_safe_pkg_prep($root) if($Opcode::VERSION > 1.04); return $obj; } sub deny { my $obj = shift; $obj->{Mask} |= opset(@_); } sub deny_only { my $obj = shift; $obj->{Mask} = opset(@_); } sub permit { my $obj = shift; $obj->{Mask} &= invert_opset opset(@_); } sub permit_only { my $obj = shift; $obj->{Mask} = invert_opset opset(@_); } sub share_from { my $obj = shift; my $pkg = shift; my $vars = shift; my $root = $obj->{Root} ; return undef if ref($vars) ne 'ARRAY' ; no strict 'refs'; return undef unless keys %{"$pkg\::"} ; my $REF ; my $arg; foreach $arg (@$vars) { next unless( $arg =~ /^[\$\@%*&]?\w[\w:]*$/ || $arg =~ /^\$\W\w?$/ ) ; my ($var, $type); $type = $1 if ($var = $arg) =~ s/^(\W)// ; *{$root."::$var"} = (!$type) ? \&{$pkg."::$var"} : ($type eq '&') ? \&{$pkg."::$var"} : ($type eq '$') ? \${$pkg."::$var"} : ($type eq '@') ? \@{$pkg."::$var"} : ($type eq '%') ? \%{$pkg."::$var"} : ($type eq '*') ? \*{$pkg."::$var"} : undef ; } return 1 ; } ###################################### # SAFE::WORLD::COMPARTMENT::SCALAR_R # TIE SCALAR FOR $^R ###################################### # The predefined variable $^R doesn't work like normal variables, # that to be global lives in the main:: package. $^R doesn't exists # at main::, soo $main::^R doesn't exists and we can't share it with # the World compartment. $^R actually points to the last scalar returned # by the code executed in the RE, soo $^R will point to different SCALARs # during the RE, and if we change by hand the scalar reference of *^R it # will be overwrited during the RE. # # To fix that I have used a closure in the # FETCH and STORE methods of the TIESCALAR, and set the scalar of the # GLOB reference inside the compartment (*^R) with the tied scalar. # Soo, if an RE compiled inside the compartment make some reference to $^R # it will see the external $^R through the TIED SCALAR. # package Safe::World::Compartment::SCALAR_R ; sub TIESCALAR { my $class = shift ; my $ref = shift ; return bless( \$ref , __PACKAGE__ ) ; } sub STORE { my $this = shift ; $^R = $_[0] ; return $^R ; } sub FETCH { my $this = shift ; return $^R ; } sub UNTIE {} sub DESTROY {} ####### # END # ####### 1;