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

Hello. I just started learning perl and I ran into a
problem. Usually I debug errors pretty fast, but I've
been sitting on this one for 2 days straight and can't
find the solution. Well, here it is:


#!/local/0/bin/perl
use CGI qw(:all);
print header;
.
..
...
/*..........Thes lines just crash the program (it stopps
sending to http...(never gets to the last line, and
never returns the error either..*/

$_=param('nameoffile');
tr/a-z//cd;
print ">$_";
if (!(open (OUT, ">$_"))) { print "Error opening file $_
for writing."; exit 0; }

print "end\n";

/* If i change the $_=param('nameoffile'); line to , say
$_="aaa"; it works fine and creates the file. Are there any
funny characters returned with the param that I
cannot sort out with tr/a-z//cd? This is killing me. I tried single quotes, didn't help.

Please help...

Replies are listed 'Best First'.
Re: Opening a file error
by swiftone (Curate) on Jun 09, 2000 at 18:07 UTC
    Update: At first I considered your tr// statement to mean that you would be doing full security checking, but it has (rightly) been pointed out that there are huge security concerns here that it would be wrong to ignore. Read KM's reply below

    1) In this line:

    if (!(open (OUT, ">$_"))) { print "Error opening file $_ for writing."; exit 0; }
    Try this:
    if(!open(OUT, ">$_")){ print "Error opening file $_ for writing: $!"; # $! holds the error mesg exit 0; }
    The more tradional way to write this is:
    open(OUT, ">$_") or die "Can't open $_ for writing: $!";
    Since you are using this in a CGI program, it'd be a good idea to use perlfunc:warn or perlfunc:die too. (See the module CGI::Carp for http friendly die and warn functions)

    But it doesn't seem to get to this point, so this isn't the source of the troubles. 2) some more information would be useful. You have the line:

    print ">$_";
    Does it get printed? (Note that print statements might occur but not get printed if they are in the buffer when the program gets confused. Either use warn statements, or set $|=1, which will autoflush any statements in the buffer).
      This reply didn't mention two other things with the original code that should be pointed out. First, you are not using -T (read perlsec and perlrun). Second, you aren't using -w or strict (perldoc strict and perlrun). You should NEVER NEVER NEVER NEVER create a file based on raw user input which you are doing. This is BAD BAD BAD. Learn now before you learn the hard way. You seem to use tr// to help make this safe, but it isn't the best way, and safer programming is better programming. Look at Untaint.pm for untainting of the input and read perlsec, twice. Also, I see no reason why you are using $_. Also, please skim this node but really pay attention to the comments I made on that node following it. It deals with file locking. You have no file locking here, and possibly do not need it, however you should take a look and familiarize yourself with it if you are using text files and not a DB.
      swiftone is right about looking at CGI::Carp. It is a great tool for debugging CGI, just add this in your script:

      use CGI::Carp qw(fatalsToBrowser);

      and you will get more useful error messages to the browser, most of the time at least :)

      Cheers,
      KM

      Why are you using c-style comments? If these are in your code, then there's your trouble.
RE: Opening a file error
by Ovid (Cardinal) on Jun 09, 2000 at 20:59 UTC
    If you're trying to debug a CGI script, one thing you can do is run the program from the command line. If you have instatiantiated a new CGI object
    $query = new CGI;
    It will ask for name/value pairs and you enter them one per line such as
    name=Irving color=Blue money=happiness
    You would enter those for whatever value your script expects, if any. When you're done, or if you are not passing any name/value pairs to the script, hit control-D and the script will run. If you have a lot of name/value pairs, you can toss them into a file and use
    $query = new CGI(FILENAME);
    That will read the information from the file without you needing to retype it every time.

    If you haven't used "new CGI" the program will run without asking for name/value pairs.

    This may seem like a bit more work up front, but I find that it allows for a lot of quick and dirty debugging from the command line. You may also want to look into the Perl debugger. Once you get used to it, it's a wonderful tool.

    Final note: not to be redundant, but the others are right when they say to never create a CGI script without -wT and use strict. A good source for initial information is a brief overview of Safe Scripting in Perl that can be found at perl.com. Also, on a Linux or Unix system with perl documentation installed, enter the following at the command line: <CODE> perldoc perlsec </

RE: Opening a file error
by rendhalver (Initiate) on Jun 09, 2000 at 18:12 UTC
    $_=param('nameoffile'); tr/a-z//cd; print ">$_"; if (!(open (OUT, ">$_"))) { print "Error opening file $_ for writing."; exit 0; } why are you using $_ to store a file name anyway ?? try using a declared variable for storing the file name that will work
RE: Opening a file error
by Cheburashka (Acolyte) on Jun 10, 2000 at 09:13 UTC
    Ok, I took all your advice and tried to run it from the
    shell (by writing in the params manually (yyy for filename)) and the script
    work fine (creates the file i ask yyy.html)!!! But when I
    run it from http (I added the use CGI::Carp qw
    (fatalsToBrowser); line) it outputs the following error to
    http:

    // start

    yyy.html
    Content-type: text/html
    Software error:
    Insecure dependency in open while running setgid
    at /dev/fd/6 line 63.
    Please send mail to this site's webmaster for help.


    //end

    once again the script is:
    **************************************
    **************************************

    #!/local/0/bin/perl
    use CGI qw(:all);
    use CGI::Carp qw(fatalsToBrowser);
    print header;
    .
    ..
    ...
    $nameoffile=param('nameoffile');
    #By the way when I tried to use
    #$nameoffile=$query->param('nameoffile'); it returned the
    #error "..param must be part of some structure..."
    $myfilepath="$nameoffile".".html";
    print "$myfilepath"; #good path returned to html

    #http crashes here, unix prompt works fine
    if (!(open (OUT, ">$myfilepath"))) { print "Error opening
    file $myfilepath for writing."; exit 0; }

    print "end\n"; #http never gets here

    **************************************
    **************************************

    //none of the other shell debugging hints really apply
    (like using $! for error) because script works great from
    the shell.
    Any ideas what this could mean anyone?
      You're getting the error:
      > Software error: > Insecure dependency in open while running setgid
      which means that your software is doing something good and right. You said earlier that you weren't yet worrying about security in your scripts... well, you should be happy that you're getting this error, then! It means that at least you have software looking out for your security.

      Anyway, if you read perlsec, you'll find that this error is occurring because you're using tainted data--data that's coming from a source external to your program. This is a problem in a CGI environment, because you don't control the input to your script. And in fact, the example you use is a huge security hole.

      To untaint your data, you can check run it through a regular expression that checks for safe characters, then grab the safe characters and use those for your filename. perlsec has this example:

      if ($data =~ /^([-\@\w.]+)$/) { $data = $1; # $data now untainted } else { die "Bad data in $data"; # log this somewhere }
      So you can do something similar to your $nameoffile variable. Run it through a similar regular expression and then set it to $1.

      Read perlsec so that you write secure code.

      By the way, you also said this:

      > #By the way when I tried to use > #$nameoffile=$query->param('nameoffile'); it returned the > #error "..param must be part of some structure..."
      That code tries to call the param method on the $query object. You don't have a $query object defined, so you can't call a method on it. Just using
      param('nameoffile')
      like you are should work fine.
Re: Opening a file error
by rendhalver (Initiate) on Jun 09, 2000 at 19:02 UTC
    ask me about perl, i dare you $_=param('nameoffile'); tr/a-z//cd; print ">$_"; if (!(open (OUT, ">$_"))) { print "Error opening file $_ for writing."; exit 0; } had a think it could be stuffing up because you have not imported param in the name space of your script if not you will have to fully qualify it ie $var = $query->param('nameoffile');
Re: Opening a file error
by Anonymous Monk on Jun 09, 2000 at 21:14 UTC
    Hello. I am the guy who posted the question. WOW, I didn't
    expect so many replies in such a short time...I thank
    you for all your advice but I would like to point out
    that:

    1. Yes, print ">$_"; prints a perfectly good path.

    2. I don't care for security so far, all I want to
    understand is why when I enter ,say, myfile.html in a
    form, it UNDERSTANDS it, spits it out at the print ">$_"; line,
    and seems to behave PERFECTLY WELL ..EXCEPT when it gets to
    the open file line.

    Thanx for the debugging tips though, I will examine each
    reply very careful. I think with all that new info, It will
    be pretty easy to debug it. Averall I like Perl
    very much. Reminds me a lot of C (my favorite language of all time.)

    Eugene
      1. Yes, print "<$_"; prints a perfectly good path.
      This stumps me then. Although I'm not up on the tr// operator...what happens if you comment that out and try "safe" names (such as "aaa")?

      2. I don't care for security so far, all I want to understand is why when I enter ,say, myfile.html in a form, it UNDERSTANDS it, spits it out at the print ">$_"; line, and seems to behave PERFECTLY WELL ..EXCEPT when it gets to the open file line.
      Well, I'm sure KM has already given you a security rant. I'll just add that it's easier to include security from the start than it is to rewrite. That said, I understand your concerns about understanding what is going on.

      Let us know what kind of warnings it generates.

      Averall I like Perl very much. Reminds me a lot of C (my favorite language of all time.)
      Soon you will love perl more. (near) Equal power, much easier to program. C will always have it's place though (gotta write the perl interpreter in something :))

      When will you start caring about security? When you write a big hole in your code and you get hacked? Even when I paint the front door to my house, I keep a lock on it. Learn to do everything the right way, right away.

      Cheers,
      KM