<html>
<body>
<pre>
Apache 1 - bozza versione 0.0
=============================
A coloro che hanno voglia di dare un'occhiata a questo mattone.
Sto preparando anche l'articolo sui protocolli. E' anche piu' lungo.
Fatemi sapere se e' meglio che lascio stare.
- Umb
---------------------------------------------------------------
</pre>
<h1>Apache - Prima puntata</h1>
<h2>Indice</h2>
<a href="#intro">Introduzione</a></br>
<a href="#percominciare">Per cominciare</a><br>
<a href="#hostvirtualibasatisullindirizzoip">Host virtuali basati sull'indirizzo IP</a><br>
<a href="#hostvirtualibasatisulnome">Host virtuali basati sul nome</a><br>
<a href="#cominciamolaconfigurazione">Cominciamo la configurazione</a><br>
<a href="#passo1dichiarareinuovidomini">PASSO 1: Dichiarare i nuovi domini</a><br>
<a href="#passo2predisporreglispaziweb">PASSO 2: Predisporre gli spazi WEB</a><br>
<a href="#passo3configuriamoapache">PASSO 3: Configuriamo Apache</a><br>
<a href="#passo4creiamolehomepage">PASSO 4: Creiamo le home page</a><br>
<a href="#passo5verificadeglihostvirtuali">PASSO 5: Verifica degli host virtuali</a><br>
<a href="#esperimentiinteressanti">Esperimenti interessanti</a><br>
<a href="#webdinamicoeprogrammicgi">WEB dinamico e programmi CGI</a><br>
<a href="#suexecovverodelbracciodestrodeldemonio">SUEXEC - Ovvero del braccio destro del demonio</a><br>
<a href="#scriptaliasdefinirelaledirectorydeicgi">ScriptAlias - Definire la/le directory dei CGI</a><br>
<a href="#scriptaliasmatchunnomeuncgi">ScriptAliasMatch - Un nome, un CGI</a><br>
<a href="#homepagepersonali">Home page personali</a><br>
<a href="#proviamoilsuexec">Proviamo il SUEXEC</a><br>
<a href="#ritocchifinali">Ritocchi finali</a><br>
<a href="#httpdconfintuttalasuagloria"><code>http.conf</code> in tutta la sua gloria</a><br>
<a href="#conclusioni">Conclusioni</a><br>
<a href="#bibliografia">Bibliografia</a><br>
<a name=intro></a>
<h2>Introduzione</h2>
<p>
Apache è un potente WEB server multipiattaforma. Le statistiche
dicono che sia il più utilizzato al mondo, e tutto lascia prevedere
che lo sarà ancora per qualche anno.
</p>
<p>
Apache è disponibile nel sito ufficiale <a
href="http://www.apache.org"><code>www.apache.org</code></a> insieme ai
sorgenti e a tutta la documentazione. Tutte le distribuzioni di Linux
includono il pacchetto Apache, tipicamente già precompilato e
preconfigurato: è sufficiente una installazione base del sistema
operativo, ed anche l'utilizzatore più sprovveduto si ritrova
con un WEB server preinstallato (magari a sua insaputa...).
</p>
<p>
Le cose vanno diversamente quando si desidera configurare Apache per
uso di produzione: diventa allora difficile orientarsi tra la miriade di
opzioni di configurazione di Apache, e la documentazione ufficiale non
aiuta il neofita. In particolare in questo articolo vogliamo configurare
Apache per supportare la multiutenza e raggiungere i seguenti obiettivi:
gestire vari domini WEB; isolare i programmi CGI dei vari siti tra di
loro; dotare gli utenti ciascuno della propria home page.
</p>
<p>
Queste note sono il frutto di alcuni mesi di lavoro passati a spulciare
nella documentazione del programma e a fare prove su varie distribuzioni
Linux, principalmente Red Hat 6.2 e Red Hat 7.1, che includono la
versione 1.3 di Apache. I suggerimenti e le soluzioni che descrivo si
applicano ovviamente anche ad altre distribuzioni, che potranno differire
al più per la scelta dei path di installazione e per il diverso
packaging dei componenti di Apache (modulo base, moduli supplementari,
ecc.).
</p>
<p>
Non ho certo intenzione di scrivere un tutorial di Apache o un ennesimo
manuale. Si tratta semplicemente della descrizione di esperienze
che possono interessare solo gli iniziati che, una volta eseguita con
successo l'installazione base di Apache, desiderano approfondirne alcune
funzionalità avanzate.
</p>
<p>
Non ci inoltreremo qui nelle procedure di ricompilazione del sorgente
del programma, nè faremo altre cose più tediose e
"difficili": ci limiteremo a modifcare il file di configurazione di
Apache ed eventualmente interverremo su qualche altro file di sistema
usando pratiche consuete di configurazione. Riporremo la nostra fiducia
nel rivenditore della distribuzione, che di solito ha cura di rendere
disponibile sul suo sito WEB l'ultima versione di Apache corretta rispetto
ai bug e ai problemi di sicurezza. Non ci interessa invece di installare
l'ultimissima versione, poiché ci concentreremo sugli aspetti
generali della gestione del server.
</p>
<p>
Ultima annotazione prima di cominciare: teoricamente il <i>system
administrator</i> e il <i>WEB administrator</i> sono due ruoli distinti.
In realtà l'intreccio di competenze è tale che le due figure
finiscono per coincidere. È molto probabile che la configurazione
del WEB server coinvolga parecchi settaggi del sistema, della posta
elettronica, del DBMS, dei permessi e degli utenti, sicchè separare
le due figure diventa davvero difficile. Perciò qui userò
i due termini in modo interscambiabile.
</p>
<a name="percominciare"></a>
<h2>Per cominciare</h2>
<p>
Assicuriamoci innanzitutto che Apache sia installato ed in esecuzione.
È interessante nonché divertente per il sistemista conoscere modi alternativi per fare ciò:
</p>
<b>1. Ordine e disciplina - Seguire la via maestra</b><br>
Linux segue le convenzioni System V per l'inizializzazione del sistema.
Quindi dovrebbe essere disponibile un piccolo script di shell che si incarica
di avviare, fermare e verificare lo stato del server. Lo script esegue una
di queste funzioni a seconda che sia stato invocato con il parametro
<code>start</code>, <code>stop</code> oppure <code>status</code>;
esiste poi anche il parametro <code>restart</code> che ha l'ovvio significato.
Sulla distribuzione Red Hat 6.2 il comando è
</p>
<pre>
# <b>/etc/rc.d/init.d/httpd status</b>
httpd (pid 9702 9701 9698) is running...
</pre>
<p>
mentre per la Red Hat 7.1 differisce leggermente il path:
</p>
<pre>
# <b>/etc/init.d/httpd status</b>
httpd (pid 9702 9701 9698) is running...
</pre>
<p>
L'output conseguente dovrebbe confortarci che Apache è regolarmente
in esecuzione. Il messaggio esatto dipende da come è stato scritto
questo script, che invito ad andare a vedere.
</p>
<b>2. Il Riduzionista - In Unix è tutta una questione di file e di processi</b><br>
Sappiamo che Unix e Linux sono sistemi operativi concepiti con la filosofia del
meccano: pochi strumenti, ma buoni. File e processi sono il fondamento del sistema, il resto è il sale e il pepe. Il sistemista-riduzionista non si fida
degli script automatici, ma vuole andare alla all'origine delle cose e va a guardare direttamente i processi in esecuzione:
</p>
<pre>
# <b>ps ax | grep httpd</b>
9698 ? S 0:00 /usr/sbin/httpd <i>parametri vari</i>
9701 ? S 0:00 /usr/sbin/httpd <i>parametri vari</i>
9702 ? S 0:00 /usr/sbin/httpd <i>parametri vari</i>
9706 pts/2 S 0:00 grep httpd
</pre>
<p>
Il sistemista-riduzionista è previdente: sa che sulla sua
macchina oberata di lavoro sono in esecuzione centinaia di processi,
per cui inserisce un sano <code>grep</code> che seleziona solo le righe
che contengono la stringa <code>httpd</code>. Guardacaso, queste righe
sono proprio quelle relative ai processi di Apache.
</p>
<b>3. L'hacker che c'è in noi - Emerge il lato oscuro</b><br>
Ragioniamo: se un server di rete fornisce servizi in rete, il
modo migliore per verificarne il funzionamento è provare
direttamente questi servizi. Apriamo allora il nostro browser WEB
preferito e puntiamolo sull'URL <code>http://localhost</code>. Il bravo
sistemista/hacker con tendenze riduzioniste usa Telnet come browser WEB:
<p>
<pre>
# <b>telnet localhost 80</b>
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
<b>GET / HTTP/1.0</b> <i>qui premi ENTER due volte</i>
HTTP/1.1 200 OK
Date: Mon, 10 Dec 2001 21:50:38 GMT
Server: Apache/1.3.19 (Unix) (Red-Hat/Linux)
Last-Modified: Sat, 11 Aug 2001 19:58:38 GMT
ETag: "49183-20e-3b758e6e"
Accept-Ranges: bytes
Content-Length: 526
Connection: close
Content-Type: text/html
<HTML>
<i>la pagina HTML che non ci interessa</i>
</HTML>
Connection closed by foreign host.
#
</pre>
<p>
Come al solito, solo il comando evidenziato in grassetto deve essere impartito
a tastiera, il resto sono le risposte del sistema. Notiamo che il comando
<code>GET</code> deve essere scritto proprio in lettere maiuscole, e che
occorre premere due volte il tasto ENTER prima che il server risponda:
la riga vuota è il modo in cui il client (cioè il nostro
Telnet) spiega al server che ha concluso la sua domanda. Infatti, vedremo
che il client ha la possibilità di specificare vari altri parametri
su altrettante righe.
</p>
<p>
Come è facile immaginare, il comando <code>GET</code> serve per
richiedere un documento; a seguire bisogna specificare la parte di path
file dell'URL del documento, essendo per convenzione <code>/</code> la
richiesta della home page, o pagina default, o pagina indice del sito.
Con lungimiranza, il protocollo HTTP richiede anche di specificare
esplicitamente il protocollo e la versione.
</p>
<center>
<table width="70%" border=1 cellpadding=5>
<tr><th bgcolor=#aaaaff>Trucco</th></tr>
<tr><td>Se il terminale che usi non supporta lo scrolling,
sarà difficile riuscire a leggere le prime righe, che sono le
più interessanti. Rimedi possibili: usare <code>script</code>;
richiedere una pagina deliberatamente errata al posto di <code>/</code>,
ad esempio <code>/xxx</code>;
infine, usare un comando come questo:
</p>
<pre>
# <b>(echo -ne "GET / HTTP/1.0\n\n"; sleep 2) \</b>
> <b>| telnet localhost 80 | head -20</b>
</pre>
<p>
In questo modo appariranno solo le prime 20 righe del dialogo con il server,
indipendentemente dalla effettiva lunghezza della risposta. Usando lo stesso
principio si può andare ad esplorare in giro i vari server, e verificare
di persona quali sono i server più usati: interessante, vero?
</p>
</td>
</tr>
</table>
</center>
<p>
A questo punto dovremmo avere la certezza che l'installazione di base di
Apache è a posto. Per ora Apache ritorna la pagina default predefinita
dalla distribuzione, ma questo ci va bene perché stiamo per cambiare
un po' tutto...
</p>
<a name="hostvirtualibasatisullindirizzoip"></a>
<h2>Host virtuali basati sull'indirizzo IP</h2>
<p>
Di base il server Apache risponde ad un unico indirizzo IP e ad
un unico dominio, cioè gestisce un solo sito WEB del tipo
<code>www.azienda.it</code> o una cosa del genere. Gli ISP hanno
invece la necessità di gestire parecchi domini. Le aziende
più avanzate informaticamente sul fronte Internet possono
voler creare siti WEB distinti per le diverse aree funzionali, come
<code>support.azienda.it</code>, oppure desiderano ospitare siti WEB
delle ditte affiliate. Con il protocollo HTTP versione 1.0 era necessario
dotare ogni sito WEB di un indirizzo IP distinto, anche se poi questo
indirizzo si riferiva alla stessa macchina fisica. In questo consiste
il meccanismo di <i>host virtuale basato sull'indirizzo IP</i>.
</p>
<p>
Le cose funzionavano (e possono funzionare tuttora) così: se un
navigatore cliccava sull'URL <code>www.azienda.it</code>, il browser
risolveva il nome in un certo numero IP <code>11.22.33.44</code>, ed
è a questo server che il browser inviava la richiesta; quando
il navigatore cliccava su <code>support.azienda.it</code>, il browser
risolveva il nome in un indirizzo IP diverso <code>55.66.77.88</code>
al quale rispondeva magari la stessa macchina, ma lì il server
poteva discriminare il sito WEB richiesto in base all'indirizzo IP.
</p>
<a name="hostvirtualibasatisulnome"></a>
<h2>Host virtuali basati sul nome</h2>
<p>
Per ridurre lo spreco di preziosi indirizzi IP, e tutte le inevitabili
complicazioni tecniche, burocratiche e di costi, il protocollo HTTP
versione 1.1 ha aggiunto la funzionalità di host virtuale basato
sul nome.
Il meccanismo è abbastanza semplice: il browser segue la stessa trafila
di prima, ma nella richiesta della pagina specifica anche per esteso il nome
del dominio richiesto. Il server WEB, anche se dotato di un solo indirizzo
IP, ha così modo di riconoscere quale sito WEB tra quelli ospitati
è stato effettivamente richiesto. In questo consiste il meccanismo
di <i>host virtuale basato sul nome</i>. È ovvio che questo sistema
richiede la collaborazione del browser per funzionare. Comunque, tutti i browser
moderni supportano HTTP 1.1, tanto che il meccanismo degli host virtuali
è ampiamente utilizzato. Forse tutto 'sto discorso suona un po'
ingarbugliato, ma vedremo subito degli esempi molto concreti che dovrebbero
chiarire bene come vanno le cose.
</p>
<a name=cominciamolaconfigurazione></a>
<h2>Cominciamo la configurazione</h2>
<p>
Dunque, Apache include il supporto per gli host virtuali basati sul nome
di dominio, previsti dal protocollo HTTP versione 1.1. Questo ci permette
di ospitare sulla nostra macchina un numero arbitrario di siti WEB distinti
utilizzando sempre un solo indirizzo IP. Le specifiche tecniche della
implementazione che andremo a fare sono le seguenti:
</p>
<center>
<table bgcolor="#dddddd" border=1 cellpadding=10>
<tr><th colspan=3>The "Casa" ISP Specs</th></tr>
<tr><td><b>IP Address:</b></td> <td colspan=2><code>127.0.0.1</code></td></tr>
<tr><td valign=top rowspan=4><b>WEB Sites:</b></td>
<th>Domain</th> <th>DocumentRoot</th></tr>
<tr><td><code>localhost.localdomain</code></td> <td><code>/home/httpd/html</code></td></tr>
<tr><td><code>www.tizio.casa</code></td> <td><code>/home/tizio/public_html</code></td></tr>
<tr><td><code>www.caio.casa</code></td> <td><code>/home/caio/public_html</code></td></tr>
</tr>
</table>
</center>
<p>
L'indirizzo IP non è scelto a caso: si tratta dell'indirizzo di
loop-back previsto per scopi di test e disponibile su
ogni macchina. Altro aspetto positivo di questa scelta: non servono
schede di rete e non serve essere connessi ad Internet.
</p>
<a name=passo1dichiarareinuovidomini></a>
<h2>PASSO 1: Dichiarare i nuovi domini</h2>
<p>
Per quanto riguarda i domini gestiti, sono ovviamente nomi di
fantasia che possiamo inserire nell'elenco degli host name del file
<code>/etc/hosts</code>, che andiamo subito a modificare in modo che
appaia così:
</p>
<pre>
127.0.0.1 localhost.localdomain localhost
<b>127.0.0.1 www.tizio.casa</b>
<b>127.0.0.1 www.caio.casa</b>
</pre>
<p>
In genere la prima riga è già predisposta, mentre le altre
due sono quelle appena aggiunte. A questo punto i processi che avvieremo
saranno in grado di risolvere i nuovi nomi di dominio.
</p>
<a name=passo2predisporreglispaziweb></a>
<h2>PASSO 2: predisporre gli spazi WEB</h2>
<p>
La strategia che seguiremo comporta la creazione di un normale account
per ciascun dominio gestito. Vogliamo insomma che ogni dominio sia gestibile
da un utente distinto, che vi può accedere in Telnet o FTP come
di consueto. Nella home directory, ciascun utente sarà libero di gestire
il suo sito in totale libertà.<br>
Per creare l'utente Tizio facciamo questo:
</p>
<pre>
# <b>useradd tizio -g users</b>
# <b>passwd tizio</b>
Changing password for user tizio
New UNIX password: <b>******</b>
Retype new UNIX password: <b>******</b>
passwd: all authentication tokens updated successfully
# <b>chmod u=rwx,g=,o=x /home/tizio</b>
# <b>mkdir /home/tizio/public_html</b>
# <b>chown tizio:users /home/tizio/public_html</b>
# <b>chmod u=rwx,g=,o=x /home/tizio/public_html</b>
</pre>
<p>
Per i più pigri, spiego a parole quello che abbiamo fatto:
il nuovo utente possiede una normale home directory locata in <code>/home/tizio</code>; dentro a questa directory questo signore potrà lavorare normalmente
come un qualsiasi utente. In più abbiamo creato una sotto-directory
di nome <code>public_html</code> che conterrà la parte pubblica
del sito WEB del sig. Tizio. In altri termini, andremo a configurare Apache
in modo che gli URL del tipo <code>http://www.tizio.casa/x</code> vengano
tradotti nel pathfile <code>/home/tizio/public_html/x</code>.
</p>
<p>
Ci sono però due aspetti molto importanti da considerare:
</p>
<p>
- Abbiamo assegnato esplicitamente il nuovo utente al gruppo
<code>users</code>: questo devia dallo schema generale della distribuzione
Red Hat, che per default crea un nuovo gruppo per ogni utente.
</p>
<p>
- Abbiamo ampliato i diritti di accesso alla home directory
dell'utente con <code>o+x</code> per consentire ad Apache di
attraversarla per raggiungere le pagine WEB dentro a alla subdirectory
<code>public_html</code>. I permessi assegnati sono:
</p>
<center>
<table cellpadding=3 border=1>
<tr><th colspan=9>Permessi di <code>/home/tizio</code></th></tr>
<tr><td colspan=3><center>UID:<br><code>tizio</code></center></td>
<td colspan=3><center>GID:<br><code>users</code></center></td>
<td colspan=3><center>others:</center></td></tr>
<tr>
<td><code>r</code></td>
<td><code>w</code></td>
<td><code>x</code></td>
<td><code>-</code></td>
<td><code>-</code></td>
<td><code>-</code></td>
<td><code>-</code></td>
<td><code>-</code></td>
<td><code>x</code></td>
</tr>
</table>
</center>
<p>
Conviene spendere due parole sul significato di quanto fatto riguardo ai
permessi di accesso, perché l'argomento è un po' delicato,
essendo coinvolti i problemi di sicurezza e riservatezza. Fintanto che
il server WEB è al servizio di un'unica azienda, la separazione degli
spazi di lavoro semplifica la gestione e riduce le interferenze. Tuttavia
se il server deve essere reso disponibile ad altri soggetti sui quali non
si ha pieno controllo, allora le cose vanno studiate più attentamente.
</p>
<p>
Spieghiamo innanzitutto cosa intendiamo con il termine <b>identità
di un processo</b>. Ogni processo ha varie caratteristiche: ad esempio una è il
PID (process identifier), il numero univoco che identifica il processo nel
sistema. Altre due caratteristiche molto importanti sono l'<b>UID</b> e
il <b>GID</b> del processo, cioè il numero dell'utente e il numero
del gruppo che contraddistinguono il processo. Sono questi valori che
il kernel esamina prima di dare il permesso a un processo di accedere ad
una risorsa, come un file o un device. Richiamiamo brevemente i criteri
seguiti dal kernel per decidere se autorizzare o meno una certa operazione
richiesta da un processo su di un file:
</p>
<center>
<table bgcolor=#dddddd width="90%" border=0 cellpadding=10>
<tr><td>
<p>
1. <u>L'UID del processo è uguale all'UID del file.<br></u>
In questo caso si applicano i tre flag dei permessi di utente del file.
Se la combinazione dei flag non permette di eseguire l'operazione richiesta
dal processo (lettura, scrittura, esecuzione), l'operazione viene negata
<b>indipendentemente da tutti gli altri flag di gruppo e others</b>.
</p>
<p>
2. <u>Gli UID del processo e del file differiscono, ma i GID sono uguali</u>.<br>
In tal caso si applicano i tre flag dei permessi di gruppo del file.
Anche qui, se la combinazione dei flag non permette di eseguire l'operazione
richiesta dal processo, l'operazione viene negata
<b>indipendentemente da tutti gli altri flag di others</b>.
</p>
<p>
3. <u>L'UID e il GID del processo non corrispondono a quelli del file</u>.<br>
In tal caso si applicano i tre flag dei permessi di others.
</p>
</td></tr>
</table>
</center>
<p>
Ricordo che Apache gira con l'identità UID:GID = <code>nobody:nobody</code> su Red Hat 6.2, e con l'identità <code>apache:apache</code> su
Red Hat 7.1. Questi parametri vengono impostati nella configurazione
predefinita con le direttive <code>User</code> e <code>Group</code>
nel file di configurazione <code>httpd.conf</code>.
</p>
<p>
La conseguenza di tutto questo discorso è che Apache potrà
entrare nelle directory degli utenti Tizio e Caio grazie al permesso
<code>o+x</code>; inoltre Apache potrà leggere tutti e soli i file
accessibili ad "other". Viceversa, gli altri utenti del sistema, i cui processi
operano con GID = <code>users</code>, si scontrano con il secondo criterio
di validazione, e non possono entrare nella directory.
</p>
<center>
<table width="70%" border=1 cellpadding=5>
<tr>
<th bgcolor=#ffff00>ATTENZIONE!</th>
</tr>
<tr>
<td>
Il modello di sicurezza per i permessi dei file e delle directory
non è l'unico possibile, ma forse è il più semplice
da applicare e da gestire. Lascia tuttavia qualche perplessità
il dover rendere accessibile a "other" la propria home directory.
<p>
Esiste almeno un'altra soluzione che si basa sulla creazione di un gruppo
per ciascun utente, paradigma scelto per default dalla distribuzione
Red Hat. Le home directory degli utenti vanno poi rese attraversabili
dal proprio gruppo. L'utente del server (<code>nobody</code> oppure
<code>apache</code>) deve poi essere inserito nel gruppo di ciascun utente.
Questa, in estrema sintesi la ricetta alternativa.
</td>
</tr>
</table>
</center>
<a name=passo3configuriamoapache></a>
<h2>PASSO 3: Configuriamo Apache</h2>
<p>
E finalmente arriviamo alla configurazione di Apache. Il file di
configurazione è <code>httpd.conf</code>, che nella distribuzione
Red Hat 6.2 e 7.1 si trova in <code>/etc/httpd/conf/httpd.conf</code>.
Raccomando a questo punto di fare una bella copia del file prima che
ci mettiamo su le manacce: è utile avere come riferimento un file
di configurazione che sappiamo essere funzionante.
</p>
<p>
Al termine del file <code>httpd.conf</code> c'è la sezione
destinata agli host virtuali. Assicuriamoci che sia presente la direttiva
<pre>
NameVirtualHost 127.0.0.1:80
</pre>
<p>
che attiva la funzionalità degli host virtuali basati sul nome
sulla solita porta 80 del nostro server. Creiamo il virtual host per il
dominio <code>www.tizio.casa</code>:
</p>
<pre>
<VirtualHost 127.0.0.1:80>
ServerName <b>www.tizio.casa</b>
DocumentRoot /home/<b>tizio</b>/public_html
ServerAdmin <b>tizio</b>@localhost
CustomLog logs/<b>www.tizio.casa</b>-access_log common
ErrorLog logs/<b>www.tizio.casa</b>-error_log
</VirtualHost>
</pre>
<p>
Per gli altri domini virtuali creiamo altrettanti utenti e altre sezioni
VirtualHost similari, facendo attenzione a modificare di conseguenza
il dominio, il path e l'indirizzo di posta, evidenziati in grassetto
nell'esempio. Come ServerAdmin ho indicato in realtà l'utente tizio
invece che il vero WEB administrator: di solito i problemi legati a un
sito WEB sono locali a quel sito (pagine mancanti, CGI non funzionanti,
ecc.) piuttosto che responsabilità del WEB administrator.
</p>
<a name=passo4creiamolehomepage></a>
<h2>PASSO 4: Creiamo le home page</h2>
Questa è la parte facile e rilassante:
<pre>
# <b>su - tizio</b>
$ <b>echo "<html><body><h1>Benvenuti in www.tizio.casa</body></html>"</b>
<b>> public_html/index.html</b>
$ <b>[CTRL-D]</b>
# <b>su - caio</b>
$ <b>echo "<html><body><h1>Benvenuti in www.caio.casa</body></html>"</b>
<b>> public_html/index.html</b>
$ <b>[CTRL-D]</b>
</pre>
...e così via per gli altri dominii.
<a name=passo5verificadeglihostvirtuali></a>
<h2>PASSO 5: Verifica degli host virtuali</h2>
<p>
Non ci resta che riavviare Apache. Il comando da dare su Red Hat 6.2 è
</p>
<pre>
# <b>/etc/rc.d/init.d/httpd restart</b>
</pre>
<p>
mentre su Red Hat 7.1 è
</p>
<pre>
# <b>/etc/init.d/httpd restart</b>
</pre>
<p>
Se qualcosa è andato storto, c'è sempre il log file in
<code>/var/log/httpd</code>. Mentre si fanno queste prove consiglio
di tenere sempre aperta una finestra dedicata alla visualizzazione dei
messaggi di log tramite il comando <code>tail -f /var/log/httpd/*</code>.
</p>
<p>
Se è tutto ok, puntiamo il WEB browser
sull'URL <code>http://www.tizio.casa</code> e poi su
<code>http://www.caio.casa</code>. Ecco quello che io ho ottenuto:
</p>
<pre>
$ <b>(echo -ne "GET / HTTP/1.1\nHost: www.tizio.casa\n\n"</b>
> <b>sleep 2) | telnet localhost 80</b>
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
HTTP/1.1 200 OK
Date: Wed, 11 Dec 2001 21:33:20 GMT
Server: Apache/1.3.19 (Unix) (Red-Hat/Linux)
Last-Modified: Mon, 10 Dec 2001 07:55:23 GMT
ETag: "fa7b-43-3c146a6b"
Accept-Ranges: bytes
Content-Length: 67
Content-Type: text/html
<html><body>Benvenuto in www.tizio.casa</body></html>
Connection closed by foreign host.
</pre>
<a name=esperimentiinteressanti></a>
<h2>Esperimenti interessanti</h2>
<p>
Prova questo comando:
</p>
<pre>
# <b>(echo -ne "GET / HTTP/1.0\n\n"; sleep 2) \</b>
> <b>| telnet localhost 80 | head -20</b>
</pre>
<p>
che dovrebbe ritornare il primo virtual host (che al momento dovrebbe
essere quello del sig. Tizio). Possiamo provare anche ad aggiungere il
virtual host <code>localhost.localdomain</code> come primo virtual host
e ripetere la prova.
</p>
<p>
Adesso sfruttiamo il protocollo HTTP v. 1.1 per ritornare gli altri
virtual host. Per il isg. Caio si tratta di aggiungere la riga <code>Host:
www.caio.casa</code> nella nostra interrogazione:
</p>
<pre>
# <b>(echo -ne "GET / HTTP/1.0\nHost: www.caio.casa\n\n"; sleep 2) \</b>
> <b>| telnet localhost 80 | head -20</b>
</pre>
<p>
Le stesse prove si possono fare anche da un browser WEB "normale",
ma si perde tutto il gusto...
</p>
<p>
Con questo abbiamo concluso il nostro tour sul meccanismo dei
domini virtuali. In una situazione realistica avremo che i
domini <code>www.tizio.casa</code> e <code>www.caio.casa</code>
saranno registrati su un qualche DNS (e non nel nostro file
<code>/etc/hosts</code>), e l'indirizzo IP da assegnare ai VirtualHost
sarà l'indirizzo pubblico assegnato alla nostra macchina (e non
l'indirizzo di loopback 127.0.0.1).
</p>
<a name=webdinamicoeprogrammicgi></a>
<h2>WEB dinamico e programmi CGI</h2>
<p>
Il WEB sarebbe ben poca cosa se senza la possibilità di generare
dinamicamente le pagine richieste e senza la possibilità di
interagire con il client remoto. Il protocollo HTTP da una parte,
e le tecnologie CGI e SSI di Apache dall'altra sono gli strumenti che
forniscono queste possibilità. Apache viene corredato anche con
vari interpreti incorporati, tipicamente PHP e PERL, che permettono una
esecuzione molto efficiente di codice di scripting incorporato all'interno
delle pagine WEB.
</p>
<p>
Spendiamo due parole per chiarire cos'è un <i>programma CGI</i>: si
tratta appunto di un programma, realizzabile con un qualsiasi linguaggio
di programmazione o di scripting, che può essere invocato come
una pagina WEB o come gestore di un <code>form</code> HTML; il WEB
server, invece che ritornare al client il file del programma, lo esegue
e l'output generato da questo programma è quello che il server
và a restituire al client, sia essa una pagina HTML, una immagine
GIF o qualsiasi altro tipo di informazione sia eccettabile nel WEB.
Le specifiche della interfaccia CGI dicono anche come il programma CGI
possa ricevere input dal client, chiudendo quindi il cerchio. Rimandiamo
al prossimo articolo la discussione dettagliata della tecnologia CGI,
delle possibilità che essa offre, e dei possibili utilizzi pratici.
</p>
<p>
Tuttavia, nuove possibilità significano nuovi problemi per
l'amministratore del sistema. Cerchiamo di capire meglio il problema
introducendo l'importantissima questione della identità dei
processi CGI.
</p>
<p>
Abbiamo detto che il server Apache è un processo avviato
con l'identità UID:GID = <code>nobody:nobody</code> nella
distribuzione Linux Red Hat 6.2, oppure con l'identità UID:GID =
<code>apache:apache</code> nella distribuzione Linux Red Hat 7.1. Con
altre distribuzioni di Linux questa identità può cambiare,
ma resta il fatto che Apache funziona con questa unica identità.
L'identità del processo impone anche i limiti per quanto riguarda
l'accesso alle risorse del sistema:
</p>
<ul>
<li>attraversamento di directory;<p>
<li>elencazione del contenuto delle directory;<p>
<li>creazione e cancellazione di file in una data dir.;<p>
<li>lettura/scrittura/esecuzione dei file;<p>
<li>accesso a un DBMS;<p>
<li>accesso alle altre risorse del sistema.
</ul>
<p>
I programmi CGI avviati da Apache ereditano l'identità di processo
di quest'ultimo anche quando questi programmi appartengono ad utenti
diversi. Lo stesso discorso vale per gli interpreti incorporati PHP
e PERL. Quindi, ad esempio, le funzioni per gestire i file richiedono di
impostare opportunamente i permessi e la proprietà della directory
dove il file risiede, oltre che i permessi e la proprietà del file
stesso. Non è possibile creare file in directory non accessibili
al server, nè è possibile leggere file non leggibili per
il server.
</p>
<p>
Supponiamo ora che i programmi CGI prodotti dal sig. Tizio e dal sig. Caio
abbiano necessità di svolgere varie funzioni: esattamente come
qualsiasi altro programma, i loro CGI avranno bisogno di leggere e scrivere
file, accedere a un DB e altre cose del genere. Purtroppo, i siccome i loro
programmi CGI verranno eseguiti con la stessa identità, saremo costretti
ad assegnare diritti di accesso in comune a tutti i CGI. Per essere più
espliciti: a livello di CGI gli utenti Tizio e Caio potranno pasticciare
liberamente sugli stessi file. Il sig. Tizio non potrà leggere o
scrivere un suo file riservato senza che questo non sia leggibile anche
al sig. Caio. Il Sig. Tizio vorrà accedere a un DBMS riservato
specificando una password, ma se usa un linguaggio di scripting il suo
programma deve necessariamente essere leggibile ai programmi CGI degli
altri utenti, che potranno così carpirgli facilmente la password.
Il sig. Tizio non potrà leggere o scrivere file nella propria home
directory (al di fuori di <code>public_html</code>) senza dover
pericolosamente rilassare i diritti di accesso al suo account.
In altri termini, abbiamo un sistema multiutente che, a livello del server
WEB, diventa monoutente...
</p>
<p>
Pensiamo invece a quanto sarebbe logicamente bello e praticamente utile
se i programmi CGI di un utente fossero eseguiti con l'identità
dell'utente stesso: il programma avrebbe pieno accesso al suo account e potrebbe
leggere e scrivere file; i CGI non sarebbero leggibili nè copiabili
dagli altri utenti, anche quando si trattasse di script; l'autenticazione
al DBMS potrebbe essere automatica perchè basata sulla identità
del processo; ecc. Tutte queste possibilità offrono agli utenti
molte opportunità di sfruttare in modo creativo le tecnologie del WEB.
</p>
<p>
Esiste anche un rovescio della medaglia: l'esecuzione di programmi
CGI qualora siano realizzati come script richiede più tempo per
l'avviamento rispetto agli stessi programmi eseguiti dagli interpreti
incorporati in Apache. Del resto, se un sito WEB comporta realmente un
grande flusso di traffico, forse vale la pena di dedicare ad esso un
server completo, per cui l'obiezione è valida solo in parte.
</p>
<a name=suexecovverodelbracciodestrodeldemonio></a>
<h2>SUEXEC - Ovvero del braccio destro del Demonio</h2>
<p>
La documentazione di Apache è estrememente prudente in proposito:
SUEXEC è uno strumento potente, ma altrettanto potentemente
insidioso per la sicurezza dalle intrusioni. L'esperienza del passato
ha lasciato alcune vittime, ma gli sviluppatori di Apache hanno studiato
contromosse altrettanto diaboliche. Rimando perciò a questa fonte
per la discussione della questione. Noi sfideremo intrepidi il rischio,
ansiosi di esplorare le nuove dimensioni che si dischiuderanno.
</p>
<p>
Il famigerato SUEXEC di Apache non è altro che un programmino
di una decina di KB che si occupa di avviare i CGI per conto di Apache,
conferendo però al processo così avviato l'identità
del suo proprietario. Quindi, ad esempio, i CGI del sig. Tizio verranno
eseguiti con l'identità UID:GID = <code>tizio:users</code>.
Il SUEXEC si preoccupa di garantire che il processo avviato sia legittimo.
La tabellina qui sotto riassume le identità dei vari processi nel
caso di un programma CGI <code>mio.cgi</code> avviato per conto del sig. Tizio:
</p>
<center>
<table border=1 cellpadding=5>
<tr>
<th>Processo</th><th>UID</th><th>GID</th></tr>
<td><code>httpd</code></td><td><code>nobody</code> (RH6.2)<br><code>apache</code> (RH7.1)</td><td><code>nobody</code> (RH6.2)<br><code>apache</code> (RH7.1)</td></tr>
<tr><td><code>suexec</code></td><td><code>root</code></td><td><code>nobody</code> (RH6.2)<br><code>apache</code> (RH7.1)</td></tr>
<tr><td><code>mio.cgi</code></td><td><code>tizio</code></td><td><code>users</code></td></tr>
</table>
</center>
<p>
La distribuzione Red Hat viene con il programma <code>suexe</code>
già pronto, ma disattivato. Inoltre, il programma prevede,
tra gli infiniti controlli, che il CGI avviato si trovi dentro alla
directory <code>/home/httpd</code> (o in altra directory prevista dalla
distribuzione), sicché non è adatto alla nostra situazione.
</p>
<p>
Se la tua distribuzione non include il programma
<code>/usr/sbin/suexec</code> (è infatti questo il nome al secolo
dell'innominabile), allora dovrai proprio procedere alla compilazione dei
sorgenti di <u>tutto</u> Apache, oltre che scaricare la patch SUEXEC dal
sito ufficiale. In questo caso seguire scrupolosamente le indicazioni
fornite, eccetto che il pathfile della directory dei CGI dovrà
essere <code>/home</code>. Buon lavoro e buona fortuna. Ci rivediamo al
prossimo paragrafo sugli ScripAlias.
</p>
<p>
Se invece sei un pigro, troverai più veloce ed indolore la ricetta
che segue, valida per le distribuzioni Red Hat 6.2 e 7.1.
</p>
<p>
suexec è abilitato per eseguire i CGI solo nella directory
<code>/home/httpd/</code> (RH6.2) o nella dir. <code>/var/www</code>
(RH7.1): per abilitare il meccanismo nelle dir. degli utenti
<code>/home</code> è necessario ricompilare il programma suexec
cambiando opportunamente la configurazione hard-coded. Poiché ci
secca di intraprendere questo lungo e impervio cammino, scegliamo una
scorciatoia sporca: andremo a cambiare il codice del programma con un
editor binario! Io ho usato l'editor del potente Midnight Commander:
</p>
<ul>
<li>Apri il file <code>/usr/sbin/suexec</code> da mc, e usa l'editor binario
integrato di Midnight Commander.
<p>
<li>Ora dobbiamo cambiare il path dove suexec consente di eseguire
CGI col meccanismo del suexec. Per la RH6.2, individua la stringa
<code>/home/httpd/html</code> e inserisci uno zero al posto del secondo
slash: in questo modo per il programma la stringa risulterà
troncata a solo <code>/home</code>. Per la RH7.1 invece, individua la
stringa <code>/var/www/</code> e modificarla in <code>/home</code>,
ricordando sempre di mettere un byte zero in fondo, e sempre senza
cambiare la lunghezza complessiva del file. In entrambi i casi, i
caratteri d'avanzo dopo il byte nullo inserito sono irrilevanti. Un
errore in questa fase renderebbe inutilizzabile il file suexec. Ne hai
già fatto una copia, vero?
<p>
<li>Nel file suexec è hard-coded anche il nome dell'utente sotto
il quale viene eseguito Apache. Nella RH6.2 è <code>nobody</code>,
mentre nella RH7.1 è <code>apache</code>.
Se nella tua configurazione personalizzata hai modificato l'identità
del server Apache, dovrai individuare questa stringa e modificarla
di conseguenza, sempre nello stesso modo. Di norma non dovrebbe
però essere necessario.
<p>
</ul>
<p>
Per la RH6.2 e RH7.1 è sufficiente attivare
il bit SUID del programma suexec, e magari restringere il set di permessi
inutilmente ampi che la distribuzione attribuisce al file. Per la RH6.2:
</p>
<pre>
# <b>chown root:nobody /usr/sbin/suexec</b>
# <b>chmod u=xs,g=x,o= /usr/sbin/suexec</b>
</pre>
mentre per la RH7.1 cambia solo il nome del gruppo proprietario:
<pre>
# <b>chown root:apache /usr/sbin/suexec</b>
# <b>chmod u=xs,g=x,o= /usr/sbin/suexec</b>
</pre>
Adesso il suexec è a posto: controlla che l'identità
e i permessi del file suexec appaiano così nella RH6.2:
<pre>
# <b>ls -l /usr/sbin/suexec</b>
---s--x--- 1 root nobody 9488 Aug 12 14:19 /usr/sbin/suexec
</pre>
mentre nella RH7.1 dovrebbero apparire cosi':
<pre>
# <b>ls -l /usr/sbin/suexec</b>
---s--x--- 1 root apache 10976 Aug 12 13:05 /usr/sbin/suexec
</pre>
<p>
Se non corrispondono, agire con <code>chown</code> e <code>chmod</code>
opportunamente.
</p>
<p>
Non rimane che riavviare Apache. Nel log file <code>/var/log/httpd/access_log</code> dovrebbe apparire:
<pre>
[notice] caught SIGTERM, shutting down
[notice] Apache/1.3.19 (Unix) (Red-Hat/Linux) configured
-- resuming normal operations
[notice] <b>suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)</b>
</pre>
<p>
La riga che ci interessa è l'ultima, è ci rassicura che
Apache ha digerito il nostro suexec!
</p>
<a name=scriptaliasdefinirelaledirectorydeicgi></a>
<h2>ScriptAlias - Definire la/le directory dei CGI</h2>
<p>
Il nome di questa direttiva di Apache è fuorviante, perché
lascia pensare che riguardi solo gli script. In realtà si tratta
di una regola di matching che permette ad Apache di stabilire se un certo
file va considerato come documento o come programma CGI. Nel primo caso
Apache tenterà di riconoscerne il tipo e lo restituirà
al client che lo ha richiesto. Nel secondo caso Apache lancerà il
programma come CGI; siccome abbiamo appena attivato il supporto SUEXEC,
il programma assumerà l'identità del proprietario.
Esiste anche <code>ScripAliasMatch</code>, che permette di utilizzare
anche espressioni regolari: ne vedremo degli esempi.
</p>
<p>
Le direttive <code>ScriptAlias</code> e <code>ScriptAliasMatch</code>
possono apparire nella configurazione globale del server, e anche nelle
sezioni dei VirtualHost. La scelta più tradizionale prevede
di collocare i CGI nella directory <code>/cgi-bin</code> della root
directory del sito. In tal caso come direttiva globale metteremo
<pre>
ScriptAlias /cgi-bin/ /home/httpd/cgi-bin/
</pre>
Dato che abbiamo già fatto la configurazione degli host virtuali,
nelle sezioni dei VirtualHost metteremo qualcosa come
<pre>
<VirtualHost 127.0.0.1:80>
ServerName www.tizio.casa
<b>User tizio</b>
<b>Group users</b>
DocumentRoot /home/tizio/public_html
ServerAdmin tizio@localhost
<b>ScriptAlias /cgi-bin/ /home/tizio/public_html/cgi-bin/</b>
CustomLog logs/www.tizio.casa-access_log common
ErrorLog logs/www.tizio.casa-error_log
</VirtualHost>
</pre>
<p>
Le direttive <code>User</code> e <code>Group</code> dicono al programma
<code>suexec</code> quale dovrebbe essere l'identità del
programma CGI: <code>suexec</code> esegue poi un controllo stringente
sulla proprietà del file e sui suoi diritti di accesso prima di
autorizzarne l'esecuzione con l'identità stabilita.<br>
La direttiva <code>ScriptAlias</code> dichiara dove
si trova la directory dei CGI, e mappa gli URL del tipo
<code>http://www.tizio.casa/cgi-bin/xxx</code> nel pathfile
<code>/home/tizio/public_html/cgi-bin/xxx</code>.
</p>
<a name=scriptaliasmatchunnomeuncgi></a>
<h2>ScripAliasMatch - Un nome, un CGI</h2>
<p>
Più potente la direttiva <code>ScriptAliasMatch</code>: diventa
possibile utilizzare espressioni regolari per identificare i programmi
CGI. Per fare un esempio, possiamo istruire Apache a riconoscere
come programma CGI ogni file il cui nome termina con la stringa
"<code>.cgi</code>". A questo scopo basta una direttiva globale come
questa:
<pre>
ScriptAliasMatch /(.*)\.cgi /home/httpd/html/$1.cgi
</pre>
Per i VirtualHost aggiungeremo invece:
<pre>
<VirtualHost 127.0.0.1:80>
ServerName www.tizio.casa
User tizio
Group users
DocumentRoot /home/tizio/public_html
ServerAdmin tizio@localhost
ScriptAlias /cgi-bin/ /home/tizio/public_html/cgi-bin/
<b>ScriptAliasMatch /(.*)\.cgi /home/tizio/public_html/$1.cgi</b>
CustomLog logs/www.tizio.casa-access_log common
ErrorLog logs/www.tizio.casa-error_log
</VirtualHost>
</pre>
<p>
Questa volta la direttiva <code>ScriptAliasMatch</code> mappa URL
del tipo <code>http://www.tizio.casa/x/y/z.cgi</code> nel pathfile
<code>/home/tizio/public_html/x/y/z.cgi</code>, ed istruisce anche Apache
che questo file è un CGI da eseguire.
</p>
<a name=homepagepersonali></a>
<h2>Home page personali</h2>
<p>
Avrai visto qualche volte un URL del tipo
</p>
<pre>
www.qualcosa.org/~tizio
</pre>
<p>
dove <code>tizio</code> è un qualche individuo che rende
disponibile la sua home page pur senza disporre di un dominio
registrato. Il carattere tilde viene utilizzato per convenzione a questo
scopo. Sulle tastiere italiane si ottiene la tilde premendo ALT+123
(su Windows) o, in alternativa, indicando nell'URL la sequenza %7e. Nel
primo caso, 125 è il codice ASCII della tilde espresso nella base
decimale; nel secondo caso è lo stesso numero espresso nella base
esadecimale e nella convenzione della codifica degli URL.
</p>
<p>
Comunque sia, è pratica comune consentire agli utenti dei sistemi
Unix (e quindi anche Linux) di predisporre la propria home page. Per
attivare il meccanismo della tilde in Apache bisogna inserire questa
direttiva nella parte globale della configurazione:
</p>
<pre>
UserDir public_html
</pre>
<p>
il cui significato è il seguente: mappa gli URL della forma
<code>http://localhost.localdomain/~utente</code> nel pathfile
<code>/home/utente/public_html</code>. Si possono abilitare anche i CGI
nel solito modo:
</p>
<pre>
ScriptAliasMatch /~(.*)/(.*)\.cgi /home/$1/public_html/$2.cgi
</pre>
<p>
Il pattern <code>(.*)</code> esegue il match col nome dell'utente, che viene
sostituito in $1; di conseguenza la stringa <code>(.*)</code> deve
eseguire il match con tutto ciò che resta, che viene sostituito
in $2. Il risultato di queste due sostituzioni fornisce ad Apache il
pathfile assoluto del CGI nel file system. Quindi, ad esempio, l'URL
</p>
<pre>
http://localhost.localdomain/~tizio/x/y/z.cgi
</pre>
<p>
produce gli assegnamenti <code>$1=tizio</code>, <code>$2=x/y/z</code>
e quindi in definitiva Apache invoca il CGI
</p>
<pre>
/home/tizio/public_html/x/y/z.cgi
</pre>
<a name=proviamoilsuexec></a>
<h2>Proviamo il SUEXEC</h2>
<p>
Finalmente, siamo giunti alla conclusione. Sinceramente non credo sia
cosa sana tentare tutte le pratiche configuratorie viste fin qua e
ridursi solo ora a provare le cose. Più probabile che tu abbia
fatto le tue prove un po' alla volta modificando progressivamente il
file preconfezionato.
</p>
<p>
Comunque sia andata, adesso bisogna proprio verificare il funzionamento
SUEXEC. A questo scopo conviene loggarsi come utente, per esempio
il sig. Tizio, in modo che tutti i file e le directory create avranno
automaticamente l'identità giusta e faranno contento SUEXEC, che
così non si lamenterà. Crea uno script di test come questo:
<pre>
#!/bin/bash
echo "Content-Type: text/plain"
echo ""
echo "Identita':"
id
</pre>
chiamalo <code>/home/tizio/public_html/test.cgi</code> e rendilo
eseguibile:
<pre>
$ <b>chmod u=rwx,go= test.cgi</b>
</pre>
<p>
Eseguilo localmente per vedere se funziona (<code>./test.cgi</code>),
quindi prova l'URL <code>http://www.tizio.casa/test.cgi</code>. Se
hai configurato le home page degli utenti puoi provare anche
<code>http://localhost/~tizio/test.cgi</code>. Sul browser
dovrebbe apparire l'id <code>tizio/users</code>, prova provata che
il nostro programmino <code>test.cgi</code> è stato eseguito
con l'identità del suo proprietario.
Ecco quello che vedo io:
</p>
<pre>
$ <b>(echo -ne "GET /test.cgi HTTP/1.0\nHost: www.tizio.casa\n\n"</b>
> <b>sleep 2) | telnet localhost 80</b>
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
HTTP/1.1 200 OK
Date: Tue, 11 Dec 2001 21:15:53 GMT
Server: Apache/1.3.19 (Unix) (Red-Hat/Linux)
Connection: close
Content-Type: text/plain
Identita':
uid=506(<b>tizio</b>) gid=100(<b>users</b>) groups=100(users)
Connection closed by foreign host.
</pre>
<p>
La cosa importante sono lo due paroline evidenziate in grassetto,
<code>tizio</code> e <code>user</code>: è per vederle comparire
che abbiamo fatto tutta 'sta trafila del SUEXEC. Congratulazioni, obiettivo
centrato!
</p>
<p>
Se invece, come è probabile, salta fuori qualcos'altro, allora
non resta che ripercorrere tutti i passi della configurazione fatta fin
qui, tenendo sempre aperta una bella finestra con <code>tail -f</code>
dei file di log come abbiamo visto. Alcuni suggerimenti diagnostici:
</p>
<dl>
<dt><b>Netscape mostra sempre lo stesso risultato comunque io agisca.</b>
<dd>Bisogna premere il bottone <b>Reload</b> del browser mentre si tiene
premuto il tasto <b>SHIFT</b>, altrimenti Netscape restituisce quello che
ha nella cache.
<p>
<dt><b>Il browser risponde "Not Found" e sul log file appare "unable
to stat".</b>
<dd>Apache ha risolto l'URL nel pathfile, come viene specificato nel log;
sfortunatamente, tale file non esiste, oppure i permessi delle directory
non permettono ad Apache (che in questa fase ha ancora l'identità
standard) di attraversare una o più delle directory del pathfile.
Controlla il corretto pathfile. Controlla i permessi della directory
home di <code>tizio</code>.
<p>
<dt><b>Il browser mostra che lo script ha identità diversa da
<code>tizio/users</code>.</b>
<dd>Non sta funzionando SUEXEC. Controlla nel log file se all'avvio
di Apache compare il messaggio esplicito della attivazione del
SUEXEC. Controlla la presenza delle direttive <code>User</code> e
<code>Group</code> nella sezione <code>VirtualHost</code> del dominio
<code>www.tizio.casa</code>.
<p>
<dt><b>Il browser mostra il sorgente dello script.</b>
<dd>Controlla la direttiva <code>ScriptAliasMatch</code> nella sezione
<code>VirtualHost</code> del dominio <code>www.tizio.casa</code>.
</dl>
<p>
Infine, confronta il tuo file di configurazione con quello che riporto
qui più avanti.
</p>
<a name=ritocchifinali></a>
<h2>Ritocchi finali</h2>
<p>
Rimane ora solo da disabilitare gli interpreti PHP e PERL incorporati
in Apache. È facile, basta commentare tutte le righe di
<code>http.conf</code> che si riferiscono a questi linguaggi. Potremo
sempre usare il PHP e il PERL nei nostri CGI, ma nelle loro versioni
stand-alone consuete.
</p>
<p>
La direttiva globale
</p>
<pre>
DirectoryIndex index.html index.htm index.shtml index.cgi
</pre>
<p>
istruisce il server su quale pagina ritornare quando il client esegue una
<code>GET /</code> o comunque un'altra directory, senza specificare un
file preciso all'interno di questa directory. In questi casi, Apache tenta
di ritornare i file specificati, nell'ordine. Le prime voci sono quelle
consuete, mentre l'ultima l'ho aggiunta per l'occasione. per inciso,
se nessuno di questi file esiste, Apache ritorna l'elenco dei file della
directory se è presente la direttiva <code>Option Indexes</code>,
altrimenti dà un bel "Forbidden".
</p>
<a name=httpdconfintuttalasuagloria></a>
<h2><code>httpd.conf</code> in tutta la sua gloria</h2>
<p>
Giunti alla conclusione di questo lungo cammino, ecco come appare il mio
<code>httpd.conf</code>. Raccomando, prima di procedere ad uno sbrigativo
taglia-e-incolla, di fare una copia del vostro attuale file di configurazione,
e per due buoni motivi: 1) contiene molti utili commenti, qui omessi;
2) funziona.
</p>
<p>
Alcuni moduli opzionali li ho commentati, ma si possono re-inserire secondo
necessità. La loro omissione velocizza parecchio l'avvio, e riduce
il consumo di memoria.
</p>
<p>
Ho lasciato commentate anche alcune funzionalità che hanno valore
di commento per le personalizzazioni successive. Anche qui, vedere la
documentazione di Apache per il significato delle varie direttive.
</p>
<pre>
####### httpd.conf: INIZIO
ServerType standalone
ServerRoot "/etc/httpd"
LockFile /var/lock/httpd.lock
PidFile /var/run/httpd.pid
#ScoreBoardFile /var/run/httpd.scoreboard
Timeout 300
KeepAlive On
MaxKeepAliveRequests 10
KeepAliveTimeout 60
MinSpareServers 2
MaxSpareServers 10
# Pochi processi --> risparmio memoria; riavvii + veloci
StartServers 2
MaxClients 10
MaxRequestsPerChild 100
# Carico solo quello che mi serve:
#LoadModule vhost_alias_module modules/mod_vhost_alias.so
LoadModule env_module modules/mod_env.so
LoadModule config_log_module modules/mod_log_config.so
#LoadModule agent_log_module modules/mod_log_agent.so
LoadModule referer_log_module modules/mod_log_referer.so
LoadModule mime_module modules/mod_mime.so
#LoadModule negotiation_module modules/mod_negotiation.so
#LoadModule status_module modules/mod_status.so
#LoadModule info_module modules/mod_info.so
#LoadModule includes_module modules/mod_include.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule dir_module modules/mod_dir.so
LoadModule cgi_module modules/mod_cgi.so
#LoadModule asis_module modules/mod_asis.so
#LoadModule imap_module modules/mod_imap.so
#LoadModule action_module modules/mod_actions.so
LoadModule userdir_module modules/mod_userdir.so
LoadModule alias_module modules/mod_alias.so
#LoadModule rewrite_module modules/mod_rewrite.so
LoadModule access_module modules/mod_access.so
LoadModule auth_module modules/mod_auth.so
#LoadModule anon_auth_module modules/mod_auth_anon.so
#LoadModule db_auth_module modules/mod_auth_db.so
#LoadModule digest_module modules/mod_digest.so
#LoadModule proxy_module modules/libproxy.so
#LoadModule expires_module modules/mod_expires.so
#LoadModule headers_module modules/mod_headers.so
#LoadModule usertrack_module modules/mod_usertrack.so
LoadModule setenvif_module modules/mod_setenvif.so
ClearModuleList
#AddModule mod_vhost_alias.c
AddModule mod_env.c
AddModule mod_log_config.c
#AddModule mod_log_agent.c
AddModule mod_log_referer.c
AddModule mod_mime.c
#AddModule mod_negotiation.c
#AddModule mod_status.c
#AddModule mod_info.c
#AddModule mod_include.c
AddModule mod_autoindex.c
AddModule mod_dir.c
AddModule mod_cgi.c
#AddModule mod_asis.c
#AddModule mod_imap.c
#AddModule mod_actions.c
AddModule mod_userdir.c
AddModule mod_alias.c
#AddModule mod_rewrite.c
AddModule mod_access.c
AddModule mod_auth.c
#AddModule mod_auth_anon.c
#AddModule mod_auth_db.c
#AddModule mod_digest.c
#AddModule mod_proxy.c
#AddModule mod_expires.c
#AddModule mod_headers.c
#AddModule mod_usertrack.c
AddModule mod_so.c
AddModule mod_setenvif.c
Listen 80
####### Red Hat 6.2:
User nobody
Group nobody
####### Red Hat 7.1:
#User apache
#Group apache
ServerAdmin root@localhost
# Permessi globali:
<Directory />
Options IncludesNOEXEC Indexes SymLinksIfOwnerMatch
AllowOverride None
</Directory>
UserDir public_html
# Permessi di base per le dir. degli utenti:
<Directory "/home/*/public_html">
AllowOverride All
Options Includes Indexes SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
ScriptAliasMatch /~(.*)/(.*)\.cgi /home/$1/public_html/$2.cgi
ScriptAliasMatch /~(.*)/cgi-bin/(.*) /home/$1/public_html/$2
<Directory /home/*/public_html/cgi-bin>
AllowOverride All
Options ExecCGI
</Directory>
DirectoryIndex index.html index.htm index.shtml index.cgi _index
AccessFileName .htaccess
<Files ~ "^\.ht">
Order allow,deny
Deny from all
</Files>
UseCanonicalName On
TypesConfig /etc/mime.types
DefaultType text/plain
HostnameLookups Off
ErrorLog /var/log/httpd/error_log
LogLevel warn
#LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
#LogFormat "%{Referer}i -> %U" referer
#LogFormat "%{User-agent}i" agent
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\"" mioformatolog
CustomLog /var/log/httpd/access_log mioformatolog
ServerSignature On
Alias /icons/ "/home/httpd/icons/"
<Directory "/home/httpd/icons">
Options Indexes MultiViews
AllowOverride None
Order allow,deny
Allow from all
</Directory>
IndexOptions FancyIndexing
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/*
AddIconByType (VID,/icons/movie.gif) video/*
AddIcon /icons/binary.gif .bin .exe
AddIcon /icons/binhex.gif .hqx
AddIcon /icons/tar.gif .tar
AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
AddIcon /icons/a.gif .ps .ai .eps
AddIcon /icons/layout.gif .html .shtml .htm .pdf
AddIcon /icons/text.gif .txt
AddIcon /icons/c.gif .c
AddIcon /icons/p.gif .pl .py
AddIcon /icons/f.gif .for
AddIcon /icons/dvi.gif .dvi
AddIcon /icons/uuencoded.gif .uu
AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
AddIcon /icons/tex.gif .tex
AddIcon /icons/bomb.gif core
AddIcon /icons/back.gif ..
AddIcon /icons/hand.right.gif README
AddIcon /icons/folder.gif ^^DIRECTORY^^
AddIcon /icons/blank.gif ^^BLANKICON^^
DefaultIcon /icons/unknown.gif
ReadmeName README
HeaderName HEADER
IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t
AddEncoding x-compress Z
AddEncoding x-gzip gz tgz
AddLanguage en .en
AddLanguage fr .fr
AddLanguage de .de
AddLanguage da .da
AddLanguage el .el
AddLanguage it .it
# v. mod_negotiation
#LanguagePriority it en fr de
AddType text/html .shtml
AddHandler server-parsed .shtml
AddHandler imap-file map
BrowserMatch "Mozilla/2" nokeepalive
BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
BrowserMatch "RealPlayer 4\.0" force-response-1.0
BrowserMatch "Java/1\.0" force-response-1.0
BrowserMatch "JDK/1\.0" force-response-1.0
NameVirtualHost 127.0.0.1:80
<VirtualHost 127.0.0.1:80>
ServerName localhost.localdomain
DocumentRoot /home/httpd/html
ServerAdmin root@casa.lan
ErrorLog logs/localhost.localdomain-error_log
CustomLog logs/localhost.localdomain-access_log common
</VirtualHost>
<VirtualHost 127.0.0.1:80>
ServerName www.tizio.casa
User tizio
Group users
DocumentRoot /home/tizio/public_html
ServerAdmin root@casa.lan
ErrorLog logs/www.tizio.casa-error_log
CustomLog logs/www.tizio.casa-access_log common
ScriptAlias /cgi-bin /home/tizio/public_html/cgi-bin
ScriptAliasMatch /(.*)\.cgi /home/tizio/public_html/$1.cgi
</VirtualHost>
<VirtualHost 127.0.0.1:80>
ServerName www.caio.casa
User caio
Group users
DocumentRoot /home/caio/public_html
ServerAdmin root@casa.lan
ErrorLog logs/www.caio.casa-error_log
CustomLog logs/www.caio.casa-access_log common
ScriptAlias /cgi-bin /home/caio/public_html/cgi-bin
ScriptAliasMatch /(.*)\.cgi /home/caio/public_html/$1.cgi
</VirtualHost>
#### httpd.conf: FINE!
</pre>
<a name=conclusioni></a>
<h2>Conclusioni</h2>
<p>
Abbiamo visto come in ambiente multiutente si possono creare siti WEB
per domini virtuali, abbiamo collocato questi siti in spazi isolati
del sistema, abbiamo visto come ciascun soggetto possa creare i propri
programmi CGI che girano con la propria identità. Ogni utente
può creare file e gestire dati nello spazio della propria home
directory, senza interferenze con gli altri utenti.
</p>
<p>
Ho verificato tutti gli esempi presentati qui, ho installato e configurato
il mio computer come descritto, e tutto mi funziona. Tuttavia la materia
è abbastanza complessa, e la configurazione di un programma come
Apache richiede comunque l'attenta lettura del suo manuale per poterne
sfruttare tutte le potenzialità e per risolvere i problemi che
inevitabilmente si possono incontrare. Non mi illudo di essere stato esaustivo,
nè tantomeno infallibile. Ecco perché ho già predisposto
una pagina WEB all'indirizzo
<a href="http://digilander.iol.it/salsi/erratacorrige"><code>http://digilander.iol.it/salsi/erratacorrige</code></a> dove ospitare le inevitabili correzioni e
le integrazioni che si dovessero rendere necessarie. Ovviamente, si tratta
di una vile manovra scaramantica.
</p>
<p>
Nella prossima puntata affronteremo in dettaglio la tecnologia dei
CGI, vedremo il famigerato meccanismo dei cookie, e costruiremo i primi
programmi CGI di utilità. Per fare questo useremo un linguaggio di
programmazione che tutti gli utilizzatori di Linux sicuramente già
conoscono: Bash, la shell più comunemente utilizzata.
</p>
<p>
Che il grande totem sia con voi.
</p>
<a name=bibliografia></a>
<h2>Bibliografia</h2>
<b>Apache 1.3 User's Guide</b> - La documentazione ufficiale di Apche;
<a href="http://www.apache.org">http://www.apache.org/doc</a>.<br>
<b>RFC 2616</b> - Specifiche del protocollo HTTP versione 1.1;
<a href="http://www.rfc-editor.org">http://www.rfc-editor.org/</a>.<br>
</body>
</html>
_______________________________________________
pluto-journal mailing list
pluto-journal@lists.pluto.linux.it
http://lists.pluto.linux.it/mailman/listinfo/pluto-journal