#! /usr/local/bin/perl -T -w # publius_server.pl Version 1.0 # Release Date 7/27/2000 # By Marc Waldman (waldman@cs.nyu.edu) # Publius Project WWW page - cs.nyu.edu/waldman/publius # Publius Project E-mail address - publius@cs.nyu.edu # Copyright 2000 - New York University # #PUBLIUS TERMS AND CONDITIONS #THIS SOFTWARE IS EXPERIMENTAL AND IS PROVIDED "AS IS." #ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT #LIMITED TO, THE IMPLIED WARRANTIES OF #MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # #IN NO EVENT SHALL AT&T OR THE AUTHORS BE LIABLE FOR ANY DIRECT, #INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR #CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT #OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; #OR BUSINESS INTERRUPTION) HOWEVER #CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, #STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) #ARISING IN ANY WAY OUT OF THE USE OF THIS #SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # #You are granted a royalty-free, non-exclusive, non-transferable right to #install and use the Publius software for non-commercial purposes during #the Publius trial. You #may not redistribute the code, with or without alterations, #or use the code for #commercial purposes without the permission of AT&T and the authors. use strict; use CGI; use HTTP::Status; use Cwd; use Fcntl; my $publiusFileDir="PUBLIUS DIRECTORY"; # $publiusFileDir specifies the directory where the Publius Files are to be stored my $maxNumFiles=1000; # $maxNumFiles specifies the maximum number of Publius files that may be stored # on the server. A negative number indicates no limit. my $maxFileSizeInK=100; # $maxFileSizeInK specifies the maximum size of a Publius file (in K) # Default is 100K file. my $maxUrlUpdateSize=1000; # $maxUrlUpdateSize specifies the maximum character lenght of an Update URL my $maxPasswordSize=1000; # $maxPasswordSize specifies the maximum character length of a Password and Share sub returnErrorCode{ my ($errorCode,$explanation)=@_; print "Status: $errorCode $explanation\n\n"; exit 0; } sub updateCounter{ my ($num)=@_; if ($maxNumFiles<0){ return 1; #OK to store files } sysopen(FH,"$publiusFileDir/publiusCounter.txt", O_CREAT|O_RDWR); flock(FH, 2); # lock the file for update, 2=exclusive lock my $currentValue=; if ($currentValue){ $currentValue=$currentValue+$num; } else{ $currentValue=$num; } if ($currentValue>$maxNumFiles){ close(FH); return 0; } seek(FH,0,0); truncate(FH,0); print FH $currentValue,"\n"; close(FH); #also unlocks the file return 1; #OK to store file } sub publish{ my ($query,$directory)=@_; my $share=$query->param("share"); my $password=$query->param("password"); my $file=$query->param("file"); if ((!$share) || (!$password) || (!$file)) { returnErrorCode(RC_BAD_REQUEST,"Incomplete Request"); } if ((length($file)/1000)>$maxFileSizeInK){ returnErrorCode(RC_BAD_REQUEST,"File Too Large"); } if (length($share)>$maxPasswordSize){ returnErrorCode(RC_BAD_REQUEST,"Share Too Large"); } if (length($password)>$maxPasswordSize){ returnErrorCode(RC_BAD_REQUEST,"Password Too Large"); } if (updateCounter(1)==0){ returnErrorCode(RC_UNAUTHORIZED,"File Limit Reached"); } $directory="$publiusFileDir/$directory"; if (chdir($directory)){ # can't write into existing directory, only Publius Update can returnErrorCode(RC_UNAUTHORIZED,"Directory Already Exists"); } mkdir($directory,0700) || returnErrorCode(RC_UNAUTHORIZED,"Couldn't Create Directory"); chdir($directory) || returnErrorCode(RC_UNAUTHORIZED,"Couldn't Enter Directory"); open (OUT,">share"); print OUT $share; close OUT; # if password is equal to "EMPTY" don't write password file if ($password ne "EMPTY"){ open (OUT,">password"); print OUT $password; close OUT; } open (OUT,">file"); print OUT $file; close OUT; returnErrorCode(RC_OK,"Published"); } sub readFileIntoString{ my $fileName=shift @_; my $fileContents; open (FILE, $fileName) || return (-1,\("Could Not Open File ".$fileName."\n")); local $/; # clear input separator $fileContents=; return (0,\$fileContents); } sub update{ my ($query,$directory)=@_; my $updateURL=$query->param("updateURL"); my $password=$query->param("password"); $directory="$publiusFileDir/$directory"; chdir($directory) || returnErrorCode(RC_BAD_REQUEST,"Directory Does Not Exist"); my ($errorCode,$storedPasswordRef)=readFileIntoString("password"); if ($errorCode<0){ returnErrorCode(RC_UNAUTHORIZED,"No Password File/No Update Allowed"); } if (substr($$storedPasswordRef,0,1) eq "N"){ returnErrorCode(RC_UNAUTHORIZED,"No Update Allowed"); } if ($password ne substr($$storedPasswordRef,1)){ returnErrorCode(RC_UNAUTHORIZED,"Incorrect Password"); } if (length($updateURL)>$maxUrlUpdateSize){ returnErrorCode(RC_UNAUTHORIZED,"Update URL Too Long"); } else{ open(OUT,">update"); print OUT $updateURL; close(OUT); returnErrorCode(RC_OK,"Updated"); } } sub del{ my ($query,$directory)=@_; my $password=$query->param("password"); my $fullpath="$publiusFileDir/$directory"; chdir($fullpath) || returnErrorCode(RC_BAD_REQUEST,"Directory Does Not Exist"); my ($errorCode,$storedPasswordRef)=readFileIntoString("password"); if ($errorCode<0){ returnErrorCode(RC_UNAUTHORIZED,"No Password File/No Delete Allowed"); } # password file exists - strip away first "update flag" char then check if ($password ne substr($$storedPasswordRef,1)){ returnErrorCode(RC_UNAUTHORIZED,"Incorrect Password"); } else{ unlink("file","share","password","update") || returnErrorCode(RC_BAD_REQUEST,"Unlink Failed"); chdir($publiusFileDir) || returnErrorCode(RC_BAD_REQUEST,"Couldn't Leave Directory"); updateCounter(-1); rmdir($directory) || returnErrorCode(RC_UNAUTHORIZED,"Deleted Files, Unable to Delete Directory"); returnErrorCode(RC_OK,"Deleted"); } } sub retrieve{ my ($query,$directory,$file_or_share)=@_; chdir ("$publiusFileDir/$directory") || returnErrorCode(RC_BAD_REQUEST,"Directory Does Not Exist"); if (-e "update"){ print $query->header(-type=>'application/octet-stream', -status=>'200 OK', 'update'=>'1', ); open(FH,"update"); while($_=){ print $_; } close(FH); } elsif ($file_or_share eq "S"){ # retrieve a share print $query->header(-type=>'application/octet-stream', -status=>'200 OK', 'update'=>'0', ); open(FH,"share"); while($_=){ print $_; } close(FH); } else{ # send the encrypted file print $query->header(-type=>'application/octet-stream', -status=>'200 OK', 'update'=>'0', ); open(FH,"file"); while($_=){ print $_; } close(FH); } } sub main{ my $query=CGI::new(); my $command=$query->param("command"); my $directory=$query->param("directory"); if ($publiusFileDir eq "PUBLIUS DIRECTORY"){ print $query->header(-type=>'text/html', -status=>'200 OK'); print "

No Publius Directory Specified

"; exit 0; } if ((!$command) || (!$directory)){ returnErrorCode(RC_BAD_REQUEST,"Incomplete Request"); } elsif ($directory =~ /[^\dA-Fa-f]/){ returnErrorCode(RC_BAD_REQUEST,"Illegal Directory Name"); } else{ $directory =~/([\dA-Fa-f]+)/; $directory = $1; # directory is now untainted if ($command eq "PUBLISH"){ publish($query,$directory); } elsif ($command eq "DELETE"){ del($query,$directory); } elsif ($command eq "UPDATE"){ update($query,$directory); } elsif ($command eq "RETRIEVE_S"){ # retrieve a share retrieve($query,$directory,"S"); } elsif ($command eq "RETRIEVE_F"){ # retrieve a file retrieve($query,$directory,"F"); } } } main()