|
||||||||||||||||
| ISBN: 3423050012 ISBN: 3423050012 ISBN: 3423050012 ISBN: 3423050012 | ||||||||||||||||
|
|
Wir empfehlen: | |||||||||||||||
Eine frei verwendbare Unix-Grundlagenschulung mit muLinux
|
||||||||||||||||
| -v | Verbose (engl. für geschwätzig) gibt Meldungen aus. |
| -e /usr/sbin/in.pygmy | Führt nach Kontaktaufnahme das nachfolgende Programm aus. |
| -l | Hört (engl. listen) auf eingehende Anfragen. |
| -p 80 | Abgehört wird Port 80, also das WWW-Port. |
| 2>>/var/log/httpd.log | Fehlermeldungen werden an die Log-Datei angefügt. |
Also hört hier NetCat am Port 80 und führt bei Anfragen das hinter -e erwähnte Porgramm aus. Dies ist gefährlich (engl. dangerous), da man mit nc leicht ein Trojanisches Pferd programmieren kann. Die Logdatei /var/log/httpd.log zeichnet alle Fehlermeldungen auf und wird erst nach dem Aktivieren von PYGMY angelegt.
/# ls /var/log identd.log /#
Noch ist also keine httpd.log vorhanden. Schauen wir uns mal das Programm /usr/sbin/in.pygmy an.
/# less /usr/sbin/in.pygmy
Na hier steht ja schon etwas mehr drin. Natürlich lassen wir uns davon nicht beeindrucken. Wie wir aus dem Kapitel "Einfache Shell-Scripte" wissen, ist das Doppelkreuz # der Beginn eines Kommentars. In der ersten Zeile steht ein besonderer Kommentar, der das aufzurufende Programm definiert. Hier ist das /bin/ash. Zu Beginn werden Variablen zur allgemeinen Konfiguration definiert. Ein guter Programmierstil legt die Definitionen am Anfang des Programms fest. So lassen sich Änderungen leichter durchführen. Man muß dann nicht erst den gesamten Quelltext (engl. source code) durchsuchen.
SED=sed
ROOT=/home/httpd
LOGO=/tmp/httpd.logo
LOGFILE=/var/log/httpd.log
Die Variable SED definiert das Programm zum stapelweisen Verarbeiten von Texten. Hier ist das der Stream Editor sed. Das klingt sehr beeindruckend. Wir werden uns erst später mit diesem Programm beschäftigen. ROOT definiert das Heimatverzeichnis des Webservers. Dort, bzw. in Unterverzeichnissen liegen die HTML-Dateien und Grafiken. Dies wollen wir überprüfen. Dazu wechseln wir zur zweiten Konsole und loggen uns ein.
/# ls /home/httpd total 5 0 doc 0 images 2 linux.html 0 download 3 index.html /#
Hier befinden sich wirklich HTML-Dateien. Man erkennt sie an der Endung .html. HTML-Dateien sind Textdateien, die HTML-Befehle enthalten. Diese Befehle werden in spitzen Klammern < > eingeschlossen. Web-Browser verstehen diesen Code mehr oder weniger gut und stellen uns diese Dateien als WWW-Seiten dar. Wer will kann ja mal sich eine solche Datei mit less index.html anschauen. Die Datei index.html ist eine besondere Datei in jedem Verzeichnis. Der Web-Server liefert diese Datei, wenn bei der Anfrage keine Datei sondern nur ein Verzeichnis angegeben wurde.
Doch zurück zur ersten Konsole und damit zur Datei in.pygmy.
Die nächsten Variablen definieren ein Logo für den Server und die Log-Datei. Bei der Log-Datei wissen wir, daß sie noch nicht angelegt wurde. Doch wie ist das mit dem Logo? Wir testen dies in der zweiten Konsole.
/# ls /tmp
Da ist keine Datei httpd.logo. Diese wird erst im nachfolgenden Code von /usr/sbin/in.pygmy erstellt. Dazu wechseln wir wieder in die erste Konsole und blättern im Text nach unten.
Unter den Hilfsfunktionen (engl. auxiliary funtion) sehen wir den Code zur Erzeugung des Logos.
# auxiliary functions cat > $LOGO <<END <hr> <font size=-1> <i> <center> powered by PYGMY -- muLinux rustic WWW server, on <b>`hostname` </b> </center> </i></font> </html> END
Mit dem Befehl cat wird der nachfolgende Text bis zum END in die Logo-Datei geschrieben. Das heißt, bei der ersten WWW-Anfrage wird die Logo-Datei angelegt. Wir erkennen hier die HTML-Befehle an den spitzen Klammern. Wir werden uns später im Kapitel "Erstellen einer kleinen Website" damit beschäftigen. Das Logo wird bei Meldungen des Webservers ausgegeben.
Nach dem Programmabschnitt zur Erzeugung des Logos erfolgen einige Funktionsdefinitionen. Funktionen werden bei den meisten Programmiersprachen verwendet. Das sind Programmbausteine, die immer wieder benötigt werden. Vor dem ersten Aufruf müssen sie erst definiert werden. Dies erfolgt beim Shell-Script wie bei vielen Sprachen.
funktionsname()
{
Befehl
Befehl
...
}
Zuerst wird der Funktionsname festgelegt. Mit diesem Namen wird die Funktion später aufgerufen. Dann kommen runde Klammern. Diese dienen bei Bedarf zur Parameterübergabe. Unser Webserver-Programm hat dazu bei keiner Funktion den Bedarf. Zwischen geschweiften Klammern werden dann die in dieser Funktion abzuarbeitenden Befehle geschrieben. Schauen wir und dazu weiter unseren kleinen Webserver an.
# Explorer requires explicitily a standard header
send_header()
{
cat <<END
HTTP/1.0 200 OK
Date: `date`
Server: Pygmy/Mulinux (Rustic) WWW server, v`cat /etc/version`
Leerzeile
END
}
Die Funktion send_header() sendet beim Aufruf den Header. Die erfolgt wieder mit dem Befehl cat der alles bis zu END ausgibt. Es wird die hier verwendete Version des HTTP ausgegeben und die Meldung "200 OK". Das heißt die angeforderte Datei ist vorhanden und wird anschließend gesendet. Danach wird das Datum und Informationen zum Server dargestellt. Wichtig ist die abschließende Leerzeile. So erkennt der WWW-Browser das Ende des Headers. Was danach kommt ist die angeforderte Datei.
build_error()
{
cat > /tmp/pyg_error.html << END
<html>
<h1>PYGMY (pygmean) www server</h1>
<hr>
<b>Not Found</b>
<p>
The requested URL $1 was not found on this server.
`cat $LOGO`
END
echo /tmp/pyg_error.html
}
Wenn eine angeforderte Datei auf dem Server nicht vorhanden ist, muß eine entsprechende Fehlermeldung gesendet werden. Dafür ist die Funktion build_error() zuständig. Dazu wird mit dem Befehl cat die Datei /tmp/pyg_error.html angelegt mit dem nachfolgenden HTML-Code gefüllt. Dazu gehört auch das Server-Logo. Anschließend wird die Datei mit echo ausgegeben.
build_dir()
{
case "$1" in
*/)
base="."
;;
*)
base="`basename $1`"
;;
esac
/bin/ls -s1 $1 | fgrep -v "total" > /tmp/raw.list
parent=`dirname $base`
cat > /tmp/html.list <<END
<html>
<h1>Index of $1</h1>
<hr>
<p>
<a href="../"> Parent directory </a> <p>
END
cat /tmp/raw.list | \
$SED "s/ *\([0-9]\+\) *\(.\+\)/\
\<a href=$base\/\2\> \2 \
\<\/a\> \1k\<p\>/g" >>/tmp/html.list
cat $LOGO >> /tmp/html.list
echo /tmp/html.list
}
Die Funktion build_dir() wird aufgerufen, wenn ein Verzeichnis angefordert wird, indem sich keine Datei index.html oder index.htm befindet. Ist dies der Fall, so wird der Inhalt des Verzeichnisses aufgelistet. Dazu wird der Stream Editor sed verwendet. Dessen Syntax möchte ich hier aber noch nicht erklären. Kommen wir zu wichtigsten Funktion. Das ist die Funktion GET(). Diese Funktion wird bei Anfragen an den Server aufgerufen. Die Anfrage nach einer Datei erfolgt in HTTP mit dem Befehl GET. Deshalb wurde diese Funktion hier so benannt. Sie hätte allerdings auch Pflaumenkuchen() heißen können. Der HTTP-Befehl GET übergibt als Parameter den Namen der Datei. Die Übergabe des ersten Parameter erolgt im Script-Programm mit $1. In der ersten Zeile wird $1 in die Variable page geschrieben.
GET()
{
page=$1
Mit Hilfe der Befehlskombination case (engl. für Fall) ... esac (case rückwärts geschrieben) können Fallunterscheidungen gemacht werden. Hier wird getestet ob am Anfang des Parameters ein Slash / steht. Wenn ja, dann sei die Variable pre leer, wenn nicht, dann sei pre gleich "/". Dann kommt die gleiche Fallunterscheidung für ein mögliches Slash am Ende. Hier wird post entsprechend gesetzt. Dies ist notwendig um jeweils ein Slash als Trennzeichen entsprechend der Unixschreibweise zu erhalten.
# / problem
case "$page" in
/*)
pre=""
;;
*) pre="/"
;;
esac
case "$page" in
*/)
post=""
;;
*) post="/"
;;
esac
Mit Hilfe der Befehlskombination if (engl. für wenn), then (engl. für dann), else (engl. für ansonsten) und fi (if rückwärts) können Entscheidungen getroffen werden. Das heißt: "Wenn etwas richtig ist dann mache das. Ansonsten mache jenes." Hier wird erst getestet ob ein Verzeichnis angefordert wurde. Wenn dies so ist wird versucht entweder die Datei index.htm oder index.html zu finden und mit dem kompletten Pfad zu senden. Ist weder index.htm oder index.html vorhanden so wird mit die Funktion build_dir aufgerufen, die das den Inhalt des Verzeichnisses auflistet. Wenn kein Verzeichnis angefordert wurde, so wird wohl eine Datei gemeint sein und die Variable PAGE mit dem Dateinamen und dem kompletten Pfad gefüllt.
# if a dir? exist index.html?
PAGE=
if [ -d $ROOT$pre$page ] ; then
[ -f $ROOT${pre}${page}${post}index.htm ] \
&& PAGE=$ROOT${pre}${page}${post}index.htm
[ -f $ROOT${pre}${page}${post}index.html ] \
&& PAGE=$ROOT${pre}${page}${post}index.html
[ -z "$PAGE" ] && PAGE=`build_dir $ROOT$sep$page`
else
PAGE=$ROOT$pre$page # is a file
fi
Jetzt wird getestet ob die Datei oder das Verzeichnis vorhanden ist. Wenn nicht wird mit build_error eine Fehlermeldung erzeugt.
# exist ?
if [ ! -f "$PAGE" ] ; then
PAGE=`build_error $PAGE`
fi
Ist alles OK wird mit send_header der Header und danach mit cat die Datei ausgegeben.
# Ok, send page send_header cat $PAGE }
Das waren soweit die Funktionen. Jetzt kommt das kurze Hauptprogramm (engl. main). Das Hauptprogramm wird mit while do ... done am Leben gehalten. Mit read wird die WWW-Browseranfrage gelesen. Danach erfolgt ein Eintrag in der Log-Datei. Mit if wird getestet ob es wirklich eine GET-Anforderung ist. Wenn ja wird die Funktion GET aufgerufen. Wenn nicht ertönt ein akustisches Signal und es wird eine Fehlermeldung ausgegeben.
# Main
while [ 1 ]
do
read x
echo " got [$x]" >> $LOGFILE
set -- $x
if [ "$1" = GET ] ; then
GET $2
else
[ "`which wave`" ] && wave -c 800 2
send_header
echo "<html> Error: $1 unknown. </html>"
fi
exit
done
Ich hoffe es war nicht zuviel Script-Programmierung auf einmal. Wir werden uns später mit der Script-Programmierung beschäftigen. Wer also hier nicht jedes Detail verstanden hat, braucht deshalb keine großen Sorgen machen. Hauptsache wir haben jetzt eine grobe Vorstellung was ein Webserver mindestens zu tun hat.
/# nmap localhost Scanning ports (hosts localhost), wait ... localhost [127.0.0.1] 113 (auth) open
Nur das Port 113 ist offen. Wir öffnen jetzt Port 80.
/# setup -f httpd
Setting httpd up: ask_the_user
- Internal Web Server -
Depending of what addons are mounted, muLinux support
some httpd daemon, running on port 80:
- Pygmy: the rustic script-based web-server
- thttpd: the fast web-server, developed by Jef Poskanzer
Do you want a running webserver?:
Wir wir sehen gibt es auf einer Add-on-Diskette noch einen zweiten Webserver mit dem Namen thttpd. Dieser ist schon eher ein richtiger Webserver. Wir begnügen uns hier aber mit PYGMY.
Starting PYGMY (rystic) web-server ... 1517Der Webserver wird gestartet und die Prozessnummer ausgegeben. Diese ist bei Euch sicher anders als hier. Wir testen ob PYGMY läuft.
/# ps aux | grep pygmy
... /usr/sbin/pygmy
Er läuft. Ist das Port auch offen?
/# nmap localhost Scanning ports (hosts localhost), wait ... localhost [127.0.0.1] 113 (auth) open localhost [127.0.0.1] 80 (www) open
Es ist offen. Wäre unser Rechner an das Internet angeschlossen, hätten wir ein großes Sicherheitsloch. PYGMY ist nämlich nicht sehr sicher. Wurde auch eine Log-Datei erzeugt?
/# ls /var/log httpd.log identd.log /#
Na klar! Schauen wir doch mal rein.
/# cat /var/log/httpd.log connect to [127.0.0.1] from localhost [127.0.0.1] 4194 got[] listening on [any] 80 ... /#
/# quark http://localhost
[r]eload [g]o [b]ack [v]iew [u]rls [s]ave [d]ownload [P]rint [q]uit [h]elp
Welcome to PYGMY (pygmean) WWW server!
----------------------------------------------------------------------------
This is a placeholder page installed by the muLinux setup scripts,
because no home page was installed on this host. You may want to replace
this as soon as possible with your own web pages, of course....
PYGMY is a small HTTP server, implemented with a shell script
(2174 bytes) and netcat port scanner. PYGMY run via /etc/inittab
and support: images, download and directory browsing. Remember: images
are fetched one by one, pressing RELOAD button in your browser.
Ehmm: the image is on the X11 addon ... :(
http://localhost Quark v.xx
cursor up/down, pag up/down to move vxx, hyperlink mode
|
Scheint alles zu funktionieren. Der Server zeigt uns eine Begrüßungsseite, die einige Informationen zum Server bietet. Erst im nächsten Kapitel lernen wir quark genauer kennen. Wir lernen hier nur einen Befehl kennen:
Mit Q verlassen wir den Browser wieder. Mit der Befehlswiederholung rufen wir nochmals quark auf. Diesmal geben wir noch den Port 80 an.
/# quark http://localhost:80
Das Ergebnis ist das Gleiche. Port 80 ist das Standardport für WWW und braucht nicht extra angegeben zu werden. Man kann aber auch den WWW-Server auf einen anderen Port betrieben. So können z. B. mehrere WWW-Server auf einen Rechner laufen. Wir probieren nach dem Verlassen von quark noch eine Variante.
/# quark http://localhost:80/index.html
Auch hier haben wir das gleiche Ergebnis. Wir haben ja in dem Script gesehen, daß der Webserver index.html ergänzt, wenn nur ein Verzeichnis angegeben wurde. Wir schauen uns nochmal die Log-Datei an.
/# cat /var/log/httpd.log connect to [127.0.0.1] from localhost [127.0.0.1] 4194 got[] listening on [any] 80 ... connect to [127.0.0.1] from localhost [127.0.0.1] 4687 got [GET] listening on [any] 80 ... /#
Er hat unsere Anforderung registriert. Und noch ein Versuch. Wir geben jetzt der Funktion zur Ausgabe der Fehlermeldung eine Chance.
/# quark http://localhost/quatsch
Der WWW-Server zeigt uns seine Fehlerseite.
/# cat /var/log/httpd.log connect to [127.0.0.1] from localhost [127.0.0.1] 4194 got[] listening on [any] 80 ... connect to [127.0.0.1] from localhost [127.0.0.1] 4687 got [GET] listening on [any] 80 ... connect to [127.0.0.1] from localhost [127.0.0.1] 4687 got [GET /quatsch] /#
Hier wird also genau registriert ob man Quatsch macht. Jetzt versuchen wir zu hacken indem wir zwei Verzeichnisse höher auslesen wollen.
/# quark http://localhost/../../
Entgegen aller Sicherheitsregeln bei Server können wir höher als das HTTPD-Root-Verzeichnis gehen. Wir können uns so jede Datei herunterladen. So z. B.
/# quark http://localhost/../../etc/passwd
Eine Freude für jeden Systemadministrator. Dieser WWW-Server ist also nur zum Test oder für Schulungen geeignet. PYGMY hat noch einen weiteren Nachteil. Er kann pro GET-Anforderung nur eine Datei senden. Meist besteht aber gehören zu einer HTML-Datei noch weitere Dateien, wie z. B. Grafiken. Diese könnten dann nur über ein Reload beim Browser geladen werden.
Robert.Warnke@giso.de (copyleft) Robert Warnke, Berlin (Germany) | http://rowa.giso.de