Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to pass a file name to a cgi script that will then delete the file. It seems that I'm getting the file name passed correctly, but retrieving it with the CGI.pm param() call doesn't seem to work with unlink(). However, explicitly assigning the same file name works so it's not a problem with permissions. I tried the following two methods:

1) This method (hardcoding the path and file name) works...
$fileName = "../../20080101.txt"; printf ("File to be deleted: [%s]\n", "$fileName"); unlink( $fileName );
It prints...
File to be deleted: [../../20080101.txt]
and deletes (unlinks) the file.

2) This method (passing the path and file name as a cgi parameter, $q is a CGI object) does NOT work...
$fileName = $q->param('deletetarget'); printf ("File to be deleted: [%s]\n", "$fileName"); unlink( $fileName );
It prints...
File to be deleted: [../../20080101.txt]
but doesn't delete (unlink) the file.

Can anyone explain this?

Replies are listed 'Best First'.
Re: Why aren't these equivalent?
by tilly (Archbishop) on Jul 12, 2008 at 00:46 UTC
    That would happen for good reason if taint checking is on. See perlsec for an explanation of that. Looking in the error logs would also be helpful. Failing that, I'd double-check your assumptions.

    I should note that it does not look like you're using strict.pm, and your printf is adding unnecessary complexity, that line is more clearly written as:

    print "File to be deleted: [$fileName]\n";
    (The quotes you have around $fileName now means that it already is being interpolated.)
      You are correct, tilly. I turned off taint checking and now the parameter passing method works. I'll have to look into this a little deeper, since taint checking seems to be something I want to have active.

      Thank you all for your quick responses!

        PLEASE COME BACK HERE don't, please, run CGIs without -T. As holli said below, someone will pass you "/etc/passwd" as a parameter and you will be hosed. you can unlink the file IIRC if you check it against a regex, like this:
        unlink $1 if $fileName =~ /^(\.\.\/\.\.\/20\d{6}\.txt)$/;
        _without_ having to run it insecurely. as a plus, it will only remove the remove-able files.
        []s, HTH, Massa
Re: Why aren't these equivalent?
by Joost (Canon) on Jul 12, 2008 at 00:42 UTC
      That was my first thought as well. But if it was a permission problem, then neither method would work. unlink() just returns the number of files unlinked, so it returns 1 for the snippet that works and 0 for the snippet that doesn't work, in this case.
        So it can't for some reason unlink the file. There are two possibilities: 1. you don't have permissions. 2. the path does not point to the right file (for instance, you're in the wrong current directory).

        So what's in "$!" ? I did not put that code there for laughs. Anyone who wonders why some operation on a file didn't succeed and doesn't do a check + print $! gets what (s)he deserves.

Re: Why aren't these equivalent?
by holli (Abbot) on Jul 12, 2008 at 05:12 UTC
    Would you be so kind and tell us the url of the place where this little gem runs? I'd like to give it try with '/etc/passwd'.


    holli, /regexed monk/
Re: Why aren't these equivalent?
by jethro (Monsignor) on Jul 12, 2008 at 00:52 UTC
    To check whether Joost is right you might give delete rights to everyone for the file

    If that isn't the problem you might check for unprintable control-characters in the filename by printing the length of $fileName and check for problems with the current directory by printing $ENV{PWD} or by using an absolute pathname instead of the '../../'