http://www.perlmonks.org?node_id=639564

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

I am trying to run a simple Perl script that calls an external executable (called 'ameme'). A CGI script would simply execute this 'script.pl'.
# MyPerl script.pl my $thebase = $ARGV[0] || 'bar'; my $my_repo = "/home/monkfan/public_html/FOO/results/" .$thebase. "\.o +ut"; system("/home/monkfan/bin/ameme /home/monkfan/public_html/FOO/input_fi +les/input_file.txt > $my_repo");
Strangely these things happen:
I've checked the permission of the executable and directory, all seems to be ok:
#under "/home/monkfan/public_html/FOO/cgi-bin/" -rwxrwxrwx 1 monkfan monkfan 127K Sep 17 13:20 ameme #under "/home/monkfan/public_html/FOO" drwxrwxrwx 13 monkfan monkfan 4.0K Sep 18 10:08 results drwxrwxrwx 2 monkfan monkfan 4.0K Sep 18 14:56 input_files #under "/home/monkfan/public_html/FOO/input_files/" -rw-r-xr-- 1 monkfan monkfan 327 Sep 18 13:31 input_file.txt
And looking at /var/log/httpd/error_log, there is no error message whatsoever.

Without any SU power, I am using the following:
Apache/2.2.3 (Red Hat)
What went wrong with my Perl script above?

Regards,
Edward

Replies are listed 'Best First'.
Re: System and CGI - File Created but not the Content
by moritz (Cardinal) on Sep 18, 2007 at 07:47 UTC
    You could try to use strace to find out what ameme is doing that could possibly fail under a different user.

    Does your system have selinux (or any other fancy security system) enabled?

    BTW this doesn't seem to be related to perl at all, so you're rather off topic here.

      Hi moritz,
      Yes it seems that it uses SELINUX, since I'm with:
      Enterprise Red Hat 4.1.1-52
      I tried strace with the following snippet in my script.pl:
      system("strace -o $my_repo /home/monkfan/bin/ameme /home/monkfan/publi +c_html/FOO/input_files/input_file.txt param1");
      It doesn't seem to give any error message and it gives the following:
      execve("/home/ewijaya/bin/ameme", ["/home/monkfan/bin/ameme", "numMoti +fs=10", "rcToo=off", "good=/home/monkfan/public_html/FOO"...], [/* 28 + vars */]) = 0 brk(0) = 0x85a6000 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, + 0) = 0x110000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or d +irectory) open("/etc/ld.so.cache", O_RDONLY) = 0 fstat64(0, {st_mode=S_IFREG|0644, st_size=58761, ...}) = 0 mmap2(NULL, 58761, PROT_READ, MAP_PRIVATE, 0, 0) = 0x111000 close(0) = 0 open("/lib/i686/nosegneg/libm.so.6", O_RDONLY) = 0 read(0, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\20t\223"..., +512) = 512 fstat64(0, {st_mode=S_IFREG|0755, st_size=208364, ...}) = 0 mmap2(0x934000, 155776, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE +, 0, 0) = 0x934000 mmap2(0x959000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ +DENYWRITE, 0, 0x24) = 0x959000 close(0) = 0 open("/lib/i686/nosegneg/libc.so.6", O_RDONLY) = 0 read(0, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0000\177"..., 5 +12) = 512 fstat64(0, {st_mode=S_IFREG|0755, st_size=1589232, ...}) = 0 mmap2(0x7f2000, 1308068, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRIT +E, 0, 0) = 0x7f2000 mmap2(0x92c000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP +_DENYWRITE, 0, 0x13a) = 0x92c000 mmap2(0x92f000, 9636, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ +ANONYMOUS, -1, 0) = 0x92f000 close(0) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, + 0) = 0x120000 set_thread_area({entry_number:-1 -> 6, base_addr:0x1208d0, limit:10485 +75, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_ +not_present:0, useable:1}) = 0 mprotect(0x92c000, 8192, PROT_READ) = 0 mprotect(0x959000, 4096, PROT_READ) = 0 mprotect(0x7ee000, 4096, PROT_READ) = 0 munmap(0x111000, 58761) = 0 brk(0) = 0x85a6000 brk(0x85c7000) = 0x85c7000 fstat64(0, 0xbf9640b0) = -1 EBADF (Bad file descripto +r) mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, + 0) = 0x3d1000 read(0, 0x3d1000, 8192) = -1 EBADF (Bad file descripto +r) write(2, "Short POST input.", 17) = -1 EBADF (Bad file descripto +r) write(2, "\n", 1) = -1 EBADF (Bad file descripto +r) exit_group(-1) = ?

      Regards,
      Edward
        Yes it seems that it uses SELINUX

        That explains a lot.

        Selinux provides "security contexts", and everything that a webserver may run is in the server's security context.

        This means that it is not allowed to do a whole lot of things, even if the file permissions allow it.

        Which in turn means that virtually everything can go wrong.

        I'd recommend to write a daemon that runs a normal user, validates it input and executes the program. The CGI script and the daemon can communicate via TCP or named pipes.

        I've written some CGI scripts under Fedora Core 4 (similar to Red hat) running SELinux, and there are some things you have to watch out for.

        The easiest way to verify if this is the problem: log in as root, then use this command:

        setenforce 0

        This will turn off the enforcement of SELinux security checks - but not the checking. Errors will continue to be logged. On my system the default location was /var/log/messages (this may vary from one flavor of linux to another).

        If the error with the CGI script goes away, you know it's SELinux. The log file should help give you a clue as to where the problem is. Turn enforcing back on with:

        setenforce 1

        If you want a CGI script to be able to write a file, the directory it's writing to much have read and execute permission:

        chmod 755 output_dir

        It must also have the proper SELinux security context:

        chcon -t httpd_sys_content_t output_dir

        Also, you have to remember that the CGI script runs with the user id of the web server. For apache, this is usually 'nobody' or 'www'. Make sure this user has permission to run the external executable (ameme?). Then make sure the executable has the the proper security context:

        chmod 755 ameme
        chcon -t httpd_sys_script_exec_t ameme

        You can use "ls -lZ" to check the current security context settings.

        Note also that the log file will contain errors that say what the expected context is, in the case SELinux blocks something from running. It will also give the path to the offending directory or executable.

Re: System and CGI - File Created but not the Content
by bart (Canon) on Sep 18, 2007 at 10:59 UTC
    It seems to me like the shell command line you calls with system did work, but that the program you tried to call did not. That way you can indeed end up with an empty file.

    Try adding capturing for STDERR too, redirecting it to a file of its own, with 2>$errfile. I bet you will find an error message in it, after you ran the script.

      Hi bart,
      You are right. I tried this command
      my $errfile = "errlog.txt"; system("/home/monkfan/bin/ameme /path/to/inputfile.txt param1 2> $errf +ile");
      The $errfile only gives this single line:
      Short POST input.
      However I don't know what does it mean. Tried to google but of no avail.
      Any idea? Or is there other way to get more complete error message?

      Regards,
      Edward
        It seems to me like your program runs, but that it doesn't like the input it gets. At least, the error message appears to come straight from that program. You'll have to check its documentation to understand exactly what this error message may mean.
Re: System and CGI - File Created but not the Content
by Gangabass (Vicar) on Sep 18, 2007 at 08:12 UTC

    I don't know there the problem is but... Maybe your executable use current dir for working (some config files for example) and when you run under CGI that dir doesn't right for you tool.

      I don't think this could be the problem. I tried to re-install 'ameme' in cgi-bin, and it still gives the same issue.

      Regards,
      Edward