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:
- Create the new folder, and give Apache ownership of this folder
- Place scripts into the new folder
- Update SELinux configurations to support the new cgi script location
- Update the main Apache config, or create/edit vhost file
- 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:httpd_sys_script_exec_t: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:
AllowOverride None Options None Require all granted
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
See ScriptAlias setting under the main Apache config file.
$ httpd -M | grep cgi
$ getsebool -a | grep cgi
$ setsebool -P httpd_enable_cgi on
$ cat /var/www/cgi-bin/test.sh
echo 'Content-type: text'
echo 'hello world'
$ curl http://localhost/cgi-bin/test.sh
- 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