[Templates] some patches

Chris Nandor pudge@pobox.com
Fri, 3 Aug 2001 13:02:33 -0400


The patches below are for two things:

* Fix up taint checks.  

The taint checks in place seemed to be trying to do two things: check for 
"valid" characters, and untaint.  I am not sure if untainting is the right thing 
to do, but assuming it is, its set of valid characters wasn't.

Now they allow any characters.  Stephen Howard has a ":" in his names (full 
DOS pathnames), and I had ";" in mine (just because I want to :-).

Also changed is the check for time; it skips the whole thing if time is not 
defined (I don't currently have timestamps from my templates, provided from the 
database), and also allows 0 as a valid time.  Also, the check was always 
failing because of a context error bug (finding is is an exercise left to the 
reader.  ;-)

I also changed write_perl_file to use sysopen(), which is really 
the only portable way to avoid shell metacharacters causing problems.  I don't 
know if anyone cares, but they might.

These are security issues involved, of course, so please look over the patch 
carefully.


* Allow overriding FACTORY.  This allows me to do this:

package Slash::Display::Directive;

use base qw(Template::Directive);
use Slash::Utility::Environment;

# this is essentially the same as Template::Directive, but we want
# to hijack simple calls to $constants to optimize it
sub ident {
	my ($class, $ident) = @_;
	return "''" unless @$ident;

	if ($ident->[0] eq q['constants'] && @$ident == 4) {
		(my $key = $ident->[2]) =~ s/^'(.+)'$/$1/s;
		my $data = getCurrentStatic($key);
		$data =~ s/'/\\'/;
		return "'$data'";
	}

	if (scalar @$ident <= 2 && ! $ident->[1]) {
		$ident = $ident->[0];
	} else {
		$ident = '[' . join(', ', @$ident) . ']';
	}
	return "\$stash->get($ident)";
}

__END__


Now I can have constant folding!  W00p!  (Thanks Andy.)  This should help speed 
up Slash considerably, as we have [% constants.foo %] littered all over our 
templates, and, being constants, they don't often change.

Patch below.


diff -ru Document.pm.orig Document.pm
--- Document.pm.orig	Fri Jun 29 13:34:43 2001
+++ Document.pm	Fri Aug  3 12:26:46 2001
@@ -32,6 +32,7 @@
 use vars qw( $VERSION $ERROR $COMPERR $DEBUG $AUTOLOAD );
 use base qw( Template::Base );
 use Template::Constants;
+use Fcntl qw(O_WRONLY O_CREAT);
 
 $VERSION = sprintf("%d.%02d", q$Revision: 2.19 $ =~ /(\d+)\.(\d+)/);
 
@@ -243,11 +244,11 @@
 		       } keys %$metadata);
 
     local *CFH;
-    my ($cfile) = $file =~ /^([\w\.\-\/]+)$/ or do {
+    my ($cfile) = $file =~ /^(.+)$/s or do {
 	$ERROR = "invalid filename: $file";
 	return undef;
     };
-    open(CFH, ">$cfile") or do {
+    sysopen(CFH, $cfile, O_CREAT|O_WRONLY) or do {
 	$ERROR = $!;
 	return undef;
     };
diff -ru Parser.pm.orig Parser.pm
--- Parser.pm.orig	Fri Jun 29 13:34:43 2001
+++ Parser.pm	Fri Aug  3 12:25:49 2001
@@ -117,6 +117,7 @@
 	EVAL_PERL   => 0,
 	GRAMMAR     => undef,
 	_ERROR      => '',
+	FACTORY     => 'Template::Directive',
     }, $class;
 
     # update self with any relevant keys in config
@@ -128,7 +129,6 @@
 	require Template::Grammar;
 	Template::Grammar->new();
     };
-    $self->{ FACTORY } ||= 'Template::Directive';
 
 #    # determine START_TAG and END_TAG for specified (or default) TAG_STYLE
 #    $tagstyle = $self->{ TAG_STYLE } || 'default';
diff -ru Provider.pm.orig Provider.pm
--- Provider.pm.orig	Fri Jun 29 13:34:43 2001
+++ Provider.pm	Fri Aug  3 12:27:58 2001
@@ -436,9 +436,9 @@
 		    # want 1 returned by require() to say it's in memory)
 		    delete $INC{ $compiled };
 		    eval { 
-			my ($ccompiled) = $compiled =~ /^([\w\-\.\/]+)$/ 
+			my ($ccompiled) = $compiled =~ /^(.+)$/s 
 			    or die "invalid filename: $compiled";
-			$data = require $compiled;
+			$data = require $ccompiled;
 		    };
 		    if ($data && ! $@) {
 			# store in cache
@@ -727,16 +727,20 @@
 		    . &File::Basename::basename($compfile)
 		    . ": $Template::Document::ERROR"
 		unless Template::Document::write_perl_file($compfile, $parsedoc);
-
-	    if (!defined($error)) {
-		my ($ctime, $cfile);
-		# set atime and mtime of newly compiled file
-		($cfile = ($compfile =~ /^([\w\-\.\/]+)$/))
-		    or return("invalid filename: $compfile", 
+ 
+	    # set atime and mtime of newly compiled file, don't bother
+	    # if time is undef
+	    if (!defined($error) && defined $data->{ time }) {
+		my ($cfile) = $compfile =~ /^(.+)$/s or do {
+		    return("invalid filename: $compfile", 
 			      Template::Constants::STATUS_ERROR);
-		($ctime = ($data->{ time } =~ /^(\d+)$/))
-		    or return("invalid time: $ctime", 
+		};
+
+		my ($ctime) = $data->{ time } =~ /^(\d+)$/;
+		unless ($ctime || $ctime eq 0) {
+		    return("invalid time: $ctime", 
 			      Template::Constants::STATUS_ERROR);
+		}
  		utime($ctime, $ctime, $cfile);
 	    }
 	}



-- 
Chris Nandor                      pudge@pobox.com    http://pudge.net/
Open Source Development Network    pudge@osdn.com     http://osdn.com/