tags:

views:

78

answers:

4

I was wondering if it was possible to read a text file that was located in a directory called "/home/user/files"

I wanted to read it from my cgi-bin which is located in /home/user/cgi-bi/ Below is my code,

#!/usr/bin/perl
use strict;
use CGI;


#Virtual Directory
#Steffan Harris

eval
{


use constant PASSWORD => 'perl';
use constant UPLOAD_DIR => '/home/sharris2/files';

sub mapToFile
{
   print chdir UPLOAD_DIR;

}

#This function will list all files in a directory.
sub  listDirectoryFiles
{
    chdir UPLOAD_DIR;

    my @files = <*>;

    mapToFile;
    print<<LIST;
    <h2>Current Files</h2>
      <ul>
LIST
     if(!$files[0])
     {
     print" </ul>\n<em>No files in directory</em>";
     }

    foreach(@files)
    {


    print"      <li>$_</li>";

    }
    print "     </ul>\n";


}
#This function generates a 404 Not Found error
sub generate404
{

print<<RESPONSE;
Status: 404 Not Found
Content-Type: text/html


      <html>
          <head><title>404 Not Found</title></head>
      <body>
        <p>
          <h1>404 - Not Found</h1>
        </p>
        The requested URL <b>$ENV{"HTTP_HOST"}$ENV{"REQUEST_URI"}</b> was not found on the server.
      </body>
      </html>


RESPONSE
exit;

}
#This function checks the path info to see if it matches a file in the UPLOAD_DIR directory, If it does not, then it returns a 404 error
sub checkExsistence
{

    if($ENV{"PATH_INFO"})
    {


    chdir UPLOAD_DIR;

    my @files = <*>;

    if(!$files[0] and $ENV{"PATH_INFO"} eq "/")
    {
        return;
    }


    foreach(@files)
    {


        if($ENV{"PATH_INFO"} eq "/".$_ || $ENV{"PATH_INFO"} eq "/")
        {
        print "yes";
        return;
        }


    }


    generate404;

    }


}

sub checkPassword
{
    my ($password, $cgi);
    $cgi = new CGI;

    $password = $cgi->param('passwd');

    unless($password eq PASSWORD)
    {

    print<<RESPONSE;
Status: 200 OK
Content-Type: text/html

     <html>
       <head>
         <title>Incorrect Password</title>
       </head>
       <body>
         <h1>Invalid password entered.</h1>
     <h3><a href="/~sharris2/cgi-bin/files/">Go Back</a></h3>
       </body>


RESPONSE

    exit;

    }

}


sub upLoadFile
{
    checkPassword;
    my ($uploadfile, $cgi);
    $cgi = new CGI;
    $uploadfile = $cgi->upload('uploadfile');


    chdir UPLOAD_DIR;

    $uploadfile
    or die "Did not receive a file to upload";

    open my $FILE, '>', UPLOAD_DIR."/$uploadfile" or
    die "$!";


    while(<$uploadfile>)
    {
    print $FILE $_;
    }

}

#Start of main  part of program

my $cgi = new CGI;

if(!$ENV{"PATH_INFO"})
{
    print $cgi->redirect('/~sharris2/cgi-bin/files/');
}

checkExsistence;

if($ENV{"REQUEST_METHOD"} eq "POST")
{

    upLoadFile;

}

print <<"HEADERS";
Status: 200 OK
Content-Type: text/html

HEADERS
    print <<"HTML";
<html>
    <head>
       <title>Virtual Directory</title> 
    </head>
    <body>

HTML

    listDirectoryFiles;

  print<<HTML;
       <h2>Upload a new file</h2>
      <form method = "POST" enctype = "multipart/form-data" action = "/~sharris2/cgi-bin/files/" />


          File:<input type = "file" name="uploadfile"/>



             <p>Password:
              <input type = "password" name ="passwd"/></p>
             <p><input type = "submit" value= "Submit File" /></p>


       </form>

    </body>


</html>

HTML



};
A: 

You probably need to make sure the web server can read your files. Note that with this method, anyone with an account on the server would be able to read the files. (But not anyone just accessing through the web). Try (in the shell):

chown a+r <file you want the web server to be able to read>

The web server will also need execute permission on your directory (do chown a+x on it) in order to access its contents.

If you don't have shell access to your stuff, you may have to use whatever interface you have to make the stuff readable. Your system may be set up to not allow you to do this.

One possible somewhat secure alternative is to inline the files in your script (or in other scripts called by your script). The web server won't serve the text of the scripts, so you can still protect the content.

Splat
i do have shell access, I did an ls -l and i gotdrwx-xr-x.
Zerobu
What are the permissions on the file itself? If it's world readable, perhaps permissions aren't the problem. I'd suggest printing extra stuff to verify that each step of your program is working as you expect. Print the current directory after the chdir for example and check/print error codes whenever possible, as suggested by msw above.
Splat
well after chdir, wouldn't my current directory be /home/user/files
Zerobu
@Zerobu: only if the chdir succeeded
ysth
+1  A: 

Your script can read any file the web server have permissions to, provided higher-order security frameworks such as SELinux and grsec don't interfere.

Ignacio Vazquez-Abrams
+1  A: 

Always check the status of chdir:

chdir SOME_DIR || die "chdir failed: $!";

And remember that when your CGI script dies, the error will go into the web server error log - not to the web browser.

noswonky
+2  A: 

There's no need to chdir, and you probably don't really want to do that anyway. Just try to open the directory. If you can't open the directory, log an error message so you know what happened. Remember, anything you try to access, including containing directories, has to have the appropriate permissions to let the web server user do whatever you are trying to do.

  sub  listDirectoryFiles
      {
      my( $dir ) = @_;

      unless( opendir my $dh, $dir )
           {
           warn "Could not open directory [$dir]: $!";
           return;
           }

      # filter "hidden" files with the map          
      my @files = map { ! /^\./ } readdir( $dh );
      ...
      }

Also remember that in any subroutine that you create you want to limit its side-effects. Don't rely on global data, and don't change global state. You'll have a much easier time managing your program when you keep control of those things.

brian d foy