1

I was working on client program in pure html/javascript which would be able to send the folder, file and its contents as paramaters in a post request to the target cgi script (i.e saveFile.cgi ).

I am able to retrieve the data from the post request , but i am unable to create a file/folder using these form data in the script, yet i am able to print these values using print.

Also, I am able to create file/folder using the exact string literal which I was trying to retrieve from the post request.I am not understanding where i am going wrong.

I am programming in a windows environment:

Client Code :

var data = {
             "folder": variant,
             "file"  : "metadata.json",
             "content": response
           };

           $.post('../cgi-bin/demos/saveJSON.cgi', data, function(resp) {
                  // Do something with the request
           }, 'json');

Server-Side/CGI Script:

#!C:\perl\bin\perl.exe -wT
    use CGI;
    use JSON;

    print "Content-type: text/html\n\n";

    $query = new CGI;

    $folder  = $query->param("folder");
    $file    = $query->param("file");
    $content = $query->param("content");

    #print "Folder " . $folder ."<br/>";
    #print "File " . $file ."<br/>";
    #print "Content " . $content ."<br/>";

    mkdir($folder, 0700) unless(-d $folder);
    open(OS,">$folder/$file") or die("Cannot write to file");
    print OS $content;
    close(OS);
touchStone
  • 317
  • 2
  • 16

2 Answers2

1

i am unable to create a file/folder using these form data in the script, yet i am able to print these values using print

Almost certainly, the problem is that your web server doesn't have permissions to create a file in the directory where you are trying to create it. You can check that theory by improving the error checking for the open() call and looking in the web server error log.

# $! contains the details of the error
open(OS,">$folder/$file") or die("Cannot write to file '$folder/$file': $!");

You'll then have to change your processing so that you're writing to a directory where you have the correct permissions.

Some other suggestions.

  • Always include use strict and use warnings.
  • Use my $query = CGI->new rather than $query = new CGI.
  • Use lexical filehandles and three arguments to open()
    • open my $os_fh, '>', "$folder/$file" or die "..."
  • Consider moving away from CGI to a modern solution like Dancer.
Dave Cross
  • 68,119
  • 3
  • 51
  • 97
  • If the filename/folder was part of a string literal the folders/files get created perfectly but same thing doesn't work with POST params. These params are printing right but I am unable to use them to create a file while the string literal way works.I don't understand this hypocrisy. – touchStone Mar 04 '15 at 14:48
  • Then I can only reiterate my suggestion about the enhanced error logging around the call to `open()`. Try that and then update your post with details of what you get in the error log. There must be some weird characters getting into your parameters. – Dave Cross Mar 04 '15 at 15:08
  • Nailed it. It was all due to the "taint or -T" flag set for the perl command. This prevented it from executing variables received from form data. Check: http://stackoverflow.com/questions/4239076/t-option-in-perl – touchStone Mar 04 '15 at 19:23
  • So, once you improved your error logging, you immediately saw what the problem was? – Dave Cross Mar 04 '15 at 19:28
  • I do always check the apache/logs/error.txt but didn't pay much attention to -T flag thing because the error was not very specific to this issue and the above link , supplemented the theory about "taint". Anyways thanks :) for all your help. – touchStone Mar 04 '15 at 19:37
-1

I don't know whether you can install modules on your server. If yes, I would definitely advise you to use some abstraction layer like IO::All.

...
$folder  = $query->param("folder");
$file    = $query->param("file");
$content = $query->param("content");

# very minimal folder and filename sanitizing: allow only 
# alphanumeric characters. No slashes!
$folder =~ s{[^a-z0-9_\-.]}{}gi;
$file   =~ s{[^a-z0-9_\-.]}{}gi;

use IO::All;
io( $folder )->mkdir;
io( "$folder/$file" ) < $content; # yes, the < is like "put into"

The cool thing about IO::All is that is hides the handling of file handles, buffers and such and will die with an error when something goes wrong - like when the directory cannot be created.

See: IO::All on metacpan

The sanitizing is very minimal and does not allow for subdirctories, but you don't want anybody to write send something like

{ 
    folder:  "/var/www-data/.evil", 
    file:    "hacker.zip",
    content: "..someting really evil.."
}

to upload this to your server.

Anyhow, to install IO::All use either

cpan IO::All

or on Debian/Ubuntu

sudo apt-get install libio-all-perl
gutschilla
  • 157
  • 1
  • 4