[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
[0184]
[0185]
[0186]
[0187]
[0188]
[0189]
[0190]
[0191]
[0192]
[0193]
[0194]
[0195]
[0196]
[0197]
[0198]
[0199]
[0200]
[0201]
[0202]
[0203]
[0204]
[0205]
[0206]
[0207]
[0208]
[0209]
[0210]
[0211]
[0212]
[0213]
[0214]
[0215]
[0216]
[0217]
[0218]
[0219]
[0220]
[0221]
[0222]
[0223]
[0224]
[0225]
[0226]
[0227]
[0228]
[0229]
[0230]
[0231]
[0232]
[0233]
[0234]
[0235]
[0236]
[0237]
[0238]
[0239]
[0240]
[0241]
[0242]
[0243]
[0244]
[0245]
[0246]
[0247]
[0248]
[0249]
[0250]
[0251]
[0252]
[0253]
[0254]
[0255]
[0256]
[0257]
[0258]
[0259]
[0260]
[0261]
[0262]
[0263]
[0264]
[0265]
[0266]
[0267]
[0268]
[0269]
[0270]
[0271]
[0272]
[0273]
[0274]
[0275]
[0276]
[0277]
[0278]
[0279]
[0280]
[0281]
[0282]
[0283]
[0284]
[0285]
[0286]
[0287]
[0288]
[0289]
[0290]
[0291]
[0292]
[0293]
[0294]
[0295]
[0296]
[0297]
[0298]
[0299]
[0300]
[0301]
[0302]
[0303]
[0304]
[0305]
[0306]
[0307]
[0308]
[0309]
[0310]
[0311]
[0312]
[0313]
[0314]
[0315]
[0316]
[0317]
[0318]
[0319]
[0320]
[0321]
[0322]
[0323]
[0324]
[0325]
[0326]
[0327]
[0328]
[0329]
[0330]
[0331]
[0332]
[0333]
[0334]
[0335]
[0336]
[0337]
[0338]
[0339]
[0340]
[0341]
[0342]
[0343]
[0344]
[0345]
[0346]
[0347]
[0348]
[0349]
[0350]
[0351]
[0352]
[0353]
[0354]
[0355]
[0356]
[0357]
[0358]
[0359]
[0360]
[0361]
[0362]
[0363]
[0364]
[0365]
[0366]
[0367]
[0368]
[0369]
[0370]
[0371]
[0372]
[0373]
[0374]
[0375]
[0376]
[0377]
[0378]
[0379]
[0380]
[0381]
[0382]
[0383]
[0384]
[0385]
[0386]
[0387]
[0388]
[0389]
[0390]
[0391]
[0392]
[0393]
[0394]
[0395]
[0396]
[0397]
[0398]
[0399]
[0400]
[0401]
[0402]
[0403]
[0404]
[0405]
[0406]
[0407]
[0408]
[0409]
[0410]
[0411]
[0412]
[0413]
[0414]
[0415]
[0416]
[0417]
[0418]
[0419]
[0420]
[0421]
[0422]
[0423]
[0424]
[0425]
[0426]
[0427]
[0428]
[0429]
[0430]
[0431]
[0432]
[0433]
[0434]
[0435]
[0436]
[0437]
[0438]
[0439]
[0440]
[0441]
[0442]
[0443]
[0444]
[0445]
[0446]
[0447]
[0448]
[0449]
[0450]
[0451]
[0452]
[0453]
[0454]
[0455]
[0456]
[0457]
[0458]
[0459]
[0460]
[0461]
[0462]
[0463]
[0464]
[0465]
[0466]
[0467]
[0468]
[0469]
[0470]
[0471]
[0472]
[0473]
[0474]
[0475]
[0476]
[0477]
[0478]
[0479]
[0480]
[0481]
[0482]
[0483]
[0484]
[0485]
[0486]
[0487]
[0488]
[0489]
[0490]
[0491]
[0492]
[0493]
[0494]
[0495]
[0496]
[0497]
[0498]
[0499]
[0500]
[0501]
[0502]
[0503]
[0504]
[0505]
[0506]
[0507]
[0508]
[0509]
[0510]
[0511]
[0512]
[0513]
#
# Dick Munroe (munroe@csworks.com)
#
# Convert all local address blocks from the OSU configuration
# files to a format that can be processed by WASD.
#
# Usage:
#
#	perl CONVERT-OSU-TO-WASD.PL www_system:osu.conf
#
# What is produced are files in the current directory.  Some
# tweaking may be necessary for your configuration to do everything
# at your site.
#
# One thing that I would like to figure out is how to actually
# generate HTA files instead of HTL files for authentication if
# an authenticator is specified in the OSU configuration.
#
# The OSU configuration file is expected to be of the form:
#
# localaddress (cname | ip number) host name
# configuration statements
# localaddress
#

use strict ;

use File::Basename ;
use FileHandle ;
use VMS::Filespec ;

sub glob2pat {
    my $globstr = shift;
    my %patmap = (
        '*' => '(.*)',
        '?' => '.',
        '[' => '[',
        ']' => ']',
    );
    $globstr =~ s{(.)} { $patmap{$1} || "\Q$1" }ge;
    return '^' . $globstr . '$';
}

sub dcl
{
	return '$ ' . $_[0] . "\n" ;
} ;

sub convertProtToHTL
{
	my $theFileHandle = new FileHandle "< " . $_[0] ;

	die $_[0] . " does not exist" if (!defined $theFileHandle) ;

	my $theLine ;
	my $theRealm ;
	my @theResult ;

	while (defined($theLine = $theFileHandle->getline()))
	{
		chomp $theLine ;

		if ($theLine =~ m/^<realm>\s+(.*)/)
		{
			$theRealm = $1 ;
		}
		elsif ($theLine =~ m/^(\w+?)\s+(\w+)/)
		{
			push @theResult,$1 . "=" . $2 ;
		}
		elsif ($theLine =~ m/^\s*#/)
		{
			push @theResult,$theLine ;
		}
		else
		{
			push @theResult,"# " . $theLine ;
		}
	}

	my @theReturnValue ;

	$theReturnValue[0] = $theRealm ;
	$theReturnValue[1] = (join "\n",@theResult) . "\n" ;

	return @theReturnValue ;
} ;

my $theBusyCount ;
my $theCurrentHost ;
my $theInputFile = new FileHandle "< " . $ARGV[0] ;
my $theLine ;
my %theLocalAddressBlocks ;
my %theProtectionDomains ;

while (defined($theLine = $theInputFile->getline()))
{
	chomp $theLine ;

	#
	# Ignore blank lines.
	#

	next if ($theLine eq "") ;

	#
	# And comments.
	#

	next if ($theLine =~ m/^\s*#/) ;

	last if ($theLine =~ m/^localaddress\s*(#.*$|$)/i) ;

	#
	# The OSU file local address block provides either a
	# canonical name or an ip address followed by a host
	# name.  We use the host name to define the virtual
	# service.
	#

	if ($theLine =~ m/^localaddress\s+(cname|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+(localhost|([\w-]+(\.[\w-]+)+))/i)
	{
		$theCurrentHost = $2 ;
		$theLocalAddressBlocks{$theCurrentHost}{'ip'} = $1 ;
	}
	elsif ($theLine =~ m/^localaddress\s+\@listen_backlog=(\d+)/i)
	{
		$theBusyCount = $1 if ($theBusyCount < $1) ;
	}
	elsif ($theLine =~ m/^localaddress/i)
	{
		print "ERROR: ",$theLine,"\n" ;
	}
	else
	{
		if ($theLine =~ m/^\s*protect\s+([^\s]+)\s+([^\s]+)/i)
		{
			if (-e $2)
			{
				$theProtectionDomains{$theCurrentHost}{$1} = $2 ;
			}
			else
			{
				print "ERROR: ",$theLine,"\n" ;
			}
		}
		else
		{
			push @{$theLocalAddressBlocks{$theCurrentHost}{'configuration'}},$theLine ;
		} ;
	}
} ;

undef $theInputFile ;

my $theFileHandle ;

$theFileHandle = rmsexpand('sys$disk:[].httpd$service',$ARGV[0]) ;

$theFileHandle = new FileHandle "> " . $theFileHandle ;

print $theFileHandle "#\n" ;
print $theFileHandle "# Generated from ",$ARGV[0]," by convert-osu-to-wasd.pl\n" ;
print $theFileHandle "#\n" ;

foreach (sort keys %theLocalAddressBlocks)
{
	my $theScheme ;

	foreach $theScheme ("http", "https")
	{
		print $theFileHandle "[[$theScheme://",$_,"]]\n" ;

		print $theFileHandle "[ServiceIpAddress] ",$theLocalAddressBlocks{$_}{ip},"\n" if ($theLocalAddressBlocks{$_}{ip} ne 'cname') ;

		print $theFileHandle "\n" ;
	} ;
} ;

undef $theFileHandle ;

my %theAcls ;

$theFileHandle = rmsexpand('sys$disk:[].httpd$map',$ARGV[0]) ;

$theFileHandle = new FileHandle "> " . $theFileHandle ;

print $theFileHandle "#\n" ;
print $theFileHandle "# Generated from ",$ARGV[0]," by convert-osu-to-wasd.pl\n" ;
print $theFileHandle "#\n" ;

foreach (sort keys %theLocalAddressBlocks)
{
	my @theLengths ;
	my @theResult ;

	foreach (@{$theLocalAddressBlocks{$_}{'configuration'}})
	{
		if (m/^(redirect|map)\s+([^\s]+)\s+([^\s]+)/i)
		{
			push @theResult,[$1, unixify($2), unixify($3)] ;
		}
		elsif (m/^(exec)\s+([^\s]+)\s+([^\s]+)/i)
		{
			push @theResult,[$1, unixify($2), '/0::"task=wwwexec"' . unixify($3) . "*"] ;
		}
		elsif (m/^(pass)\s+([^\s]+)\s*([^\s]*)/i)
		{
			push @theResult,[$1, unixify($2), unixify($3)] ;
		}
		else
		{
			push @theResult,"# " . $_ ;
		}
		
		if ((ref $theResult[$#theResult]) ne "")
		{
			my $theIndex ;

			for ($theIndex = 0; $theIndex < scalar(@{$theResult[$#theResult]}); $theIndex++)
			{
				if ($theLengths[$theIndex] < length($theResult[$#theResult]->[$theIndex]))
				{
					$theLengths[$theIndex] = length($theResult[$#theResult]->[$theIndex]) ;
				}
			}
		} ;
	}

	@{$theLocalAddressBlocks{$_}{result}} = @theResult ;

#	print $theFileHandle "if (host:$_*)\n" ;
	print $theFileHandle "[[",$_,"]]\n" ;

	foreach (@theResult)
	{
		my $theRef = ref $_ ;

		if ($theRef eq "")
		{
			print $theFileHandle "    ",$_,"\n" ;
		}
		else
		{
			my $theIndex ;
			my $theString ;

			for ($theIndex = 0; $theIndex < scalar(@{$_}); $theIndex++)
			{
				$theString = $theString . sprintf("%-" . sprintf("%d", $theLengths[$theIndex]) . "s",$_->[$theIndex]) . " " ;
			} ;
			
			print $theFileHandle "    ",$theString,"\n" ;
		}
	}

#	print $theFileHandle "endif\n" ;
	print $theFileHandle "\n" ;
}

undef $theFileHandle ;

my %theConvertedProtectionDomains ;

$theFileHandle = rmsexpand('sys$disk:[].httpd$auth',$ARGV[0]) ;

$theFileHandle = new FileHandle "> " . $theFileHandle ;

print $theFileHandle "#\n" ;
print $theFileHandle "# Generated from ",$ARGV[0]," by convert-osu-to-wasd.pl\n" ;
print $theFileHandle "#\n" ;

foreach (sort keys %theProtectionDomains)
{
	my $theDomain = $_ ;

#	print $theFileHandle "if (host:",$theDomain,")\n\n" ;
	print $theFileHandle "[[",$theDomain,"]]\n\n" ;

 	foreach (sort keys %{$theProtectionDomains{$theDomain}})
	{
		my $theFileName = $theProtectionDomains{$theDomain}{$_} ;

		if (! exists($theConvertedProtectionDomains{$theFileName})) 
		{
			@{$theConvertedProtectionDomains{$theFileName}} = convertProtToHTL($theFileName) ;
		}

		print $theFileHandle "[\"",$theConvertedProtectionDomains{$theFileName}[0],"\"=",uc((fileparse($theFileName,'\..*'))[0]),"=list]\n" ;
		print $theFileHandle $_," r+w\n" ;
		print $theFileHandle "\n" ;
	}

#	print $theFileHandle "endif\n\" ;
	print $theFileHandle "\n" ;
}

undef $theFileHandle ;

foreach (sort keys %theConvertedProtectionDomains)
{
	$theFileHandle = new FileHandle "> " . rmsexpand('sys$disk:[].$htl',$_) ;

	print $theFileHandle "#\n" ;
	print $theFileHandle "# Converted from $_ by convert-osu-to-wasd.pl\n" ;
	print $theFileHandle "#\n" ;

	print $theFileHandle $theConvertedProtectionDomains{$_}[1] ;

	undef $theFileHandle ;
}

if (defined($theBusyCount))
{
	$theFileHandle = new FileHandle "> " . rmsexpand('sys$disk:[].httpd$config',$ARGV[0]) ;

   	print $theFileHandle "[Busy] ",$theBusyCount,"\n" if (defined($theBusyCount)) ;

	undef $theFileHandle ;
} ;

#
# Produce a DCL procedure that will get "close" to the protections
# necessary to run the OSU content and cgis from the new WASD
# server.  Basically what's happening here is that every directory
# that needs read access (shows up in a redirect, map, or pass)
# will have protection set to:
#
#	S:RWED,O:RWED,G:RE,W:RE
#
# for all files, including directories.
#
# An ACL setting the following will then be applied to the directory
# and all subdirectorys:
#
#       (DEFAULT_PROTECTION,SYSTEM:RWED,OWNER:RWED,GROUP:RE,WORLD:RE)
#
# Which will keep the right protections going.
#
# Execute directories will have the following protections set:
#
#	S:RWED,O:RWED,G:RE,W:E
#
# which will allow anybody to execute things.  An ACL will be placed
# on all directories:
#
#       (DEFAULT_PROTECTION,SYSTEM:RWED,OWNER:RWED,GROUP:RE,WORLD:E)
#
# In addition, all .DAT files (and you will need to do this manually
# for all files that need to be written by these CGIs) will have an
# acl added that allows http$nobody full access.
#
#	(IDENTIFIER=WASD_HTTP_NOBODY,ACCESS=READ+WRITE+EXECUTE+DELETE)
#
# Remember that this is just a template and should be inspected
# carefully before executing.
#

$theFileHandle = rmsexpand('sys$disk:[].set-protection',$ARGV[0]) ;

$theFileHandle = new FileHandle "> " . $theFileHandle ;

print $theFileHandle dcl("!") ;
print $theFileHandle dcl("! Generated from " . $ARGV[0] . " by convert-osu-to-wasd.pl") ;
print $theFileHandle dcl("!") ;
print $theFileHandle dcl("EXIT") ;
print $theFileHandle dcl("") ;

print $theFileHandle dcl('DEFAULT_DIRECTORY = F$ENVIRONMENT("DEFAULT")') ;

foreach (sort keys %theLocalAddressBlocks)
{
	if (exists($theLocalAddressBlocks{$_}{result}) &&
	    scalar(@{$theLocalAddressBlocks{$_}{result}}))
	{
		my $theIndex ;

		OUTER :
		for ($theIndex = 0; $theIndex < scalar(@{$theLocalAddressBlocks{$_}{result}}) - 1; $theIndex++)
		{
			next if (ref(${$theLocalAddressBlocks{$_}{result}}[$theIndex]) eq '') ;

			my @theResults = @{${$theLocalAddressBlocks{$_}{result}}[$theIndex]} ;
			my @theInnerResults ;
			my $theResult = $theResults[2] ;
			my $theInnerIndex ;

			if ($theResults[0] eq 'exec')
			{
				@theInnerResults = @{${$theLocalAddressBlocks{$_}{result}}[$theIndex]} ;
				$theResult = $theInnerResults[2] ;
			}
			else
			{
				for ($theInnerIndex = $theIndex + 1; 
				     $theInnerIndex < scalar(@{$theLocalAddressBlocks{$_}{result}});
				     $theInnerIndex++)
				{
					@theInnerResults = @{${$theLocalAddressBlocks{$_}{result}}[$theInnerIndex]} ;

					my $theMatch = glob2pat($theInnerResults[1]) ;
	
					if ($theResult =~ m/$theMatch/)
					{
						if ($theInnerResults[2] ne '')
						{
							my $theTemp = $1 ;

							$theResult = $theInnerResults[2] ;

							$theResult =~ s/\*/$theTemp/ ;

							last if ($theInnerResults[0] ne 'map') ;
						} ;
					} ;
				} ;
			} ;

			$theResult =~ s/\/.*::.*?\//\// ;

			$theResult = vmsify($theResult) ;

			$theResult =~ s/\].*/\]/ ;

			$theAcls{$theResult}{$theInnerResults[0]}++ ;
		}

	}
}

my $theLastKey ;
my $theLastKeyMatch ;

foreach (sort { $b cmp $a } keys %theAcls)
{
	my $theRoot = $_ ;

	chop $theRoot ;

	if (! defined($theLastKey))
	{
		$theLastKey = $theRoot ;
		$theLastKeyMatch = quotemeta($theLastKey) ;
	}
	elsif ($theRoot =~ m/^$theLastKeyMatch\./)
	{
		my $theMap ;
		my $theOriginalKey = $theLastKey . "]" ;
		my $theUndefFlag = 1 ;

		foreach $theMap ("pass", "exec")
		{
			$theUndefFlag = $theUndefFlag && 
			    (((defined($theAcls{$theOriginalKey}{$theMap})) && (defined($theAcls{$_}{$theMap}))) ||
			     ((!defined($theAcls{$theOriginalKey}{$theMap})) && (!defined($theAcls{$_}{$theMap})))) ;
		} ;

		undef $theAcls{$_} if ($theUndefFlag) ;
	}
	else
	{
		$theLastKey = $theRoot ;
		$theLastKeyMatch = quotemeta($theLastKey) ;
	} 
} ;

foreach (sort keys %theAcls)
{
	next if (!defined($theAcls{$_})) ;

	my $theDirectory = $_ ;

	$theDirectory = uc($theDirectory) ;

	print $theFileHandle dcl("!") ;
	print $theFileHandle dcl("SET DEFAULT $theDirectory") ;
	$theDirectory =~ s/^.+\[([^\]]*).*/$1/ ;

	$theDirectory =~ s/^([^\.]+\.)*// ;

	my $theDirectoryAce ;
	my $theDirectoryProtection ;

	if ((defined($theAcls{$_}{'pass'}) && defined($theAcls{$_}{'exec'})) || defined($theAcls{$_}{'pass'}))
	{
		$theDirectoryAce = "(DEFAULT_PROTECTION,SYSTEM:RWED,OWNER:RWED,GROUP:RE,WORLD:RE)" ;
		$theDirectoryProtection = "(SYSTEM:RWED,OWNER:RWED,GROUP:RE,WORLD:RE)" ;
	}
	else
	{
		$theDirectoryAce = "(DEFAULT_PROTECTION,SYSTEM:RWED,OWNER:RWED,GROUP:RE,WORLD:E)" ;
		$theDirectoryProtection = "(SYSTEM:RWED,OWNER:RWED,GROUP:RE,WORLD:E)" ;
	} ;

	print $theFileHandle dcl("SET FILE /PROTECTION=$theDirectoryProtection [-]$theDirectory.DIR;") ;
	print $theFileHandle dcl("SET FILE /PROTECTION=$theDirectoryProtection [...]*.*;*") ;

	print $theFileHandle dcl("SET ACL /ACL=$theDirectoryAce [-]$theDirectory.DIR;") ;
	print $theFileHandle dcl("SET ACL /LIKE=(OBJECT_TYPE=FILE,OBJECT_NAME=[-]$theDirectory.DIR;) [...]*.DIR;") ;

	my $theDataAce = "(IDENTIFIER=WASD_HTTP_NOBODY,ACCESS=READ+WRITE+EXECUTE+DELETE)" ;

	if (defined($theAcls{$_}{'exec'}))
	{
		print $theFileHandle dcl("SET ACL /ACL=$theDataAce [...]*.DAT;*") ;
	}
} ;

print $theFileHandle dcl("!") ;
print $theFileHandle dcl("SET DEFAULT 'DEFAULT_DIRECTORY'") ;
print $theFileHandle dcl("EXIT") ;

undef $theFileHandle ;