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

In the logs I see this:

[Fri Nov 21 09:02:15 2008] [error] [client 76.17.99.50] Premature end +of script headers: test_ult.cgi
My test script looks like this:

#!/usr/bin/perl -w use strict; use warnings; use CGI; use CGI::Carp qw(fatalsToBrowser); $| = 1; my $q = CGI->new(); print $q->header, $q->start_html('test.cgi at ult****.com'), $q->h1("Found me in ult****.com vhost "), $q->end_html; $| = 0; 1;
The Q&A section (How to get over 'premature end of script headers' in Apache?) on this site mentions that suExec could be an issue and in this situation the relevant CentOS / plesk server has an http.conf file enabling suExec.

Carp responds with a blank browser screen (and empty source).

As root, running this from a command line, look like this:

cgi-bin]# ./test_ult.cgi Content-Type: text/html; charset=ISO-8859-1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-U +S"> <head> <title>test.cgi at ult****.com</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1 +" /> </head> <body> <h1>Found me in ult****.com vhost </h1> </body> </html> cgi-bin]#
So I have a couple of questions here. Is there a simple way, as root, from the command line, to run this script as the apache user? If this script is not running as apache, how would I determine what user suExec has it running as? Can anyone offer any other pointers to help me determine what my issue here might be?

My real script (nms' FormMail.pl) is also throwing this same error. I usually work in Debian, not CentOS. I usually work at a cli, and am not use to seeing Plesk written config files warning me I will break everything should I edit them. Not sure to what extent this unusual environment may be a factor. I'm hopeful that if I can figure this out for a simple test script, I'll be able to translate this to the real issue I face this morning.

-- Hugh

UPDATE:

grep apache /etc/passwd says: apache:x:48:48:Apache:/var/www:/sbin/nologin
ANOTHER UPDATE:

Thanks all. And thank you ig and eye for the pointers about suExec and SELinux. And I had not known how to set a temporary shell with the su command. That looks useful for the future.

To resolve this issue Friday night, I had to immerse myself in the suExec documentation for the first time and feel that I have finally wrapped my head around how that works. Once doing so, it was a rather quick path to resolving this issue. But first I had to spend an hour or two immersing myself in literature about seLinux, before finally assuming that it was not the issue in this case. However there is more practical advice in eye's and ig's posts below, than in the articles I read Friday. Fully understanding seLinux will have to wait for another day, but it will start with a review of this thread, when the time comes. Thanks again.

if( $lal && $lol ) { $life++; }

Replies are listed 'Best First'.
Re: Premature end of script headers more annoying than usual . . .
by MidLifeXis (Monsignor) on Nov 21, 2008 at 15:27 UTC
    echo "GET /foo/bar/test_ult.cgi HTTP/1.0\n\n" | telnet localhost 80

    See what the output is. I would bet that either (1) there is something else being printed first, or (2) there is a permission error of some sort and nothing at all is being printed, generating the error in the logs.

    Update: Minor typo correction.

    --MidLifeXis

Re: Premature end of script headers more annoying than usual . . .
by moritz (Cardinal) on Nov 21, 2008 at 15:29 UTC
    Is there a simple way, as root, from the command line, to run this script as the apache user?
    $ su apache -c './test_ult.cgi'

    Please also note that (to the best of my knowledge, I never used it) CentOS, being a RedHat clone, uses SeLinux, which means that you have to set a special security contexts on the scripts you're trying to execute (if that feature is enabled).

Re: Premature end of script headers more annoying than usual . . .
by almut (Canon) on Nov 21, 2008 at 15:50 UTC

    I think moritz's point about SELinux is a good one. So, you might first want to check whether it's enabled (cat /etc/selinux/config — IIRC that's the respective config file). In case it's enabled, you could temporarily disable it (though I think that would require a server reboot...), to see whether the problem goes away.

    If all else fails, you could start Apache in debugging mode (option -X — in which case it will start only one child/worker), attach strace to that process (via option -p, as root), and then make the request. The strace output should give you a clue as to what's wrong...

      I have no prior experience with selinux and so am flying blind here.

      ls /etc/selinux/ restorecond.conf semanage.conf
      but no config, for whatever that is worth . . .

      man apachectl shows no -X or -p options. Do I feed those to /etc/init.d/apache start instead? I'm not sure how to try your advise, here. Further guidance would be appreciated.

      -- Hugh

      if( $lal && $lol ) { $life++; }
        ls /etc/selinux/ restorecond.conf semanage.conf

        Without doing further research myself, I can't really comment on those files... What do they contain?  At least, the fact that there is a /etc/selinux/ directory indicates that the issue might not be totally irrelevant...

        man apachectl shows no -X or -p options.

        Sorry if I wasn't being clear. -X is an option of the actual binary (i.e. httpd or apache, depending on distro), and the -p option belongs to strace.

        You could either simply start httpd manually (after having terminated the running instances with apachectl as usual), or edit the -X into the apachectl script (in the "start" section1). If you do start it manually, it's probably a good idea to first check with which options it is being run currently (ps axf, or some such), and use those in addition to -X. Also, I forgot to mention that with strace you probably also want the option -f.

        ___

        1 something like:

        ... start|stop|restart|graceful) $HTTPD -X ... ^ insert this
Re: Premature end of script headers more annoying than usual . . .
by eye (Chaplain) on Nov 22, 2008 at 09:09 UTC
    You can get the status of selinux with the "getenforce" command (example from CentOS 5.2):
    $ /usr/sbin/getenforce Enforcing $
    If it is in "Enforcing" mode and you are authorized to place it in "Permissive" mode, you can do so with:
    sudo /usr/sbin/setenforce 0
    and restore "Enforcing" mode with:
    sudo /usr/sbin/setenforce 1
    In "Permissive" mode, selinux logs things it finds objectionable, but does not prevent them. In my limited experience, this has always been able to distinguish an selinux issue from other issues. (If you want to disable selinux entirely, you'll need to modify "/etc/selinux/config".)

    CAUTION: I don't recall whether changes to enforcing mode made in this way persist across system restarts.

    If you determine that this is an selinux issue or it is not an option to switch to "Permissive" mode even temporarily, the next step would be to look at "/var/log/audit/audit.log".

    I've heard that CentOS 5 has vastly improved tools to help diagnose selinux problems, but I have no experience with them.

Re: Premature end of script headers more annoying than usual . . .
by hesco (Deacon) on Nov 21, 2008 at 15:35 UTC
    Thanks MidLifeXis:

    Here is what I see:

    [root@ cgi-bin]# echo "GET /var/www/vhosts/<vhost>/cgi-bin/test_ult.cg +i HTTP/1.0\n\n" | telnet localhost 80 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Connection closed by foreign host. [root@ cgi-bin]#
    I'm not sure what that tells me, though. I get the same result when I address it only with the relative path from the URi (echo "POST /cgi-bin/test_ult.cgi HTTP/1.0\n\n" | telnet localhost 80). Any clues in your world?

    -- Hugh

    if( $lal && $lol ) { $life++; }

      Yep, the server is not executing the script. I would go with moritz's response. It shows promise.

      --MidLifeXis

Re: Premature end of script headers more annoying than usual . . .
by ig (Vicar) on Nov 23, 2008 at 00:43 UTC

    To determine if your script is running and what user and group it runs as, you might have it write to STDERR and add a long sleep. Output to STDERR should appear in the web server error log. While it is sleeping you can inspect the process with ps to determine security context. If nothing appears in the error log and you can't see the process with ps, then the script is probably not running at all, in which case suexec and selinux appear to be your prime suspects.

    If suexec is running, the web server error log should have something like the following each time the server starts:

    [notice] suEXEC mechanism enabled (wrapper: /path/to/suexec)

    If it is running, there should be a log file: suexec_log in the web server log directory, by default. This should indicate the problem if suexec is refusing to run your script. Note that with suexec the user and group your script runs as may be specified by an SuexecUserGroup directive in the apache configuration.

    The sestatus command will tell you whether selinux is running and enforcing, with output similar to the following:

    [root@localhost ~]# sestatus SELinux status: enabled SELinuxfs mount: /selinux Current mode: enforcing Mode from config file: enforcing Policy version: 21 Policy from config file: targeted

    On my system, it says:

    [root@localhost ~]# sestatus SELinux status: disabled

    I have selinux disabled, but I understand that as of RHEL/CentOS 5, messages are written to the audit logs rather than /var/log/messages and the setroubleshoot command is supposed to be make reviewing the logs easy. http://www.linuxtopia.org/online_books/centos5/centos5_administration_guide/centos5_rhlcommon-chapter-0017.html might be helpful.

Re: Premature end of script headers more annoying than usual . . .
by hesco (Deacon) on Nov 21, 2008 at 15:42 UTC
    I had tried that earlier, when still tossing this issue around in the cb, only without the single quotes around the script name, but got these same results.

    [root@s15261758 cgi-bin]# su apache -c './test_ult.cgi' This account is currently not available. and grep apache /etc/passwd says: apache:x:48:48:Apache:/var/www:/sbin/nologin
    so the account does in fact exist.

    if( $lal && $lol ) { $life++; }

      su says This account is currently not available because the shell is /sbin/nologin

      You can specify an alternate shell as follows:

      # su apache -s /bin/bash -c './test_ult.cgi'
      so the account does in fact exist.
      Maybe, but its still not available.