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

Background
I have some mail spool files that are corrupted.
I want to retrieve some binary attachments from these spool files.
Solution so far
This script reads in a file in the same directory, unencodes it, and then writes it out to new file, the name of which is taken from STDIN.
Problem
I get the following error message when I run the script.
(the filename i'm entering into STDIN is "info.wav") Insecure dependancy in open while running with -T switch at ./base64.pl line 48 Which relates to the following line:
open (FILEOUT, "> $file_out") or die "Couldn't create output file:\n$!\n";
I have tried running a regex on $ENV{PATH}, and it wasn't that, so I'm not sure what is failing Taint.
As you can see in the code below, the variable being used in the open, has been passed through a regexp, so it should be untainted.
#!/usr/bin/perl -wT use strict; use MIME::Base64; my $file_in = 'base64data'; ### get variables chomp (my $file_out = <STDIN>); my $data_enc; my $data_unenc; $ENV{PATH} = ""; ### check file_in unless ($file_in =~ /^[\w][\w\._-]*$/) { print "Insecure file_in\n"; exit; } if ($file_in =~ /^\.{2,}$/) { print "Insecure file_in path\n"; exit; } ### untaint file_out unless ($file_out =~ /[\w][\w\._-]*$/) { print "Insecure file_out\n"; exit; } if ($file_out =~ /^\.{2,}$/) { print "Insecure file_out path\n"; exit; } ### get the data from input_file open (FILEIN, "< $file_in") or die "Couldn't open input file:\n$!\n"; while (<FILEIN>) { $data_enc .= $_; } close (FILEIN); ### unencode the data $data_unenc = decode_base64($data_enc); ### write the data to the output file open (FILEOUT, "> $file_out") or die "Couldn't create output file:\n$!\n"; print FILEOUT $data_unenc; close (FILEOUT); ### finish print "Operation successful.\n"; exit;

Replies are listed 'Best First'.
Re: Taint problem opening file to write
by derby (Abbot) on Apr 30, 2002 at 12:35 UTC
    your $file_out is still tainted. You need to re-assign to $file_out a sub-pattern match:

    from perlsec, The only way to bypass the tainting mechanism is by referencing subpatterns from a regular expression match. Perl presumes that if you reference a substring using $1, $2, etc., that you knew what you were doing when you wrote the pattern.

    so you need to do something like this (modified from perlsec)

    if ($file_out =~ /^([-\@\w.]+)$/) { $file_out = $1; # $data now untainted } else { die "Bad data in $file_out"; # log this somewhere }

    -derby

      Thanks,
      I've changed the part that read
      unless ($file_in =~ /^[\w][\w\._-]*$/) { print "Insecure file_in\n"; exit; }
      to ...
      if ($file_out =~ /^([\w][\w\._-]*)$/) { $file_out = $1; } else { print "Insecure file_out\n"; exit; }
      And I also fixed the regexp that checked for double dots, from /^\.{2,}$/ to... /\.\./
Re: Taint problem opening file to write
by Necos (Friar) on Apr 30, 2002 at 12:41 UTC
    From what I gather, your tainting is not from the filename (because you SEEM to have untainted it). However, you should be very wary of this:

    open(FILE,">$file"); vs. open(FILE,"> $file");

    The first one (if untainted properly), will make sure there are no leading spaces in the filename. The second, may or may not work how you suspect, and just MIGHT be the cause of the problem. I don't think I've read any book that uses open(F,"> $file");.

    Looking at your code a third time, I noticed that you don't bother to look for leading or trailing spaces (regex \s) in $file_out. So, let's just eliminate part of that problem with a:  $file_out =~ s/\s+//;.

    Hope that helps some...

    Theodore Charles III
    Network Administrator
    Los Angeles Senior High
    4650 W. Olympic Blvd.
    Los Angeles, CA 90019
    323-937-3210 ext. 224
    email->secon_kun@hotmail.com
    perl -e "map{print++$_}split//,Mdbnr;"
      Here is where i recommend the 3-arg form of open. From the docs:

      Use 3-argument form to open a file with arbitrary weird characters in it,

      open(FILE, '<', $file);
      otherwise it's necessary to protect any leading and trailing whitespace:
      $file =~ s#^(\s)#./$1#; open(FOO, "< $file\0");

      jeffa

      L-LL-L--L-LL-L--L-LL-L--
      -R--R-RR-R--R-RR-R--R-RR
      B--B--B--B--B--B--B--B--
      H---H---H---H---H---H---
      (the triplet paradiddle with high-hat)
      
      Necos,

      from my version of the open documention (perl 5.6.1) but not the online monks version of the open doc -

      In the 2-arguments (and 1-argument) form of the call the mode and filename should be concatenated (in this order), possibly separated by spaces.

      so you can separate the mode from the filename by a space (and the code in doio.c backs that up) but you're right, it's not idiomatic.

      -derby