RHCE – Create a hello world CGI app on CentOS/RHEL 7

Common Gateway Interface (CGI) is a protocol that let’s you run custom scripts via the web. It’s not as commonly used as before, but you still need to know this as part of the RHCE exam objectives.

In Apache, there is a default folder where you can place scripts in, which will then get handled by the CGI protocol. This default folder is declared in the main Apache config file, here’s the relevant extract:


    #
    # Redirect: Allows you to tell clients about documents that used to
    # exist in your server's namespace, but do not anymore. The client
    # will make a new request for the document at its new location.
    # Example:
    # Redirect permanent /foo http://www.example.com/bar

    #
    # Alias: Maps web paths into filesystem paths and is used to
    # access content that does not live under the DocumentRoot.
    # Example:
    # Alias /webpath /full/filesystem/path
    #
    # If you include a trailing / on /webpath then the server will
    # require it to be present in the URL.  You will also likely
    # need to provide a  section to allow access to
    # the filesystem path.

    #
    # ScriptAlias: This controls which directories contain server scripts.
    # ScriptAliases are essentially the same as Aliases, except that
    # documents in the target directory are treated as applications and
    # run by the server when requested rather than as documents sent to the
    # client.  The same rules about trailing "/" apply to ScriptAlias
    # directives as to Alias.
    #
    ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"


Here we can see the ScriptAlias setting. This setting maps the part of a URL to a directory path on the machine. We can drop scripts into /var/www/cgi-bin/, and then we should be able to access them using the ‘/cgi-bin/’ alias in the url, e.g. something like http://example.com/cgi-bin/test.sh

We now need to check that the cgi module is running:

[root@webserver cgi-bin]# httpd -M | grep cgi
 proxy_fcgi_module (shared)
 proxy_scgi_module (shared)
 cgi_module (shared)
 fcgid_module (shared)

Since our box is in SELinux enforcing mode, Theres a SE boolean that needs to be enabled to allow the use of CGI scripts:

[root@webserver cgi-bin]# getsebool -a | grep -i cgi
git_cgi_enable_homedirs --> off
git_cgi_use_cifs --> off
git_cgi_use_nfs --> off
httpd_enable_cgi --> on

In case it wasn’t enable then you can enable it (p)ersistantly by running:

$ setsebool -P httpd_enable_cgi 1

Now to try out CGI, I created the following hello world bash script:

[root@webserver cgi-bin]# ls -lZ /var/www/cgi-bin/test.sh
-rwxr-xr--. apache apache unconfined_u:object_r:httpd_sys_script_exec_t:s0 /var/www/cgi-bin/test.sh
[root@webserver cgi-bin]# cat /var/www/cgi-bin/test.sh
#!/bin/bash
echo 'Content-type: text'
echo
echo
echo 'hello world'
echo
echo

We added the Content-Type setting so that the web browser know hot to interpret the content. Also notice that the script needs to have a specific security type attribute ‘httpd_sys_script_exec_t’.

Now let’s test out this script in the bash terminal first:

[root@webserver cgi-bin]# /var/www/cgi-bin/test.sh
Content-type: text


hello world


Now you can try accessing this link using firefox/chrome/curl, e.g.:

[root@webserver cgi-bin]# curl http://localhost/cgi-bin/test.sh
 
hello world

Using a non standard CGI folder

If you want to change the CGI folder to a different location, then you need to take 4 steps:

  1. Create the new folder, and give Apache ownership of this folder
  2. Place scripts into the new folder
  3. Update SELinux configurations to support the new cgi script location
  4. Update the main Apache config, or create/edit vhost file
  5. Restart httpd daemon

Now let’s create the new cgi folder:

[root@webserver cgi-bin]# mkdir /var/web_scripts

Next we create a dummy script and :

[root@webserver cgi-bin]# cat /var/web_scripts/test.sh
#!/bin/bash
echo 'Content-type: text'
echo
echo
echo 'hello world - this time we are in non-standard folder'
echo
echo

Next we check if the ownership, permissions, and security context looks correct:

[root@webserver cgi-bin]# ls -lZ /var/ | grep web_scripts
drw-r--r--. root root unconfined_u:object_r:var_t:s0   web_scripts
[root@webserver cgi-bin]# ls -lZ /var/web_scripts/test.sh
-rwxr-xr--. root root unconfined_u:object_r:var_t:s0   /var/web_scripts/test.sh

To start with we need to fix the ownership:

[root@webserver cgi-bin]# chown -R apache:apache /var/web_scripts/

Next the script needs to be executable:

chmod ug+x /var/web_scripts/test.sh

Next we need to fix the SELinux type security attribute setting, first find an exmaple of what the setting should be:

[root@webserver cgi-bin]# ll -lZ /var/www/ | grep cgi
drwxr-xr-x. root root system_u:object_r:<strong>httpd_sys_script_exec_t</strong>:s0 cgi-bin

Now we create and apply the SELinux policy:

[root@webserver cgi-bin]# semanage fcontext -at httpd_sys_script_exec_t "/var/web_scripts(/.*)?"
[root@webserver cgi-bin]# restorecon -Rv /var/web_scripts
restorecon reset /var/web_scripts context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:httpd_sys_script_exec_t:s0
restorecon reset /var/web_scripts/test.sh context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:httpd_sys_script_exec_t:s0

Then confirm that this has worked:

[root@webserver cgi-bin]# ls -lZ /var/ | grep web_scripts
drwxr-xr-x. apache apache unconfined_u:object_r:httpd_sys_script_exec_t:s0 web_scripts
[root@webserver cgi-bin]# ls -lZ /var/web_scripts
-rwxr-xr--. apache apache unconfined_u:object_r:httpd_sys_script_exec_t:s0 test.sh

Now we make Apache aware of our new folder. We can either update the main config file, or edit/create a vhost file. We’ve already covered other examples where we used vhosts, so this time we’ll edit the main Apache config file. SO we made a duplicate of the original ScriptAlias line and commented out the original line and modified the duplicate so that we end up with:

    #ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
    ScriptAlias /cgi-bin/ "/var/web_scripts"

We also have to add in a new Directory directive to override the high level deny ‘/’ directive, so we insert the following extract:

    <Directory "/var/web_scripts">
        AllowOverride None
        Options None
        Require all granted
    </Directory>

Then we restarted httpd:

[root@webserver web_scripts]# systemctl restart httpd

Now everything should be working, so let’s test with Firefox/Chrome/elinks/curl:

[root@webserver web_scripts]# curl http://localhost/cgi-bin/test.sh
 
hello world - this time we are in non-standard folder

Success!

Take the RHCSA Quiz

This article is part of our RHCSA Study guide (click on the yellow tab on the far left). By the end of this article you should be able to answer the following questions:


Where can you find out where is the cgi folder located?

See ScriptAlias setting under the main Apache config file.

What is the command to check if the cgi module is installed?

$ httpd -M | grep cgi

What is the command to view SELinux boolean settings for cgi?

$ getsebool -a | grep cgi

What is the command to persistantly enable cgi in se boolean settings?

$ setsebool -P httpd_enable_cgi on

Give an example of a hello world cgi script?

$ cat /var/www/cgi-bin/test.sh
#!/bin/bash
echo ‘Content-type: text’
echo
echo
echo ‘hello world’
echo
echo

What is the command to call this cgi script using curl?

$ curl http://localhost/cgi-bin/test.sh

What are the steps needed to change the default cgi folder, e.g. change it to /var/cgi?

– create the new folder and give apache ownership
– place scripts in the new folder
– sort up selinux file security attribute settings.
– update the main config file – need to update two sections
– restart apache daemon
– then test using curl

question?

answer

question?

answer

question?

answer

question?

answer

question?

answer

question?

answer