httpd
— Apache Web Server
In this chapter, we will show how to set up a web server running virtual domains and dynamic CGI web pages. HTML is not covered, and you are expected to have some understanding of what HTML is, or at least where to find documentation about it.
36.1 Web Server Basics
In Section 26.2 we showed a simple HTTP session with the telnet command. A web serveris really nothing more than a program that reads a file from the hard disk whenever aGET /<filename>.html HTTP/1.0request comes in on port 80. Here, we will show a simple web server written in shell script. &Not by me. The author did not put his name in the source, so if you are out there, please drop me an email.-You will need to add the line
¨ ¥
www stream tcp nowait nobody /usr/local/sbin/sh-httpd
§ ¦
to your/etc/inetd.conffile. If you are runningxinetd, then you will need to add a file containing ¨ ¥ service www { socket_type = stream wait = no 5 user = nobody server = /usr/local/sbin/sh-httpd } § ¦
to your/etc/xinetd.d/directory. Then, you must stop any already running web servers and restartinetd(orxinetd).
You will also have to create a log file (/usr/local/var/log/sh-httpd.log) and at least one web page (/usr/local/var/sh-www/index.html) for your server to serve. It can contain, say:
¨ ¥
<HTML> <HEAD>
<TITLE>My First Document</TITLE> </HEAD>
5 <BODY bgcolor=#CCCCCC text="#000000">
This is my first document<P> Please visit
<A HREF="http://rute.sourceforge.net/"> The Rute Home Page
10 </A>
for more info.</P> </BODY>
</HTML>
§ ¦
Note that the server runs asnobody, so the log file must be writable by the no-bodyuser, and theindex.htmlfile must be readable. Also note the use of the get-peernamecommand, which can be changed toPEER=""if you do not have the net-pipespackage installed. &I am not completely sure if other commands used here are unavailable on other UNIXsystems.-.
¨ ¥ #!/bin/sh VERSION=0.1 NAME="ShellHTTPD" DEFCONTENT="text/html" 5 DOCROOT=/usr/local/var/sh-www DEFINDEX=index.html LOGFILE=/usr/local/var/log/sh-httpd.log log() { 10 local REMOTE_HOST=$1 local REFERRER=$2 local CODE=$3 local SIZE=$4
15 echo "$REMOTE_HOST $REFERRER - [$REQ_DATE] \
\"${REQUEST}\" ${CODE} ${SIZE}" >> ${LOGFILE} }
print_header() {
20 echo -e "HTTP/1.0 200 OK\r"
echo -e "Server: ${NAME}/${VERSION}\r" echo -e "Date: ‘date‘\r"
}
25 print_error() {
echo -e "Content-type: $DEFCONTENT\r" echo -e "Connection: close\r"
echo -e "Date: ‘date‘\r"
30 echo -e "\r" echo -e "$2\r" exit 1 } 35 guess_content_type() { local FILE=$1 local CONTENT case ${FILE##*.} in 40 html) CONTENT=$DEFCONTENT ;; gz) CONTENT=application/x-gzip ;; *) CONTENT=application/octet-stream ;; esac
45 echo -e "Content-type: $CONTENT"
} do_get() { local DIR 50 local NURL local LEN if [ ! -d $DOCROOT ]; then log ${PEER} - 404 0
55 print_error 404 "No such file or directory"
fi if [ -z "${URL##*/}" ]; then URL=${URL}${DEFINDEX} 60 fi DIR="‘dirname $URL‘" if [ ! -d ${DOCROOT}/${DIR} ]; then log ${PEER} - 404 0
65 print_error 404 "Directory not found"
else cd ${DOCROOT}/${DIR} NURL="‘pwd‘/‘basename ${URL}‘" URL=${NURL} 70 fi if [ ! -f ${URL} ]; then log ${PEER} - 404 0
print_error 404 "Document not found"
75 fi
print_header
guess_content_type ${URL}
LEN="‘ls -l ${URL} | tr -s ’ ’ | cut -d ’ ’ -f 5‘"
80 echo -e "Content-length: $LEN\r\n\r"
cat ${URL} sleep 3 } 85 read_request() { local DIRT local COMMAND 90 read REQUEST read DIRT REQ_DATE="‘date +"%d/%b/%Y:%H:%M:%S %z"‘" REQUEST="‘echo ${REQUEST} | tr -s [:blank:]‘"
95 COMMAND="‘echo ${REQUEST} | cut -d ’ ’ -f 1‘"
URL="‘echo ${REQUEST} | cut -d ’ ’ -f 2‘" PROTOCOL="‘echo ${REQUEST} | cut -d ’ ’ -f 3‘" case $COMMAND in
100 HEAD)
print_error 501 "Not implemented (yet)" ;;
GET) do_get
105 ;;
*)
print_error 501 "Not Implemented" ;;
esac
110 }
#
# It was supposed to be clean - without any non-standard utilities # but I want some logging where the connections come from, so
115 # I use just this one utility to get the peer address
#
# This is from the netpipes package PEER="‘getpeername | cut -d ’ ’ -f 1‘"
120 read_request
exit 0
§ ¦
Now runtelnet localhost 80, as in Section 26.2. If that works and your log files are being properly appended (usetail -f . . . ), you can try to connect to
http://localhost/with a web browser like Netscape.
Notice also that the commandgetsockname(which tells you which of your own IP addresses the remote client connected to) could allow the script to serve pages from a different directory for each IP address. This isvirtual domainsin a nutshell. &Groovy, baby, I’m in a giant nutshell.... how do I get out?
-36.2 Installing and Configuring Apache
Because all distributions package Apache in a different way, here I assume Apache to have been installed from its source tree, rather than from a .deb or .rpm
package. You can refer to Section 24.1 on how to install Apache from its source
.tar.gz file like any other GNU package. (You can even install it under Win-dows, Windows NT, or OS/2.) The source tree is, of course, available from The Apache Home Page http://www.apache.org. Here I assume you have installed it in --prefix=/opt/apache/. In the process, Apache will have dumped a huge reference manual into/opt/apache/htdocs/manual/.
36.2.1 Sample
httpd.conf
Apache has several legacy configuration files: access.confandsrm.confare two of them. These files are now deprecated and should be left empty. A single configura-tion file/opt/apache/conf/httpd.confmay contain at minimum:
¨ ¥ ServerType standalone ServerRoot "/opt/apache" PidFile /opt/apache/logs/httpd.pid ScoreBoardFile /opt/apache/logs/httpd.scoreboard 5 Port 80 User nobody Group nobody HostnameLookups Off ServerAdmin [email protected] 10 UseCanonicalName On ServerSignature On DefaultType text/plain ErrorLog /opt/apache/logs/error_log LogLevel warn 15 LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog /opt/apache/logs/access_log common DocumentRoot "/opt/apache/htdocs" DirectoryIndex index.html AccessFileName .htaccess 20 <Directory /> Options FollowSymLinks AllowOverride None Order Deny,Allow Deny from All
25 </Directory>
<Files ˜ "ˆ\.ht"> Order allow,deny Deny from all </Files>
30 <Directory "/opt/apache/htdocs">
Options Indexes FollowSymLinks MultiViews AllowOverride All
Order allow,deny Allow from all
35 </Directory>
<Directory "/opt/apache/htdocs/home/*/www"> Options Indexes MultiViews
AllowOverride None Order allow,deny
40 Allow from all
</Directory>
UserDir /opt/apache/htdocs/home/*/www
§ ¦
With the config file ready, you can move the index.html file above to
/opt/apache/htdocs/. You will notice the complete Apache manual and a demo page already installed there; you can move them to another directory for the time be-ing. Now run
¨ ¥
/opt/apache/bin/httpd -X
§ ¦
and then point your web browser tohttp://localhost/as before.
36.2.2 Common directives
Here is a description of the options. Each option is called a directive in Apache terminology. A complete list of basic directives is in the file
/opt/apache/htdocs/manual/mod/core.html.
ServerType As discussed in Section 29.2, some services can run standalone or from
inetd (orxinetd). This directive can be exactly standaloneorinetd. If you chooseinetd, you will need to add an appropriate line into yourinetd
configuration, although a web server should almost certainly choose standalone mode.
ServerRoot This is the directory superstructure&See page 137.-under which Apache is installed. It will always be the same as the value passed to--prefix=.
PidFile Many system services store the process ID in a file for shutdown and moni-toring purposes. On most distributions, the file is/var/run/httpd.pid.
ScoreBoardFile This option is used for communication between Apache parent and child processes on some non-UNIXsystems.
Port This is the TCP port for standalone servers to listen on.
User,Group This option is important for security. It forceshttpdto usernobody
privileges. If the web server is ever hacked, the attack will not be able to gain more than the privileges of thenobodyuser.
HostnameLookups To force a reverse DNS lookup on every connecting host, set this directive toon. To force a forward lookup on every reverse lookup, set this to
double. This option is for logging purposes since access control does a reverse and forward reverse lookup anyway if required. It should certainly beoffif you want to reduce latency.
ServerAdmin Error messages include this email address.
UseCanonicalName If Apache has to return a URL for any reason, it will normally return the full name of the server. Setting tooffuses the very host name sent by the client.
ServerSignature Add the server name to HTML error messages.
DefaultType All files returned to the client have a type field specifying how the file should be displayed. If Apache cannot deduce the type, it assumes the MIME Type to betext/plain. See Section 12.6.2 for a discussion of MIME types.
ErrorLog Where errors get logged, usually/var/log/httpd/error log
LogLevel How much info to log.
LogFormat Define a new log format. Here we defined a log format and call it com-mon. Multiple lines are allowed. Lots of interesting information can actually be logged: See/opt/apache/htdocs/manual/mod/mod log config.html
for a full description.
CustomLog The log file name and its (previously defined) format.
DocumentRoot This directive specifies the top-level directory that client connec-tions will see. The string /opt/apache/htdocs/ is prepended to any file lookup, and hence a URL http://localhost/manual/index.html.enwill return the file
/opt/apache/htdocs/manual/index.html.en.
DirectoryIndex This directive gives the default file to try serve for URLs that con-tain only a directory name. If a fileindex.htmldoes not exist under that direc-tory, an index of the directory is sent to the client. Other common configurations useindex.htmordefault.html.
AccessFileName Before serving a file to a client, Apache reads additional directives from a file .htaccessin the same directory as the requested file. If a parent directory contains a.htaccessinstead, this one will take priority. The .htac-cessfile contains directives that limit access to the directory, as discussed below. The above is merely the general configuration of Apache. To actually serve pages, you need to define directories, each with a particular purpose, containing particular HTML or graphic files. The Apache configuration file is very much like an HTML document. Sections are started with<section parameter>and ended with</section>.
The most common directive of this sort is<Directory /directory>which does such directory definition. Before defining any directories, we need to limit access to the root directory. This control is critical for security.
¨ ¥
<Directory />
Options FollowSymLinks Deny from All
Order Deny,Allow
5 AllowOverride None
</Directory>
§ ¦
This configuration tells Apache about the root directory, giving clients very restrictive access to it. The directives are&Some of these are extracted from the Apache manual.-:
Options TheOptionsdirective controls which server features are available in a par-ticular directory. There is also the syntax+optionor-optionto include the options of the parent directory, for example,Options +FollowSymLinks -Indexes.
FollowSymLinks The server will follow any symbolic links beneath the direc-tory. Be careful about what symbolic links you have beneath directories with
FollowSymLinks. You can, for example, give everyone access to the root directory by having a link../../../underhtdocs—not what you want.
ExecCGI Execution of CGI scripts is permitted.
Includes Server-side includes are permitted (more on this later).
IncludesNOEXEC Server-side includes are permitted, but the#execcommand and#includeof CGI scripts are disabled.
Indexes If a client asks for a directory by name and noindex.htmlfile (or whateverDirectoryIndexfile you specified) is present, then a pretty list-ing of the contents of that directory is created and returned. For security you may want to turn this option off.
MultiViews Content-negotiated MultiViews are allowed (more on this later).
SymLinksIfOwnerMatch The server will only follow symbolic links for which the target file or directory is owned by the same user ID as the link (more on this later).
All All options except forMultiViews. This is the default setting.
Deny Hosts that are not allowed to connect. You can specify a host name or IP address, for example, as:
¨ ¥
Deny from 10.1.2.3 Deny from 192.168.5.0/24 Deny from cranzgot.co.za
which will deny access to10.1.2.3, all hosts beginning with192.168.5., and all hosts ending in.cranzgot.co.za, including the hostcranzgot.co.za.
Allow Hosts that are allowed to connect. This directive uses the same syntax asDeny.
Order If order is Deny,Allow, then theDenydirectives are checked first and any client that does not match a Denydirective or does match anAllowdirective will beallowedaccess to the server.
If order is Allow,Deny, then the Allow directives are checked first and any client that does not match an Allowdirective or does match aDenydirective will bedeniedaccess to the server.
AllowOverride In addition to the directives specified here, additional directives will be read from the file specified by AccessFileName, usually called .htac-cess. This file would usually exist alongside your .html files or otherwise in a parent directory. If the file exists, its contents are read into the cur-rent <Directory . . .> directive. AllowOverride says what directives the
.htaccess file is allowed to squash. The complete list can be found in
/opt/apache/htdocs/manual/mod/core.html.
You can see that we give very restrictiveOptionsto the root directory, as well as very restrictive access. The only server feature we allow isFollowSymLinks, then weDenyany access, and then we remove the possibility that a.htaccessfile could override our restrictions.
The<Files . . .>directive sets restrictions on all files matching a particular reg-ular expression. As a security measure, we use it to prevent access to all.htaccess
files as follows:
¨ ¥
<Files ˜ "ˆ\.ht"> Order allow,deny Deny from all </Files>
§ ¦
We are now finally ready to add actual web page directories. These take a less restrictive set of access controls:
¨ ¥
<Directory "/opt/apache/htdocs">
Options Indexes FollowSymLinks MultiViews AllowOverride All
Order allow,deny
5 Allow from all
</Directory>
36.2.3 User HTML directories
Our users may require that Apache know about their private web page directories
˜/www/. This is easy to support with the specialUserDirdirective:
¨ ¥
<Directory "/opt/apache/htdocs/home/*/www"> Options Indexes MultiViews
AllowOverride None Order allow,deny
5 Allow from all
</Directory>
UserDir /opt/apache/htdocs/home/*/www
§ ¦
For this feature to work, you must symlink /opt/apache/htdocs/home
to /home, and create a directory www/ under each user’s home direc-tory. Hitting the URL http://localhost/˜jack/index.html will then retrieve the file
/opt/apache/htdocs/home/jack/www/index.html. You will find that Apache gives aForbiddenerror message when you try to do this. This is probably because
jack’s home directory’s permissions are too restrictive. Your choices vary between now making jack’s home directory less restricted or increasing the privileges of Apache. Running Apache under the www group by using Group www, and then running
¨ ¥
groupadd -g 65 www
chown jack:www /home/jack /home/jack/www chmod 0750 /home/jack /home/jack/www
§ ¦
is a reasonable compromise.
36.2.4 Aliasing
Sometimes, HTML documents will want to refer to a file or graphic by using a simple prefix, rather than a long directory name. Other times, you want two different refer-ences to source the same file. TheAliasdirective creates virtual links between direc-tories. For example, adding the following line, means that a URL/icons/bomb.gif
will serve the file/opt/apache/icons/bomb.gif:
¨ ¥
Alias /icons/ "/opt/apache/icons/"
§ ¦
We do, of course, need to tell Apache about this directory:
¨ ¥
<Directory "/opt/apache/icons"> Options None
AllowOverride None Order allow,deny
5 Allow from all
</Directory>
§ ¦
36.2.5 Fancy indexes
You will find the directory lists generated by the preceding configuration rather bland. The directive
¨ ¥
IndexOptions FancyIndexing
§ ¦
causes nice descriptive icons to be printed to the left of the file name. What icons match what file types is a trick issue. You can start with:
¨ ¥
AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip AddIconByType (TXT,/icons/text.gif) text/*
AddIconByType (IMG,/icons/image2.gif) image/* AddIconByType (SND,/icons/sound2.gif) audio/*
5 AddIconByType (VID,/icons/movie.gif) video/*
AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip AddIcon /icons/a.gif .ps .eps
AddIcon /icons/layout.gif .html .shtml .htm
§ ¦
This requires theAliasdirective above to be present. The default Apache configura-tion contains a far more extensive map of file types.
36.2.6 Encoding and language negotiation
You can get Apache to servegzipped files with this:
¨ ¥
AddEncoding x-compress Z AddEncoding x-gzip gz
§ ¦
Now if a client requests a fileindex.html, but only a fileindex.html.gzexists, Apache decompresses it on-the-fly. Note that you must have theMultiViewsoptions enabled.
The next options cause Apache to serveindex.html.language-codewhen in-dex.htmlis requested, filling in the preferred language code sent by the web browser. Adding these directives causes your Apache manual to display correctly and will prop-erly show documents that have non-English translations. Here also, theMultiViews
must be present.
¨ ¥
AddLanguage da .dk AddLanguage nl .nl AddLanguage et .ee 5 AddLanguage fr .fr AddLanguage de .de AddLanguage el .el AddLanguage ja .ja AddLanguage ru .ru 10 LanguagePriority en da nl et fr de el ja ru § ¦
TheLanguagePrioritydirective indicates the preferred language if the browser did not specify any.
Some files might contain a.koi8-rextension, indicating a Russian character set encoding for this file. Many languages have such custom character sets. Russian files are namedwebpage.html.ru.koi8-r. Apache must tell the web browser about the encoding type, based on the extension. Here are directives for Japanese, Russian, and UTF-8&UTF-8 is a Unicode character set encoding useful for any language.-, as follows:
¨ ¥
AddCharset ISO-2022-JP .jis AddCharset KOI8-R .koi8-r AddCharset UTF-8 .utf8
§ ¦
Once again, the default Apache configuration contains a far more extensive map of languages and character sets.
36.2.7 Server-side includes — SSI
Apache actually has a built-in programming language that interprets.shtmlfiles as scripts. The output of such a script is returned to the client. Most of a typical.shtml
file will be ordinary HTML, which will be served unmodified. However, lines like
¨ ¥
<!--#echo var="DATE_LOCAL" -->
§ ¦
will be interpreted, and their outputincludedinto the HTML—hence the name server-side includes. Server-server-side includes are ideal for HTML pages that contain mostly static HTML with small bits of dynamic content. To demonstrate, add the following to your
httpd.conf: ¨ ¥ AddType text/html .shtml AddHandler server-parsed .shtml <Directory "/opt/apache/htdocs/ssi"> Options Includes 5 AllowOverride None Order allow,deny
Allow from all </Directory>
§ ¦
Create a directory/opt/apache/htdocs/ssiwith the index fileindex.shtml:
¨ ¥
<HTML>
The date today is <!--#echo var="DATE_LOCAL" -->.<P> Here is a directory listing:<br>
<PRE> 5 <!--#exec cmd="ls -al" --> </PRE> <!--#include virtual="footer.html" --> </HTML> § ¦
and then a filefooter.htmlcontaining anything you like. It is obvious how useful this procedure is for creating many documents with the same banner by means of a
#includestatement. If you are wondering what other variables you can print besides
DATE LOCAL, try the following:
¨ ¥ <HTML> <PRE> <!--#printenv --> </PRE> 5 </HTML> § ¦
You can also gotohttp://localhost/manual/howto/ssi.htmlto see some other examples.
36.2.8 CGI — Common Gateway Interface
(I have actually never managed to figure out why CGI is called CGI.) CGI is where a URL points to a script. What comes up in your browser is the output of the script (were it to be executed) instead of the contents of the script itself. To try this, create a file/opt/apache/htdocs/test.cgi:
¨ ¥
#!/bin/sh
echo ’Content-type: text/html’ echo
5 echo ’<HTML>’
echo ’ <HEAD>’
echo ’ <TITLE>My First CGI</TITLE>’ echo ’ </HEAD>’
echo ’ <BODY bgcolor=#CCCCCC text="#000000">’
10 echo ’This is my first CGI<P>’
echo ’ <A HREF="http://rute.sourceforge.net/">’ echo ’ The Rute Home Page’
echo ’ </A>’
15 echo ’for more info.</P>’
echo ’ </BODY>’ echo ’</HTML>’
§ ¦
Make this script executable withchmod a+x test.cgiand test the output by running it on the command-line. Add the line
¨ ¥
AddHandler cgi-script .cgi
§ ¦
to your httpd.conf file. Next, modify your Options for the directory
/opt/apache/htdocsto includeExecCGI, like this:
¨ ¥
<Directory "/opt/apache/htdocs">
Options Indexes FollowSymLinks MultiViews ExecCGI AllowOverride All
Order allow,deny
5 Allow from all
</Directory>
§ ¦
After restarting Apache you should be able to visit the URLhttp://localhost/test.cgi. If you run into problems, don’t forget to runtail /opt/apache/logs/error log
to get a full report.
To get a full list of environment variables available to your CGI program, try the following script:
¨ ¥
#!/bin/sh
echo ’Content-type: text/html’ echo 5 echo ’<HTML>’ echo ’<PRE>’ set echo ’</PRE>’ echo ’</HTML>’ § ¦
The script will show ordinarybashenvironment variables as well as more interesting variables likeQUERY STRING: Change your script to
¨ ¥
#!/bin/sh
echo ’Content-type: text/html’ echo
5 echo ’<HTML>’ echo ’<PRE>’ echo $QUERY_STRING echo ’</PRE>’ echo ’</HTML>’ § ¦
and then go to the URLhttp://localhost/test/test.cgi?xxx=2&yyy=3. It is easy to see how variables can be passed to the shell script.
The preceding example is not very interesting. However, it gets useful when scripts have complex logic or can access information that Apache can’t access on its own. In Chapter 38 we see how to deploy an SQL database. When you have covered SQL, you can come back here and replace your CGI script with,
¨ ¥
#!/bin/sh
echo ’Content-type: text/html’ echo
5
psql -d template1 -H -c "SELECT * FROM pg_tables;"
§ ¦
This script will dump the table list of thetemplate1database if it exists. Apache will have to run as a user that can access this database, which means changingUser no-bodytoUser postgres. &Note that for security you shouldreallylimit who can connect to the
postgresdatabase. See Section 38.4.
-36.2.9 Forms and CGI
To create a functional form, use the HTTP <FORM> tag as follows. A file
/opt/apache/htdocs/test/form.htmlcould contain:
¨ ¥
<HTML>
<FORM name="myform" action="test.cgi" method="get"> <TABLE>
<TR>
5 <TD colspan="2" align="center">
Please enter your personal details: </TD>
</TR> <TR>
10 <TD>Name:</TD><TD><INPUT type="text" name="name"></TD>
</TR> <TR>
<TD>Email:</TD><TD><INPUT type="text" name="email"></TD> </TR>
<TD>Tel:</TD><TD><INPUT type="text" name="tel"></TD> </TR>
<TR>
<TD colspan="2" align="center">
20 <INPUT type="submit" value="Submit">
</TD> </TR> </TABLE> </FORM> 25 </HTML> § ¦
which looks like:
Note how this form calls our existingtest.cgiscript. Here is a script that adds the entered data to apostgresSQL table:
¨ ¥
#!/bin/sh
echo ’Content-type: text/html’ echo
5
opts=‘echo "$QUERY_STRING" | \
sed -e ’s/[ˆA-Za-z0-9 %&+,.\/:=@_˜-]//g’ -e ’s/&/ /g’ -e q‘ for opt in $opts ; do
10 case $opt in name=*) name=${opt/name=/} ;; email=*) 15 email=${opt/email=/} ;; tel=*) tel=${opt/tel=/} ;; 20 esac
done
if psql -d template1 -H -c "\
INSERT INTO people (name, email, tel) \
25 VALUES (’$name’, ’$email’, ’$tel’)" 2>&1 | grep -q ’ˆINSERT ’ ; then
echo "<HTML>Your details \"$name\", \"$email\" and \"$tel\"<BR>" echo "have been succesfully recorded.</HTML>"
else
echo "<HTML>Database error, please contact our webmaster.</HTML>"
30 fi
exit 0
§ ¦
Note how the first lines of script remove all unwanted characters from
QUERY STRING. Such processing is imperative for security because shell scripts can easily execute commands should characters like$and‘be present in a string.
To use the alternative “POST” method, change yourFORMtag to
¨ ¥
<FORM name="myform" action="test.cgi" method="post">
§ ¦
The POST method sends the query text through stdin of the CGI script. Hence, you need to also change youropts=line to
¨ ¥
opts=‘cat | \
sed -e ’s/[ˆA-Za-z0-9 %&+,.\/:=@_˜-]//g’ -e ’s/&/ /g’ -e q‘
§ ¦
36.2.10 Setuid CGIs
Running Apache as a privileged user has security implications. Another way to get this script to execute as userpostgresis to create a setuid binary. To do this, create a filetest.cgiby compiling the followingCprogram similar to that in Section 33.2.
¨ ¥
#include <unistd.h>
int main (int argc, char *argv[]) {
5 setreuid (geteuid (), geteuid ());
execl ("/opt/apache/htdocs/test/test.sh", "test.sh", 0); return 0;
}
Then run chown postgres:www test.cgi and chmod a-w,o-rx,u+s test.cgi(orchmod 4550 test.cgi). Recreate your shell script astest.shand go to the URL again. Apache runstest.cgi, which becomes userpostgres, and then executes the script as thepostgresuser. Even with Apache asUser nobody
your script will still work. Note how your setuid program is insecure: it takes no ar-guments and performs only a single function, but it takes environment variables (or input from stdin) that could influence its functionality. If a login user could execute the script, that user could send data via these variables that could cause the script to behave in an unforeseen way. An alternative is:
¨ ¥
#include <unistd.h>
int main (int argc, char *argv[]) {
5 char *envir[] = {0};
setreuid (geteuid (), geteuid ());
execle ("/opt/apache/htdocs/test/test.sh", "test.sh", 0, envir); return 0;
}
§ ¦
This script nullifies the environment before starting the CGI, thus forcing you to use the POST method only. Because the only information that can be passed to the script is a single line of text (through the-e qoption tosed) and because that line of text is carefully stripped of unwanted characters, we can be much more certain of security.
36.2.11 Apache modules and PHP
CGI execution is extremely slow if Apache has to invoke a shell script for each hit. Apache has a number of facilities for built-in interpreters that will parse script files with high efficiency. A well-known programming language developed specifically for the Web is PHP. PHP can be downloaded as source from The PHP Home Page
http://www.php.netand contains the usual GNU installation instructions.
Apache has the facility for adding functionality at runtime using what it calls DSO (Dynamic Shared Object) files. This feature is for distribution vendors who want to ship split installs of Apache that enable users to install only the parts of Apache they like. This is conceptually the same as what we saw in Section 23.1: To give your program some extra feature provided by some library, you can either statically link the library to your programor compile the library as a shared.sofile to be linked at run time. The difference here is that the library files are (usually) calledmod name and are stored in/opt/apache/libexec/. They are also only loaded if a Load-Module name moduleappears inhttpd.conf. To enable DSO support, rebuild and reinstall Apache starting with:
¨ ¥
./configure --prefix=/opt/apache --enable-module=so
Any source package that creates an Apache module can now use the Apache utility /opt/apache/bin/apxsto tell it about the current Apache installation, so you should make sure this executable is in yourPATH.
You can now follow the instructions for installing PHP, possibly beginning with
./configure --prefix=/opt/php --with-apxs=/opt/apache/bin/apxs --with-pgsql=/usr. (This assumes that you want to enable support for the
postgres SQL database and have postgres previously installed as a pack-age under /usr.) Finally, check that a file libphp4.so eventually ends up in
/opt/apache/libexec/.
Yourhttpd.confthen needs to know about PHP scripts. Add the following lines
¨ ¥
LoadModule php4_module /opt/apache/libexec/libphp4.so AddModule mod_php4.c
AddType application/x-httpd-php .php
§ ¦
and then create a file/opt/apache/htdocs/hello.phpcontaining
¨ ¥ <html> <head> <title>Example</title> </head> 5 <body>
<?php echo "Hi, I’m a PHP script!"; ?> </body>
</html>
§ ¦
and test by visiting the URLhttp://localhost/hello.php.
Programming in the PHP language is beyond the scope of this book.
36.2.12 Virtual hosts
Virtual hosting is the use of a single web server to serve the web pages of multiple domains. Although the web browser seems to be connecting to a web site that is an isolated entity, that web site may in fact be hosted alongside many others on the same machine.
Virtual hosting is rather trivial to configure. Let us say that we have three domains: www.domain1.com, www.domain2.com, and www.domain3.com. We want domains www.domain1.com and www.domain2.com to share IP address
196.123.45.1, whilewww.domain3.comhas its own IP address of196.123.45.2. The sharing of a single IP address is calledname-based virtual hosting, and the use of a different IP address for each domain is calledIP-based virtual hosting.
If our machine has one IP address,196.123.45.1, we may need to configure a separate IP address on the same network card as follows (see Section 25.9):
¨ ¥
ifconfig eth0:1 196.123.45.2 netmask 255.255.255.0 up
§ ¦
For each domain /opt/apache/htdocs/www.domain?.com/, we now create a top-level directory. We need to tell Apache that we intend to use the IP address
196.123.45.1for several hosts. We do that with theNameVirtualHostdirective. Then for each host, we must specify a top-level directory as follows:
¨ ¥ NameVirtualHost 196.123.45.1 <VirtualHost 196.123.45.1> ServerName www.domain1.com 5 DocumentRoot /opt/apache/htdocs/www.domain1.com/ </VirtualHost> <VirtualHost 196.123.45.1> ServerName www.domain2.com 10 DocumentRoot /opt/apache/htdocs/www.domain2.com/ </VirtualHost> <VirtualHost 196.123.45.2> ServerName www.domain3.com 15 DocumentRoot /opt/apache/htdocs/www.domain3.com/ </VirtualHost> § ¦
All that remains is to configure a correct DNS zone for each domain so that lookups of
www.domain1.com and www.domain2.com return 196.123.45.1while lookups ofwww.domain3.comreturn196.123.45.2.