ubuntuusers.de

25. März 2009

Pentest oder auch Penetration-Test sind Sicherheitstest, wo ein Hacker, mit dem Einverständnis des Opfers versucht in ein Firmennetzwerk einzudringen.

Einer Firma hilft ein solcher Test zum Bestätigen, dass das eigenen Netzwerk (fast) sicher ist oder um eben Sicherheitslücken aufzudecken.

Jedoch hat nicht jeder das Wissen oder das Geld um einen solchen Test durchzuführen, doch Sicherheit sollte jeder geniessen können. Um dieses Problem auszuhebeln gibt es fix fertige Scanner, welche ein komplettes Netzwerk auf die neusten Exploits prüfen.

Welche Lücken gibt es?

Einer der besten dieser Scanner ist Nessus. Dieser ist in einer gratis Version verfügbar. Der Scanner erhält nach einer Gratis-Registrierung alle 24 Stunden die neusten Exploits und Sicherheitslücken und kann diese bei einem neuen Scan auch gleich einsetzen.

Nessus gibt es als Server und als Client. Man hat somit auch die Möglichkeit Nessus auf einem Server zu installieren und sich dann mit dem Client darauf einzuloggen.

Für die Installation habe ich ein kleines Script erstellt, welches alle Vorgänge beinahe automatisch durchführt. Oder man führt die folgenden Schritte aus:

Zuerst müssen wir Nessus installieren:

sudo apt-get install nessus nessusd

Nun müssen wir einen User hinzufügen:

sudo nessus-adduser

Hier muss man einen Usernamen eingeben, mit welchem man sich auf dem Nessus-Server einloggt. Bei Authentication kann man einfach ENTER drücken. Nach der Eingabe des Passwortes werden die Regeln definiert. Hier kann man getrost die Standardeinstellungen stehen lassen und nach einer kurzen Wartezeit mit Strg + D die Konfiguration abschliessen.
Damit man immer die aktuellen Exploits erhält, muss man sich gratis registrieren. Dies kann man hier machen: http://www.nessus.org/plugins/index.php?view=register

nessus-fetch --register $code

Nun kann man seine Plugins updaten:

sudo nessus-update-plugins

und schlussendlich den Server starten:

sudo /etc/init.d/nessusd start

Nun fügen wir noch einen Eintrag hinzu, damit der Server beim Starten des PC automatisch auch startet:

sudo update-rc.d nessusd defaults

Nun können wir Nessus starten. Das starten dauert ein bisschen, da neben dem laden aller Plugins auch noch die neusten runtergeladen werden:

nessus

Nun haben wir Nessus installiert. Doch nach einem Scan wissen wir erst, wo es eine Lücke gibt, nicht aber wie man sie ausnutzt.

Dazu haben wir das Metasploit Framework.

Die Exploits

Leider ist Metasploit nicht auf den Packetservern verfügbar. Deshalb muss man sich die Installation von hier besorgen.

Zur Installation kann man wieder mein Script verwenden oder folgende Anleitung verwenden.

Zuerst brauchen wir das aktuelle Framework. Dieses ist gepackt in einem Archiv also müssen wir zuerst entpacken:

tar -xzf framework-*

Da Metasploit auf Ruby basiert, brauchen wir noch den passenden Ruby-Hintergrund:

sudo apt-get install ruby libruby libgtk2-ruby libglade2-ruby libopenssl-ruby -y sqlite3*

Nun erstellen wir einen Ordner:

sudo mkdir /opt/metasploit

Und verschieben unsere Daten in den Ordner:

sudo mv framework-X.X/* /opt/metasploit/

Das Framework selbst gibt es als GUI, Webservice oder Konsole. Aufgerufen werden diese mit folgenden Befehlen:

/opt/metasploit/msfgui
/opt/metasploit/msfweb
sudo /opt/metasploit/msfconsole

Der Server ist dann unter der URL http://localhost:55555 verfügbar. Es ist jedoch empfohlen, die Konsole zu verwenden, da nur da alle Funktionen verfügbar sind.

Wie es nun weiter geht, dass muss jeder selbst raus finden, da sogenannte “Hack-Anleitungen” (ob für gute oder schlechte Zwecke) illegal sind. Ich weiss nicht einmal, ob es erlaubt ist die folgenden zwei Links zu posten:

Tutorial Part 1: http://www.ethicalhacker.net/content/view/227/24/
Tutorial Part 2: http://www.ethicalhacker.net/content/view/238/24/

Auf Seilo @ Geeky Ogre wurde gerade eine kurze Videopreview von Gnome-Zeitgeist vorgestellt.

Was ist das? Vor allem ist es ein Feature, das in Gnome integriert werden soll. Aktivitäten werden einer Zeitleiste zugeordnet. In dem Video kann man Videodateien, Texte und sogar besuchte Seiten erkennen.

Ergo ist es ein bisschen mehr. Diese zeitliche Einordnung ist eine andere Möglichkeit, die eigenen Dateien zu verwalten. Statt zu fragen: "Wo habe ich das vorhin gespeichert" kann man einfach beim Zeitpunkt "vorhin" nachschauen.

Denkbar sind noch viele weitere Anwendungsfälle, wenn man das Prinzip ausweiten sollte. Zeitliche Zuordnung lässt Schemata erkennen - z.B. "welche Programme werden immer nach dem Login gestartet?". Das würde einige interessante Funktionen ermöglichen.

Ich habe in den letzten Monaten ja schon immer mal wieder ein GNOME Panel Applet vorgestellt und heute bin ich auf ein weiteres sehr praktisches Applet gestoßen. Es heißt und SSHMenu. Mit diesem Applet ist es möglich mit zwei Klicks eine SSH-Verbindung zum Host seiner Wahl aufzubauen. Gerade wenn man öfter SSH-Verbindungen zu anderen Rechner aufbaut, ist dieses Tool nützlich.

Man kann SSHMenu aus den Quellen installieren:

sudo apt-get install sshmenu-gnome

Danach wird das Applet auf gewohnte Weise dem Panel hinzugefügt. Leider passt es sich nicht so schön in das Theme ein.

Bei der Konfiguration hat man sehr viele Möglichkeiten. Eine gute Übersicht findet man hier. So ist ohne Probleme möglich einen anderen Port anzugeben oder sogar die Position des Terminalfensters zu beeinflussen. Weiter kann jeder SSH Session ein bestimmtes Profil zugeordnet werden.

Quelle der Bilder: http://sshmenu.sourceforge.net

Kommentar hinzufügen

Durch einen Artikel auf Linuxdevices.com bin ich auf eine kurze Reportage zu einem Linux-Botnet aus “geknackten” Kabel- und DSL-Routern gestoßen: Larry Seltzer berichtet in der eWeek von einem Psyb0t getauften Netz, das ausschließlich aus DSL- und Kabelroutern der MIPSEL-Architektur basiert.

Betroffen sind offensichtlich Router mit schwachen Administrationspasswörtern, bei denen teilweise das Administrationsfrontend auf der WAN-Seite zugänglich war. Offenbar fand keine Modifikation des persistenten Speichers statt, so dass ein harter Reset genügt, um dem Spuk ein Ende zu bereiten — das Botnet soll abgeschaltet sein und keine weiteren Router identifizieren. Mit Routern wie der FRITZ!Box hätten die Botnet-Programmierer die Möglichkeit gehabt, durch ein paar Zeilen in der /var/flash/debug.cfg die Änderungen zu speichern.

Angesichts der weiter steigenden Fähigkeiten moderner DSL-Router, die als Datenablage im Heimnetz dienen und mittlerweile moderate Rechenleistung bereitstellen, entsteht ein interessantes Bedrohungsszenario, bei dem gehackte Boxen den Datenverkehr belauschen, Mail- oder Login-Passwörter für Shoppingportale über unverschlüsselte Verbindungen abhören oder Spam verschicken — einzelne Spam-Mails, Listen mit Mailadressen und einen SMTP-Client für den Versand, der auch mit Queueing auf Greylisting reagiert, lassen sich in wenigen hundert kB unterbringen.

Seltzer behauptet, dass der Hauptgrund dafür, dass es keine Botnets für Linux-Desktops gibt, darin liegt, dass der durchschnittliche Nutzer erfahrener als sein Windows-Kollege ist. Dem kann ich mich weitgehend anschließen. Nicht ganz d’accord bin ich mit der Behauptung, dass es sich um das erste Linux-Botnet handelt: Viele schlecht gewartete und anschließend “aufgemachte” Linux-Rootserver, die zum Spam-Versand oder für Wörterbuch-Passwort-Attacken missbraucht werden, weisen Botnet-Charakter auf — auch wenn es sich meist nur um Dutzende bis wenige Hundert beteiligte Rechner handeln dürfte und nicht um eine sechsstellige Zahl wie im vorliegenden Fall.

Für meinen eeepc suchte ich ein Stück Software, um damit e-Books zu lesen. Unter Ubuntu fand ich dann relativ schnell den FBReader. Das Teil gibt es aber auch für so manchen andere Plattform. Auf dem eeepc konnte ich die Software einfach installieren, da sie in den Quellen geführt wird:

sudo apt-get install fbreader

Das Teil versteht recht viele Formate, die es auch direkt aus Archiven (ZIP, TAR etc.) lesen kann. Aber leider kann der FBReader keine PDF-Dateien lesen, was bei der Häufigkeit von PDF-Ebooks noch ziemlich wichtig wäre, finde ich.

FBReader

Klar, PDFs liessen sich auch mit dem Document Viewer oder per Acrobat Reader ansehen, aber komfortabler wäre es schon mit einem EBook-Reader, alleine schon wegen dem Lesefluss. Ich suchte nach einem Converter, um die PDF-Files beispielsweise nach *epub zu wandeln, fand aber nichts Brauchbares.

Wahrscheinlich sitzen bei mir Härdöpfel (Kartoffeln) auf den Augen, so ich nichts finden kann. Oder ist die Welt der eBook-Reader (Software, nicht Hardware) wirklich so mager?

Ähnliche Artikel

24. März 2009

… der 1. Geburtstag von noqqe.de  =) Hätte beim ersten Blogpost ehrlichgesagt nicht erwartet das ein kleiner Blog mir mal so nützlich wird ! Mittlerweile auch mehr besucht als ich gedacht hätte :) Nach dem Umzug ist zwar nichts mehr von den damals 16.000 Besuchen auf wordpress.com zu sehen aber das macht ja nichts :)

Danke fürs viele lesen und die Kommentare :)

Bis auf weiteres…
Flo.

Dirks Kritik an der Fokussierung auf die Bootzeit hat viele Reaktionen ausgelöst. Worüber reden wir da eigentlich, auf welchem Stand ist Ubuntu?

Dabei zu klären ist die Definition der Bootzeit. Für mich und im Folgenden wird sie so definiert: Verstrichene Zeit ab der Auswahl des Systems in Grub bis die Oberfläche fertig geladen, also nutzbar, ist.

Für die Messung wurde der Autologin von GDM aktiviert, bei der Messung von KDE 4 der Autologin von KDM. Als Referenzwert dient meine Hardyinstallation, auf der IceWM von rungetty automatisch und ohne zwischengeschalteten Displaymanager gestartet wird.

Die Werte Intrepids

Gemessen wurde jeweils das Standarddesign. free +/- wurde einmal direkt nach dem Start, einmal nach 30 Sekunden gemessen. Sonstige Programme wurden nicht gestartet, allerdings auch keine standardmäßig dort platzierten Programme aus dem Panel geschmissen.

Grafisch

Tabellarisch
Kategorien Hardy (IceWM) Gnome (Compiz)* Gnome (Effekte) Gnome (ohne) KDE 4.2* Xfce LXDE IceWM (Intrepid) GDM* Windows XP
free +/-: 51916 189440 190792 185624 188212 164520 101792 82692 - 146000
free +/- (30s): 51864 211988 211736 185624 239716 182240 112660 82816 - 165000
Bootzeit: 0:50 1:15 1:13 1:03 1:11 0:59 0:55 0:45 0:44 0:50
Anmerkungen: *ohne Würfel *ohne Effekte *Design: Ubuntu *Design: Windows 2000

Fazit

Aktuelle Relationen

Im Intrepidvergleich ist nicht viel überraschendes zu entdecken. Gnome startete etwa so schnell wie KDE 4. KDE war allerdings in Version 4.2 aus inoffiziellen Quellen installiert und wird bei diesem Vergleich durch den mitzustartenden MySQL-Server behindert. Ein fairer Vergleich zwischen Gnome und KDE 4 unter Ubuntu wird erst mit Jaunty möglich sein, daher wurden die übrigen KDE-Werte nicht gemessen.

Compiz selbst wirkt nicht wirklich verlangsamend. Allerdings ändern das die Plugins ein bisschen, die durchaus Auswirkungen auf den Speicherverbrauch haben.

Xfce ist nicht wesentlich kleiner als Gnome ohne Effekte, aber deutlich größer als ein LXDE. LXDE dagegen verbraucht etwas mehr Ram als IceWM und startet etwas langsamer.

Bei IceWMs Startzeit ist beachtenswert, dass es kaum länger dauert, als wenn GDM nur sich selbst lädt.

Schön zu sehen ist die Beschleunigung im Vergleich zu Hardy. Allerdings kann man das hier nur beim IceWM-Vergleich sehen. Ob Gnome selbst unter Hardy nochmal langsamer startete? Der Speicherverbrauch zumindest von IceWM hat unter Intrepid zugenommen.

Windows XP ist etwas schneller als Gnome verfügbar, aber langsamer als IceWM. Allerdings ist das die Startzeit bis zur fertig geladenen Oberfläche, ohne Virenscanner, Firewall und sonstigen Startprogrammen, die unter Windows eher ein Muss sind als unter Ubuntu. Der Speicherverbrauch von Windows und Ubuntu ist nicht wirklich vergleichbar, die aufgelisteten Werte nur aus dem Taskmanager abgelesen.

Vergleich mit Gutsy

Unter Gutsy habe ich schonmal so einen Vergleich gemacht. Die Werte damals:

Kategorien IceWM (Dapper) Gnome (Compiz) Gnome (Metacity) Xfce LXDE IceWM (Gutsy)
Bootzeit: 0:39 1:10 1:04 0:52 0:42 0:39

Die Zeiten von Intrepid und Hardy stellen also eine Verschlechterung dar. Die Hardware hier ist fast identisch, nur der Ram wurde von 1GB auf 2GB aufgestockt, was die schlechtere Startzeit nicht erklärt (aber durchaus Auswirkungen auf den Speicherverbrauch haben kann, weswegen ich diese Werte weggelassen habe).

Auf die Befürchtungen und Wünsche von damals eingehend: Compiz hat sich kaum weiter verlangsamt, aber Gnome startet auch nicht schneller. Metacitys Effekte haben durchaus Auswirkungen auf Speicherverbrauch und Startzeit. LXDE liegt nun etwas näher bei Xfce. Konstant ist der Vorteil von IceWM: Es startet sofort.

Insgesamt bleibt festzuhalten, dass Jaunty hier einiges aufholen kann.

2.6.29 nun verfügbar. Als Maskottchen dient diesmal Tuz, ein Tasmanischer Beutelteufel mit angeklebtem Schnabel, und auch sonst hat sich gegenüber dem Vorgänger einiges verändert.

Obwohl die Änderungen am Quellcode seit -rc8 recht umfangreich sind, halten sich die spürbaren Neuerungen in Grenzen. Ein großer Teil ist dem kurzfristig angesetzten Urlaub von Tux geschuldet, daneben kamen noch Änderungen an der m86k-Architektur hinzu und letzte Korrekturen an dem aus dem staging-Zweig stammenden benet-Treiber.

Tuz, Linux-Maskottchen auf Zeit Der neue Kernel beschert uns dank Kernel Modesetting einen flackerfreien Start des Rechner, sofern wir über Intel-Grafik verfügen. Die Unterstützung für Grafik-Chips anderer Hersteller ist noch im Entstehen. Wer dagegen mit Multi-Prozessor-Systemen arbeitet wird, sich darüber freuen, dass nun ein Zusammenspiel des Kernels mit bis zu 4096 CPUs möglich ist. Für eine verbesserte Leistung auf Mehrprozessor-Systemen sorgt Tree-RCU, womit das klassiche RCU abgelöst wird, da es, ursprünglich für Systeme mit bis zu 32 CPUs konzipiert, mit zunehmender Anzahl an Prozessoren nicht mehr skalierbar war. RCU (Read-Copy Update) ist als Mechanismus zur Synchronisation von zeitgleichen Schreib- und Lesevorgängen im Hauptspeicher entwickelt worden und sorgt dafür, dass Lesevorgänge auf eine unveränderte oder eine neue Struktur zugreifen, jedoch nicht auf eine, die nur teilweise aktualisiert wurde und durch die Fehler verursacht würden.

Mit btrfs hält eine weiteres Dateisystem in den Kernel Einzug, das sich durch besondere Leistungsfähigkeit auszeichnen soll, allerdings befindet es sich derzeit noch in Entwicklung und wird daher nicht für den produktiven Einsatz empfohlen. Anders dagegen squashfs, das als Readonly-Dateisystem mit eingebauter Kompression speziell auf den Einsatz auf Live-CDs und ähnlichen Medien abzielt. Es gibt nun auch Unterstützung für WiMAX.

Viele neue Treiber sind hinzugekommen, insbesondere WLAN-Treiber aus dem staging-Zweig für z.B. Ralink, Realtek und Airgo-Chips. Die weiteren Änderungen und Korrekturen sind äußerst umfangreich und im Changelog auf KernelNewbies.org aufgeführt.

Quellen: Linux Kernel Mailing List, Kernel Newbies

 

Ich stolpere immer wieder über unbrauchbare Suchergebnisse bezüglich Linux-Themen bei Google. Die Problematik liegt einfach daran, dass das Internet ein Dschungel geworden ist, der nur nur schwer zu durchblicken ist. Speziell Anwender, die dem Englischen nicht mächtig sind, haben Probleme brauchbare Informationen auf Deutsch zu finden, weil - selbst wenn man bei Google nur deutschsprachige Seiten anzeigen lässt - zig Seiten mit Suchmaschinenspam, Ebay-Shops, Preislisten usw. die Ergebnisse verwässern.

Daher habe ich das kleine Projekt TuxSucht.de gestartet. Die Seite bindet die angepasste Suche von Google ein und durchsucht nur eine Auswahl an deutschsprachigen Foren rund um GNU/Linux, Blogs mit starkem Bezug zu Linux und auch eine Reihe von Shops, die sich auf Soft- und Hardware für Linux-Systeme spezialisiert haben. Mit de.uboontu.com gibt es zwar ein ähnliches Projekt, allerdings beschränkt man sich hier auf Ubuntu. Ein Limit das meines Erachtens viele Interessante Quellen ausser acht lässt.

TuxSucht.de

TuxSucht.de

Solltet ihr interessante Domains vermissen oder zusätzliche Ideen haben, so würde ich mich freuen, wenn ihr mir diese zukommen lassen könntet. Ich habe ein paar “Regeln” für die Aufnahme von Domains festgelegt, damit der Index nicht zu groß wird, all zu eng sehe ich die jedoch nicht. Ich hoffe, dass die Page dem einen oder anderem hilfreich ist.

Viel Spaß
Christoph

23. März 2009

Um ehrlich zu sein, mich ärgert ziemlich, dass anscheinend der Hauptfokus bei der Entwicklung mittlerweile auf der Verringerung der Bootzeit steht. Als ob es keine dringenderen Probleme zu lösen gibt.

Mich interessiert jetzt einmal, für wen die Beschleunigung der Bootzeit wirklich wichtig ist. Ab in die Kommentare bitte!.

Für mich ist es jedenfalls überhaupt kein Problem, ob der Rechner drei Minuten oder 20 Sekunden zum Starten braucht. Er wird angeschaltet, währenddessen kann man etwas anderes machen. Dann wird am Rechner gearbeitet und danach kann er schlafen gelegt werden bis zum nächsten Gebrauch.

Weil Broadcoms BCM4312 unter Linux Ärger bereitet wollte ich sie gestern gegen eine Intel 4965AGN austauschen. Allerdings muss man, um an die an der Unterseite des Mainboards befindliche WLAN-Karte heranzukommen, das Gerät komplett zerlegen. Mit dem Repair and Maintenace Manual geht das erstaunlich gut. Man benötigt lediglich einen Satz Feinmechanikerschraubendreher, kleine Torx-Schlüssel, einen flachen Schraubendreher für die Kunststofflaschen und etwas Zeit.

Die Ernüchterung kam dann, als das Mini-Note über fünf Minuten bis zum BIOS gebraucht hat: Das BIOS erkennt die Karte nicht und weigert sich, diese anzusprechen. Also die ganze Prozedur nochmal von vorne und Broadcom-Karte wieder reingebaut. Jetzt muss ich mal bei HP nachfragen, ob es einen versteckten BIOS-Menüpunkt gibt, mit dem sich andere Karten einstellen lassen. Wenn dann ein weiterer Versuch mit der Intel-Karte fällig ist, weiss ich, dass ich soviel Übung habe, dass Zerlegung und Zusammenbau in einer Viertelstunde erledigt ist.

Achja: Die Festplatte ist keine 1,8er, sondern eine normale 2,5er. Hier existiert also noch Upgradepotential. Zudem sind RAM und Platte nach Ausbau der Tastatur erreichbar und folglich auch von ungeübten Schraubern schnell getauscht.

Es geht wieder einmal um den guten alten VIM. Für alle die ihn nicht kennen, schämt euch :-P
VIM oder auch VI ist ein viel gehasster Texteditor. Viele verabscheuen und boykottieren ihn, weil er sehr kompliziert ist. Andere lieben ihn, weil er sehr komplex ist und viele Funktionen besitzt.

Ich persönlich habe mich immer zu der ersten Gruppe gezählt, da mir der VI einfach zu kompliziert war, und ich weder Zeit noch Nerven hatte mich einzuarbeiten.

Doch wie es der Zufall wollte bin ich auf ein bestimmtes Feature gestoßen, welches, soweit mir bekannt, nur der VI bietet. Es nennt sich Syntax-Highlighting, und ist extrem nützlich für Linux-User wie mich, welche oft Shellscripts schreiben (müssen).

Um die Funktion aber aktivieren zu können benötigt man das Packet vim-gui-common, welches neben dem Highlighting noch viele weitere coole Funktionen mitbringt.

Um im VI von diesem Packet zu profitieren tippt man folgenden Befehl:

:syntax enable

Wenn der Editor die Sprache erkennt, wird der Syntax farbig hervorgehoben.

Ich habe die Tage auf ubuntublog.ch einen Artikel über Xmind gelesen mit dem Hinweis, dass das Programm etwas handlicher als Freemind sein soll.
Also habe ich es gleich mal ausprobiert und war nach kurzer Zeit auch schon überzeugt. Nicht nur, dass man weitere Strukturen (Organigramm, Fischgräte, Mindmap, usw) auswählen, sondern man auch mehrere solcher Strukturen übereinander und nebeneinander anordnen kann.
Und das Allerschönste: Es gibt das Programm für Linux, Windows und Mac. Ein Wermutstropfen ist, dass man sich zum Herunterladen der Software auf der Seite registrieren muß.

22. März 2009

Zur Zeit macht ein neuer Messaging Client für Jabber / GoogleTalk im Netz von sich reden. Warscheinlich aufgrund seiner Eleganz. Hab ihn ausprobiert und er sieht wirklich sehr schön aus. Zwar noch nicht ganz ausgereift bzw ein paar Funktionen fehlen noch, aber wird demnächst bestimmt noch was schönes drauß. Wie man auf den beiden Screenshots sehen kann gibts auch verschiedene Theme-Möglichkeiten für den Chat.

Second Screenie: http://zwetschge.org/pic/Bildschirmfoto1.png

Das ganze gibts unter http://synapse.im/
Greez, Flo

Seit Ubuntu 8.10 (und wohl auch bei anderen, neueren Linux-Distributionen) werden ext3 Partitionen mit 265 I-Nodes statt mit 128 I-Nodes partitioniert. Da Acronis damit nicht zurecht kommt, kann man Ubuntu nicht mehr mit Hilfe von Acronis klonen.

Als Alterrnative kann man Ubuntu mit Hilfe einer Clonezilla Livecd klonen. Clonezilla kann von clonezilla.org heruntergeladen werden.

Ein etwas angepasstes, frisch installiertes Ubuntu 8.10 (mit einer Größe von ca. 4,3 GB) kann man innerhalb von weniger als 10 Minuten mit Clonezilla auf eine zweite, per S-ATA angeschlossene, Festplatte klonen.

(Falls man ein Image erstellt und dies spät wieder zurück spielen will, sollte man darauf achten, dass es sich um die gleiche Partitiontabelle handelt, also /dev/hdX und nicht /dev/hdY, da Clonezilla das Image sonst nicht korrekt zurückspielen kann.)

Nun ist der Linuxtag vorbei. So anstengend so ein Wochenende auch ist, es ist immer wieder schön und befriedigend. Sätze wie "Ich nutze Ubuntu jetzt seit $JAHREN und es läuft ..." sind sehr häufig.

Natürlich können wir am Stand nicht bei jedem Thema in die Tiefe gehen, dazu ist einfach nicht die Zeit. Außerdem können wir auch nicht alles wissen... Weiterführende Tipps bekommen die Leute dennoch immer mit.

Zeit für einen Plausch mit den anderen Standbetreuern gab es auch reichlich.
Das Konzept von Communtu finde ich interessant. Das Projekt macht es den Ubuntu-Nutzer einfach, nach der Installation die gewünschte zusätzliche Software in sein System zu integrieren. Ich bin gespannt, wie es da weiter geht...

Ich hab mich mehr um den Stand gekümmert, bin so weniger zu den Vorträgen gegangen. Einen hab ich dennoch angehört, den Vortrag zu LXDE. Ich mag halt kleine Desktopumgebungen...

Ich denke, daß ich 2010 wieder dabei bin...

Leider musste ich mittlerweile einen Nachteil bei der Installation der Gasterweiterungen feststellen, der mich sogar dazu brachte, sie komplett zu deinstallieren: Die Gasterweiterungen synchronisieren in unregelmäßigem Abstand die Zeit des Gastsystems mit dem Hostsystem. Wenn man als Host Windows hat und als Gast ein Linux-System mit ntpd, dann ist das nicht gerade toll. Wie also wird man die Gasterweiterungen wieder los? Nach einer Anleitung im Virtualbox-Forum muss man das aufgrund des Fehlens einer uninstall Option von Hand folgendermaßen bewerkstelligen:

sudo find /etc -name "*vboxadd*" -exec rm {} \;
sudo find /etc -name "*vboxvfs*" -exec rm {} \;
sudo rm -r /usr/src/vboxadd-*
sudo rm -r /usr/src/vboxvfs-*
sudo rm /usr/sbin/vboxadd-timesync
sudo rm /lib/modules/`uname -r`/misc/vboxadd.ko
sudo rm /lib/modules/`uname -r`/misc/vboxvfs.ko

Nach einem Neustart mit

sudo reboot

sollte sich das Zeitproblem erledigt haben. Vielleicht hätte es auch einfach gereicht, die Datei /usr/sbin/vboxadd-timesync umzubenennen und stattdessen einen Link auf /dev/null zu erzeugen. Aber sicher ist sicher ;-) Wer trotz der Entfernung der Gasterweiterungen Probleme hat, sollte bei älteren Kernel-Versionen eventuell die Bootparameter entsprechend ändern.


Früher oder später ist es für die meisten so weit: eine wissenschaftliche Arbeit, eine Facharbeit oder ein Manuskript mit wissenschaftlichem Hintergrund stehen vor der Tür. Hierfür sind oft Skizzen, Schaltbilder, Molekülstrukturen, Formeln o.Ä. von Nöten. Letztere kann man mit geeigneter Programmierung von LaTex erstellen. Für den Rest gibt es weitere, kostenlose Programme. Außerdem müssen v.a. die sparchorientierten Abiturienten Vokabeln lernen. Für diese Leute haben wir eine Liste über mögliche Programme zusammengestellt.

Chemie

Bkchem

Da ich dieses Jahr in Chemie Facharbeit schreiben musste/(durfte?), brauchte ich ein Programm, mit dem man einfach Strukturformeln erstellen kann, da ich nicht die Strukturformeln aus Wikipedia kopieren wollte.
Das Programm ist eigentlich selbsterklärend, man kann entweder mit vorgefertigten Formeln wie beispielsweise Benzol, Cyclohexan oder Cyclopentan zeichnen, oder seine Strukturformeln selbst aus Einfach-, Doppel- oder Dreifachbindungen zusammenbauen. Man kann die Atome einzeln benennen, ihnen Ladungen und freie Elektronenpaare zuweisen, oder auch Orbitale an sie anfügen. Das Programm verfügt noch über viele weitere Funktionen wie einen einfachen Vektor-Grafik-Editor oder eine Möglichkeit, Text einzufügen. Außerdem warnt das Programm einen, wenn die maximale Valenz überschritten ist, was zur Fehlervermeidung dient.
Die Formeln werden als svg-Dateien gespeichert, und können in vielen verschiedene Formate, darunter auch png, pdf oder, was besonders Praktisch ist, als OpenOffice-Draw-Datei.
Installation:
 sudo apt-get install bkchem 

gElemental

Als virtuelles Periodensystem benutze ich gElemental, ein sehr umfangreiches Periodensystem für, wie der Name schon sagt, GNOME. Natürlich kann man es auch unter KDE installieren, aber hier wäre Kalzium von der Optik her schöner.
Wenn man das Programm aufruft, sieht man ein Periodensystem und wenn man auf die Elemente klickt, öffnet sich ein Fenster mit drei Reitern, Allgemein, Physikalisch und Atomar mit sehr vielen Informationen, wie die Dichte, den Schmelzpunkt, die Elektronegativität oder den Atomradius.
Installation:
sudo apt-get install gelemental
sudo apt-get install kalzium    

Sprachen

Kwordquiz

Kwordquiz ist ein Programm, mit dem Vokabeln lernen kann.
Man kann die Vokabeln entweder selbst eintragen oder sich vorgefertigte Listen herunterladen.
Die Vokabeln kann man auf verschiedene Weisen abfragen. Einmal nach dem klassischen Karteikarten System, man sieht die eine Seite und muss dann sagen ob man es gewusst hätte oder nicht. Dies lädt natürlich dazu ein, sich selbst zu betrügen, weshalb die anderen zwei Methoden wohl besser sind. Die zweite Methode ist eine Multiple-Choice Auswahl, und das dritte ist eine Abfrage der Vokabeln. Hier ist leider der Nachteil, dass man das Ergebnis exakt so eintragen muss, wie es vorgegeben ist, was bei mehreren Bedeutungen schwierig sein kann.
Hat man eine Vokabel falsch beantwortet, kommt sie hinten an den Stapel und wird am Ende noch einmal abgefragt, solange bis alle Vokabeln richtig beantwortet wurden.
Installation:
 sudo apt-get install kwordquiz 

Mathe

Lybniz

Für die Mathematiker unter euch, die nach einem einfachen Funktionenplotter suchen, der die mathematischen Grundfunktionen kennt und Bilder einfach exportiert, sollte es einmal mit Lybniz probieren. Dieses nach einem verstorbenen Physiker benannte Programm kann bis zu 3 Funktionen gleichzeitig ausgeben. Der anzuzeigende Bereich lässt sich manuell skalieren, die x-Achse im Rad-Maß beschriften. Außerdem lassen sich Funktionswerte für alle Funktionen gleichzeitig berechnen. Die exportierten Graphen sind im PNG-Format.
Installation:
sudo apt-get install lybniz

wxMaxima

Um sich die Berechnung von ständig wiederkehrenden Mathematikaufgaben zu ersparen, kann man ein CAS benutzen, dass mehr als nur die Grundrechenarten beherrscht. Mit wxMaxima kann man sich, analog zum kommerziellen Windowsprogramm Derive, Ableitungen, Integrale und weitere wichtige Vorgehensweisen ersparen und den Computer rechnen lassen. wxMaxima basiert auf dem ungrafischen Programm Maxima und ist dementsprechend sehr mächtig.
Installation:
sudo apt-get install maxima wxmaxima 

Physik

Step

Physikalische Experimente, die in der Realität aufgrund von Luftfeuchtigkeit oder Reibung nicht funktionieren, lassen sich mit einem kleinen Programm namens step perfekt simulieren. Nach der Installation kann man sich die Anleitungen ansehen und seinen Versuchsaufbau nachstellen. Dabei ist es möglich, dass Versuchsergebnisse als Graphen in Echtzeit angezeigt werden. Für step benötigt man noch jede Menge KDE-Abhängigkeiten, die nach der Eingabe von
sudo apt-get install step
erfragt werden.

xfig/ Inkscape


Wichtig sind für physikalische Facharbeiten besonders Schaltkreise. Hierfür gibt es ein spezielles Vektorprogramm namens, xfig. Dieses mächtige Programm hat eine gewöhnungsbedürftige Oberfläche, ist aber nach einigen Zeichnungen verständlich. Wer auf eine modernere und "grafischere" Lösung setzen möchte, dem sei Inkscape empfohlen. Dieses weitaus mächtigere Programm lässt sich mit dem Linienwerkzeug (Umschalt+F6) bei gedrückter Strg-Taste perfekt zum Zeichnen von Schaltkreisen benutzen. Die Strg-Taste sorgt dabei für Winkel in 15°-Schritten.
Installation:
sudo apt-get install xfig
sudo apt-get install inkscape

Viel Spaß mit diesen Programmen

Benni & Jonas

Nachdem wir in den drei ersten Teilen zunächst OpenLDAP, Dovecot und Exim eingerichtet haben, geht es nun daran, getmail so einzurichten, dass Mails von einem externen Server via POP3 oder IMAP abgerufen werden und dann dem entsprechenden lokalen Benutzer zugestellt werden. Obwohl fast alles im Blog detailliert beschrieben ist, empfehle ich, die Konfigurationsdateien für das Mailsystem herunterzuladen.

Installation

Wir installieren getmail und das benötigte python-Modul durch den Befehl

sudo apt-get install getmail4 python-ldap

Konfiguration zum Mailabruf von externen Servern

Der Benutzer secmail wird für uns alle Mails abholen und an den jeweiligen Nutzer zustellen. Für diesen Zweck habe ich das Python-Skript getmail-ldap.py geschrieben. Es liest zunächst die Login-Daten aller externen Mail-Accounts aus dem LDAP-Verzeichnis und erzeugt für jeden Mailaccount eine entsprechende Konfigurationsdatei zur Verwendung mit getmail. Anschließend ruft es getmail auf und benachrichtigt im Falle einer Fehlermeldung den Administrator per E-Mail. Die folgenden Schritte führen wir unter dem Benutzer secmail durch, damit die Dateien mit der entsprechenden Berechtigung erzeugt werden. Dazu rufen wir sudo auf:

sudo -u secmail -s

Den folgenden Inhalt

#!/usr/bin/python
# File: getmail-ldap.py
try:
	import errno
	import string
	import logging
	import logging.handlers
	import ldap
	import ConfigParser
	import ldif
	import threading
	from StringIO import StringIO
	from ldap.cidict import cidict
	from os.path import os
	from subprocess import Popen,PIPE
except ImportError:
	print """Cannot find all required libraries please install them and try again"""
	raise SystemExit
 
config_file_location = '/home/secmail/getmail-ldap.cfg'
 
def pid_exists(pid):
    """Is there a process with PID pid?"""
    if pid < 0:
        return False
 
    exist = False
    try:
        os.kill(pid, 0)
        exist = 1
    except OSError, x:
        if x.errno != errno.ESRCH:
            raise
 
    return exist
 
def get_search_results(results):
    """Given a set of results, return a list of LDAPSearchResult
    objects.
    """
    res = []
 
    if type(results) == tuple and len(results) == 2 :
        (code, arr) = results
    elif type(results) == list:
        arr = results
 
    if len(results) == 0:
        return res
 
    for item in arr:
        res.append( LDAPSearchResult(item) )
 
    return res
 
class LDAPSearchResult:
    """A class to model LDAP results.
    """
 
    dn = ''
 
    def __init__(self, entry_tuple):
        """Create a new LDAPSearchResult object."""
        (dn, attrs) = entry_tuple
        if dn:
            self.dn = dn
        else:
            return
 
        self.attrs = cidict(attrs)
 
    def get_attributes(self):
        """Get a dictionary of all attributes.
        get_attributes()->{'name1':['value1','value2',...],
				'name2: [value1...]}
        """
        return self.attrs
 
    def set_attributes(self, attr_dict):
        """Set the list of attributes for this record.
 
        The format of the dictionary should be string key, list of
        string alues. e.g. {'cn': ['M Butcher','Matt Butcher']}
 
        set_attributes(attr_dictionary)
        """
 
        self.attrs = cidict(attr_dict)
 
    def has_attribute(self, attr_name):
        """Returns true if there is an attribute by this name in the
        record.
 
        has_attribute(string attr_name)->boolean
        """
        return self.attrs.has_key( attr_name )
 
    def get_attr_values(self, key):
        """Get a list of attribute values.
        get_attr_values(string key)->['value1','value2']
        """
        return self.attrs[key]
 
    def get_attr_names(self):
        """Get a list of attribute names.
        get_attr_names()->['name1','name2',...]
        """
        return self.attrs.keys()
 
    def get_dn(self):
        """Get the DN string for the record.
        get_dn()->string dn
        """
        return self.dn
 
    def pretty_print(self):
        """Create a nice string representation of this object.
 
        pretty_print()->string
        """
        str = "DN: " + self.dn + "\n"
        for a, v_list in self.attrs.iteritems():
            str = str + "Name: " + a + "\n"
            for v in v_list:
                str = str + "  Value: " + v + "\n"
        str = str + "========"
        return str
 
    def to_ldif(self):
        """Get an LDIF representation of this record.
 
        to_ldif()->string
        """
        out = StringIO()
        ldif_out = ldif.LDIFWriter(out)
        ldif_out.unparse(self.dn, self.attrs)
        return out.getvalue()
 
class RetrieveMails(threading.Thread):
	def __init__(self, getmail_binary, config_filename, config_data_dir):
		threading.Thread.__init__(self)
		self.getmail_binary, self.config_filename, self.config_data_dir = \
			getmail_binary, config_filename, config_data_dir
	def run(self):
		try:
			command = [self.getmail_binary, \
				#'--quiet', \
				'--rcfile=' + self.config_filename, \
				'--getmaildir=' + self.config_data_dir]
			self.pid_filename = self.config_filename + '.pid'
			# Check for a pidfile to see if the daemon already runs
			try:
				pid_file = file(self.pid_filename,'r')
				pid_number = pid = int(pid_file.read().strip())
				pid_file.close()
			except IOError:
				pid = None
			# Check whether process is really running
			if pid:
				pid = pid_exists(pid)
			if not pid:
				getmail_process = Popen(command, shell=False,stdout=PIPE,stderr=PIPE)
				try:
					file(self.pid_filename,'w+').write("%s\n" % getmail_process.pid)
					getmail_process.wait()
				finally:
					os.remove(self.pid_filename)
					# Zur Sicherheit die erstellte Konfigurationsdatei loeschen (Login-Daten!)
					os.remove(self.config_filename)
				stderr_output=string.join(getmail_process.stderr.readlines())
				if getmail_process.returncode <> 0 or len(stderr_output.strip())>0 :
					raise Exception, "Getmail command failed for " + " ".join(command) \
						+"\nStdErr: \n" + string.join(stderr_output.strip()) \
						+"\nStdOut: \n" + string.join(getmail_process.stdout.readlines())
			else:
				log_object.info("Command " + " ".join(command) +\
					" not executed, existing pid " + str(pid_number) + " found")
		except:
			log_object.exception("An error occured!")
 
class RetrieveAccount:
	account_name = None
	account_type = None
	login = None
	password = None
	server = None
	def __init__(self, account_name=None, account_type=None, server=None, login=None, password=None):
		self.account_name, self.account_type, self.login, self.password, self.server = \
			account_name, account_type, login, password, server
 
class GetmailConfigFile(ConfigParser.SafeConfigParser):
	output_filename = None
	def __init__(self, defaults, default_config_filename=None, output_filename=None):
		ConfigParser.SafeConfigParser.__init__(self, defaults)
		if default_config_filename is not None:
			self.read(default_config_filename)
		self.output_filename = output_filename
	def set_pop3_account(self, newRetrieveAccount):
		self.set('retriever','server',newRetrieveAccount.server)
		self.set('retriever','type',newRetrieveAccount.account_type)
		self.set('retriever','username',newRetrieveAccount.login)
		self.set('retriever','password',newRetrieveAccount.password)
		self.set('destination','arguments','("'+newRetrieveAccount.account_name+'",)')
	def write(self):
		if self.output_filename is not None:
			"""try:
				output_file = open(self.output_filename, 'wb')
			except:
				raise Exception, "Unable to open " + \
					self.output_filename + "for writing"
			finally:
				output_file.close()
			"""
			os.umask(0077)
			output_file = open(self.output_filename, 'wb')
			ConfigParser.SafeConfigParser.write(self, output_file)
		else:
			raise Exception, "No output file for configuration defined"
 
# Konfigurationsdatei lesen
config_object = ConfigParser.SafeConfigParser()
config_object.read(config_file_location)
 
# Set-up Logging
log_object = logging.getLogger("getmail-ldap")
log_object.setLevel(logging.DEBUG)
 
# This handler writes everything to a log file.
log_file_handler = logging.FileHandler(config_object.get('Logging','LogFile'))
log_file_formatter = logging.Formatter("%(levelname)s %(asctime)s %(funcName)s %(lineno)d %(message)s")
log_file_handler.setFormatter(log_file_formatter)
log_file_handler.setLevel(logging.DEBUG)
log_object.addHandler(log_file_handler)
 
# This handler emails anything that is an error or worse.
log_smtp_handler = logging.handlers.SMTPHandler(\
	config_object.get('Logging','MailServer'),\
	config_object.get('Logging','MailFrom'),\
	config_object.get('Logging','MailTo').split(','),\
	config_object.get('Logging','MailSubject'))
log_smtp_handler.setLevel(logging.ERROR)
log_smtp_handler.setFormatter(log_file_formatter)
log_object.addHandler(log_smtp_handler)
 
def main_call():
 
	## first you must open a connection to the LDAP server
	ldap_object = ldap.open(config_object.get('LDAP','LDAPServer'))
	ldap_object.simple_bind_s(\
		config_object.get('LDAP','BindDN'),\
		config_object.get('LDAP','BindPassword'))
	# searching doesn't require a bind in LDAP V3.
	# If you're using LDAP v2, set the next line appropriately
	# and do a bind as shown in the above example.
	# you can also set this to ldap.VERSION2 if you're using a v2 directory
	# you should  set the next option to ldap.VERSION2 if you're using a v2 directory
	ldap_object.protocol_version = ldap.VERSION3	
 
	## The next lines will also need to be changed to support your search requirements and directory
	## retrieve all attributes - again adjust to your needs - see documentation for more options
 
	if config_object.get('LDAP','SearchScope').upper() == "SUB":
            search_scope = ldap.SCOPE_SUBTREE
        elif config_object.get('LDAP','SearchScope').upper() == "ONE":
            search_scope = ldap.SCOPE_ONELEVEL
        else:
            search_scope = ldap.SCOPE_BASE
 
	ldap_result_id = ldap_object.search( \
		config_object.get('LDAP','SearchDN'), \
		search_scope,
		config_object.get('LDAP','SearchFilter'), \
		None)
 
	ldap_results = []
 
	while 1:
		result_type, result_data = ldap_object.result(ldap_result_id, 0)
		if (result_data == []):
			break
		else:
			## here you don't have to append to a list
			## you could do whatever you want with the individual entry
			## The appending to list is just for illustration.
			if result_type == ldap.RES_SEARCH_ENTRY:
				ldap_results += get_search_results(result_data)
	for ldap_result in ldap_results:
		account = RetrieveAccount( \
			# Account Name \
			ldap_result.get_attr_values(\
				config_object.get('LDAP','RelevantAttributes').split(',')[0])[0] ,\
			# Account Type \
			ldap_result.get_attr_values(\
				config_object.get('LDAP','RelevantAttributes').split(',')[1])[0],\
			# Server \
			ldap_result.get_attr_values(\
				config_object.get('LDAP','RelevantAttributes').split(',')[2])[0],\
			# Login \
			ldap_result.get_attr_values(\
				config_object.get('LDAP','RelevantAttributes').split(',')[3])[0],\
			# Password \
			ldap_result.get_attr_values(\
				config_object.get('LDAP','RelevantAttributes').split(',')[4])[0]\
		)
		config_output_filename = os.path.join(\
			config_object.get('Main','ConfigFileOutputDir'), \
			"getmail_" + \
			account.account_name + \
			".cfg")
		config_file = GetmailConfigFile(None, \
			config_object.get('Main','DefaultGetmailConfigFile'), config_output_filename)
		config_file.set_pop3_account(account)
		log_object.info("Writing Account Configuration for " + account.account_name + \
				" to file " + config_output_filename)
		config_file.write()
		RetrieveMails(\
			config_object.get('Main','GetmailBinary'), \
			config_output_filename, \
			config_object.get('Main','GetmailDir')\
		).start()
		#print config_output_filename
		#print "Name " + account.account_name
		#print "Type " + account.account_type
		#print "Server " + account.server
		#print "Login " + account.login
		#print "Password " + account.password
		#print "-----------------"
		#print ldap_result.pretty_print()
 
if __name__ == "__main__":
	try:
		main_call();
	except:
		log_object.exception("An error occured!")

speichern wir als /home/secmail/getmail-ldap.py und machen die Datei durch ein

chmod 750 getmail-ldap.py

ausführbar. Das Skript besitzt eine Konfigurationsdatei unter /home/secmail/getmail-ldap.cfg mit dem Inhalt

[Main]
# Path to getmail
GetmailBinary=/usr/bin/getmail
# Directory that should be used as a storage by getmail
GetmailDir=/home/secmail/getmail_data
# Read default values for getmail from this file
DefaultGetmailConfigFile=/home/secmail/getmailrc_template.cfg
# Save the final configuration files which include the LDAP details to this directory
ConfigFileOutputDir=/home/secmail/getmail_config
 
[Logging]
# Write messages to the following log file
LogFile=/var/log/getmail-ldap.log
# If a severe error occures a mail goes to the admin
# SMTP-Server to use for sending this error notification
MailServer=localhost
# Mail address of the sender of this error notification
MailFrom=secmail@myserver
# Recipients of this error notification
# separate multiple recipients by comma
MailTo=root@myserver
# Subject of the error notification
MailSubject=Getmail-LDAP Error
 
[LDAP]
# Read LDAP information from this server
LDAPServer=myserver
# Authenticate with the following DN
BindDN=uid=secmail, ou=users, o=effinger
# Authenticate with the following password
BindPassword=mysecmailpassword
# Restrict search of external mail accounts to this DN
SearchDN=ou=users, o=effinger
# Scope of search for external mail accounts
# Possible values include SUB, ONE and BASE
SearchScope=SUB
# Identify external mail accounts with the following filter
SearchFilter=(&(dcSubMailAddress=*)(objectClass=dcExternalMailAccount)(dcAccountStatus=active)(dcRetrieveType=*)(dcRetrieveLogin=*)(dcRetrievePassword=*))
# List of LDAP-Attributes used to determine the following variables
# 	1. Name for resulting getmail configuration file (must be unique)
#	2. Type for mail collection e.g. BrokenUIDLPOP3Retriever
#	3. Mail server to collect mails from
#	4. Login for mail server
# 	5. Password for mail server
# separate by comma
RelevantAttributes=dcSubMailAddress,dcRetrieveType,dcRetrieveServer,dcRetrieveLogin,dcRetrievePassword

Die Konfigurationsoptionen habe ich durch Kommentare dokumentiert. In jedem Fall muss in dieser Datei im Abschnitt [LDAP] der LDAPServer von myserver auf den jeweiligen DNS-Eintrag des OpenLDAP-Servers angepasst werden. Auch die Zeile mit BindPassword müssen wir ändern, so dass sie das secmail Passwort enthält. Da diese Datei mit dem Passwort sensible Informationen enthält, die es einem Angreifer erlauben würden, aus dem LDAP-Verzeichnis alle Login-Informationen der externen Mail-Accounts zu lesen, setzen wir die Berechtigung für die Datei so, dass nur secmail darauf zugreifen kann:

chmod 640 getmail-ldap.cfg

Anschließend erzeugen wir die referenzierte Datei /home/secmail/getmailrc_template.cfg mit dem Inhalt

[retriever]
type =
server =
username =
password = 
 
[destination]
type = MDA_external
path = /usr/sbin/exim4
arguments = ("user@mailhost.tld",)
 
[options]
# for testing do not delete mails
#delete = false
delete = true
message_log = /var/log/getmail.log
read_all = true
# do not manipulate the header
delivered_to = false
received = false

Die einzelnen Konfigurationsoptionen werden in der Dokumentation von getmail detailliert erläutert. Wichtig ist hier zu wissen, dass das Python-Skript diese Datei als Vorlage nimmt und dann in der Sektion [retriever] die Werte für type, server, username und password aus dem LDAP-Verzeichnis einträgt. In der Sektion [destination] wird der Wert arguments so abgeändert, dass die Mail an den lokalen Benutzer geht. Das Zusammenspiel von getmail und exim wird in einem Forumsbeitrag näher erläutert.
Empfehlung: Zu Beginn ist es sicherlich sinnvoll, im Abschnitt [options] den Wert von delete auf false zu setzen. So werden die Mails vom externen Server zwar heruntergeladen, aber nicht gelöscht. Wenn alles einwandfrei funktioniert, kann man hier den Wert wieder auf true setzen.
Auch hier setzen wir die Berechtigungen für die Datei entsprechend:

chmod 640 getmailrc_template.cfg

Nun erzeugen wir noch ein Verzeichnis, welches getmail benötigt und eines zum Ablegen der finalen Konfigurationsdateien mit den Berechtigungen, so dass nur secmail darauf zugreifen kann.

mkdir -m 750 /home/secmail/getmail_data /home/secmail/getmail_config

Dann erzeugen wir die Logdateien im Verzeichnis /var/log und setzen die Berechtigung so, dass auch secmail in diese Dateien schreiben kann.

sudo touch /var/log/getmail{-ldap,}.log
sudo chown root.secmail /var/log/getmail{-ldap,}.log
sudo chmod 660 /var/log/getmail{-ldap,}.log

Testen des Mailabrufs

Mit dem Aufruf des Pythonskripts durch ein

sudo -u secmail -s
/home/secmail/getmail-ldap.py

und das anschließende Inspizieren der Log-Dateien /var/log/getmail-ldap.log und /var/log/getmail.log können wir testen, ob die Mails heruntergeladen werden. Ob die Zustellung an den lokalen Benutzer geklappt hat, sieht man an neuen Dateien im jeweiligen maildir (hier: /home/paul/mail/paulpanzer@gmx.de/maildir/INBOX/new) bzw. durch Abruf der Mails mit einem Client z.B. per IMAP.

Regelmäßiges Zustellen externer Mails

Damit die Mails regelmäßig von dem externen Server abgerufen werden, richten wir einen Cron-Job ein, der alle fünf Minuten prüft, ob neue Mails vorhanden sind. Dazu führen wir als secmail User

crontab -e

aus und tragen dort die Zeile

*/5 * * * * /home/secmail/getmail-ldap.py

ein. Bei Adam Kane kann man nachlesen, was ein Cron-Job ist.

Feintuning – Logdateien mit Logrotate verwalten

Nachdem nun alles soweit eingerichtet ist, kümmern wir uns noch darum, dass die Logdateien ordentlich aufgeräumt werden. Wir erzeugen deshalb im Verzeichnis /etc/logrotate.d/ die Datei dovecot mit dem Inhalt

# Logrotate Konfiguration für dovecot
/var/log/dovecot.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 600 root root
}
/var/log/dovecot-deliver.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 600 root secmail
}

und ebenso die Datei getmail mit diesem Inhalt

# Logrotate Konfiguration für getmail und getmail-ldap
# siehe /home/secmail/getmail-ldap.py
/var/log/getmail.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 660 root secmail
}
/var/log/getmail-ldap.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 660 root secmail
}

Wir korrigieren außerdem noch einen kleinen Bug im exim-Paket, indem wir die Zeile

        create 640 Debian-exim adm

in den beiden Dateien exim-base und exim-paniclog im selben Verzeichnis durch folgende Zeile ersetzen

        create 640 Debian-exim root

Tip zum Logging des OpenLDAP-Servers von der OpenLDAP-Mailingliste: Standardmäßig wird alles in die syslog geschrieben. Wenn man der Übersichtlichkeit halber eine eigene Logdatei für OpenLDAP haben möchte, muss man OpenLDAP mitteilen, dass es beim Loggen einen eigenen Selektor (hier:local4) verwenden soll. Dazu muss die Datei /etc/default/slapd die folgende Zeile enthalten:

SLAPD_OPTIONS="-l local4"

Nun konfigurieren wir syslog so, dass es alle Informationen mit diesem Selektor in eine eigene Datei schreibt, indem wir in der Datei /etc/syslog.conf (bei Verwendung von sysklogd) um folgende Zeile ergänzen bzw. /etc/rsyslog.d/60-slapd.conf mit folgendem Inhalt erzeugen (bei Verwendung von rsyslog).

# Log openldap to separate file
local4.*			-/var/log/slapd.log

Außerdem legen wir eine entsprechende Datei namens /etc/logrotate.d/slapd mit dem folgenden Inhalt an.

/var/log/slapd.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 660 root openldap
}

Damit die Änderungen Wirkung zeigen, müssen wir anfangs eine Logdatei erzeugen und anschließend Syslog und OpenLDAP neu starten bzw. die Konfiguration neu laden.

sudo touch /var/log/slapd.log
sudo chown root.openldap /var/log/slapd.log
sudo chmod 660 /var/log/slapd.log
sudo /etc/init.d/sysklogd reload
sudo /etc/init.d/slapd restart

Links zum getmail-ldap Python-Skript

Bei der Erstellung des Python-Skripts waren einige Webseiten sehr hilfreich, die deshalb hier aufgeführt werden, obowhl sie für die Einrichtung des Mailservers ohne Bedeutung sind.

Weitere Konfigurationsschritte

Die Schritte zur Einrichtung der im ersten Teil angesprochenen Komponenten Roundcube als Webmaildienst, LDAP zur Verwaltung von Addressen und Spamassassin zum Filtern von Spam-Mails sowie eine Anleitung zum Einrichten eins Mail-Clients werden aufgrund von Zeitmangel leider erst in einigen Wochen verfügbar sein.

Nach der Einrichtung von OpenLDAP im ersten Teil, der Anpassung und Konfiguration von dovecot im zweiten Teil befasst sich der dritte Teil mit der Konfiguration von Exim. Obwohl fast alles im Blog detailliert beschrieben ist, empfehle ich, die Konfigurationsdateien für das Mailsystem herunterzuladen.

Installation von Exim

Da wir bei exim die LDAP-Unterstützung benötigen, müssen wir die entsprechende Exim-Version mit einem

sudo apt-get install exim4-daemon-heavy

installieren. Dabei wird notwendigerweise auch postfix entfernt, das von Ubuntu standardmäßig als Message Transfer Agent (MTA) eingesetzt wird.

Konfiguration von Exim

Damit exim auf die SSL-Zertifikate zur Verschlüsselung der SMTP-Verbindungen zugreifen kann, müssen wir den exim-Benutzer zur Gruppe ssl-cert hinzufügen

sudo adduser Debian-exim ssl-cert

Zur Konfiguration von exim kann man unter Ubuntu/Debian ein spezielles Konfigurationspaket namens exim4-config verwenden. Dieses erzeugt aus einzelnen Dateien im Verzeichnis /etc/exim4/conf.d eine finale Konfigurationsdatei (nähere Informationen zu exim4-config auf der Debian-Seite). Ich empfehle, dieses Konfigurationspaket zu verwenden und die Grundkonfiguration mit

sudo dpkg-reconfigure exim4-config

zu starten. Im anschließenden Konfigurationsdialog wählen wir Nur lokale Mailzustellung; keine Netzwerkverbindung. Dann geben wir den korrekten DNS-Namen des Servers an, den wir auch schon bei der Erzeugung der Schlüsselzertifikate verwendet haben (hier im Beispiel myserver). Der nächste Punkt ist eigentlich selbsterklärend, wenn der SMTP-Server über alle Interfaces erreichbar sein soll, das Feld leer lassen, ansonsten die gewünschte IP-Addresse eintragen. Der nächste Schritt fordert uns auf, mögliche weitere Domains für den lokalen Mailempfang anzugeben (im Zweifelsfall leer lassen). Der Punkt, ob DNS-Anfragen minimiert werden sollen, beantworten wir mit Nein. Als Speicherformat für lokale Mails wählen wir mbox (wird aber später modifiziert). Die Einstellungen sollen in kleine Dateien aufgeteilt werden. Nun machen wir uns an die Anpassung. Wir editieren die Datei /etc/exim4/update-exim4.conf.conf und ändern die letzte Zeile mit dem Eintrag

dc_localdelivery='mail_spool'

in

dc_localdelivery='dovecot_delivery'

ab. Im nächsten Schritt löschen wir den Inhalt des Verzeichnisses /etc/exim4/conf.d und kopieren die Dateien aus dem Konfigurationspaket dorthin mit

sudo rm -rf /etc/exim4/conf.d
sudo cp -R /path/to/configfiles/exim/conf.d /etc/exim4

In der Datei /etc/exim4/conf.d/main/00_local_macros passen wir folgende Zeilen an:

ldap_default_servers = myserver
MAIN_TLS_CERTIFICATE = /etc/ssl/certs/myserver.crt
MAIN_TLS_PRIVATEKEY = /etc/ssl/private/myserver.key

Wir ersetzen hier myserver jeweils durch den DNS-Namen des Servers. Nun erzeugen wir die finale Konfigurationsdatei für exim und starten exim anschließend neu mit dem Befehl

sudo update-exim4.conf && sudo /etc/init.d/exim4 restart

Das Programm erzeugt so eine finale Konfigurationsdatei, die unter /var/lib/exim4/config.autogenerated abgelegt wird. Für diejenigen, die das Debiankonfigurationssystem nicht nutzen können/wollen, ist hier deren Inhalt aufgeführt:

#########
# WARNING WARNING WARNING
# WARNING WARNING WARNING
# WARNING WARNING WARNING
# WARNING WARNING WARNING
# WARNING WARNING WARNING
# This file is generated dynamically from the files in
# the conf.d/ directory, or from exim4.conf.template respectively.
# Additional information is read from update-exim4.conf.conf
# This version of the file was created from the directory /etc/exim4
# Any changes you make here will be lost.
# See /usr/share/doc/exim4-base/README.Debian.gz and update-exim4.conf(8)
# for instructions of customization.
# WARNING WARNING WARNING
# WARNING WARNING WARNING
# WARNING WARNING WARNING
# WARNING WARNING WARNING
# WARNING WARNING WARNING
#########
 
FIRST_USER_ACCOUNT_UID = 1000
 
acl_not_smtp_start = acl_check_not_smtp
 
ldap_default_servers = myserver
 
LDAP_BASE = ou=users,o=effinger
 
SEC_MAIL_USER=secmail
IS_SENDER_SECMAIL = eq{$originator_uid}{${extract{2}{:}{${lookup{SEC_MAIL_USER}lsearch{/etc/passwd}{$value}}}}}
received_header_text = ${if !IS_SENDER_SECMAIL {Received: ${if def:sender_rcvhost {from $sender_rcvhost\n\t}{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)\n\t}}}}by $primary_hostname ${if def:received_protocol {with $received_protocol}} ${if def:tls_cipher {($tls_cipher)\n\t}}(Exim $version_number)\n\t${if def:sender_address {(envelope-from <$sender_address>)\n\t}}id $message_exim_id${if def:received_for {\n\tfor $received_for}}}{}}
LOCAL_DELIVERY_SECMAIL = dovecot_delivery_secmail
 
MAIN_TLS_ENABLE = yes
MAIN_TLS_CERTIFICATE = /etc/ssl/certs/myserver.crt
MAIN_TLS_PRIVATEKEY = /etc/ssl/private/myserver.key
MAIN_TLS_VERIFY_CERTIFICATES = /etc/ssl/certs/ca.crt
 
SENDER_EXTRACT_UID = ${sg{${lc:$sender_address}} \
	{\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+)$\N}{\$1}}
 
SENDER_EXTRACT_REAL_MAIL = ${sg{${lc:$sender_address}} \
	{\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+)$\N}{\$2}}
 
IS_SENDER_REMOTE = ${lookup ldap \
		{ldap:///uid=${quote_ldap_dn:SENDER_EXTRACT_UID},LDAP_BASE??sub?(&(dcSubMailAddress=${quote_ldap:SENDER_EXTRACT_REAL_MAIL})(dcAccountStatus=active))} \
		{yes}fail}
 
IS_LOCAL_PART_VALID = ${lookup ldap \
		{ldap:///uid=${quote_ldap_dn:${lc:$local_part}},LDAP_BASE??base?(objectClass=dcMailUser)} \
		{yes}{no}}
 
GET_UID_FOR_RCPT = ${tr \
	{${lookup ldapm \
		{ldap:///LDAP_BASE??sub?${if match_domain{$domain}{+local_domains}{(mail=${quote_ldap:$local_part})}{(&(dcSubMailAddress=${quote_ldap:$local_part@$domain})(dcAccountStatus=active))}}} \
		{${sg{${lc:$value}}{\N(?m)^.*uid="(.*?)".*$\N}{\$1}}} \
	}} \
	{\n}{,} \
}
 
GET_ALIAS_FOR_RCPT = ${tr \
	{${lookup ldapm \
		{ldap:///LDAP_BASE?mail,dcSubMailAddress?sub?(|(dcMailAlias=${quote_ldap:$local_part${if match_domain{$domain}{+local_domains}{}{@$domain}}})(&(dcMailAlternateAddress=${quote_ldap:$local_part@$domain})(dcAccountStatus=active)))} \
		{${sg{${lc:$value}}{\N(?m)^.*(mail|dcsubmailaddress)="(.*?)".*$\N}{\$2}}} \
	}} \
	{\n}{,} \
}
 
GET_ALIAS_FOR_AUTH = ${tr \
	{${lookup ldapm \
		{ldap:///LDAP_BASE?dcMailAlias,dcMailAlternateAddress?sub?(|(mail=${quote_ldap:AUTH_SERVER_MAIL})(&(dcSubMailAddress=${quote_ldap:AUTH_SERVER_MAIL})(dcAccountStatus=active)))} \
		{${sg{${lc:$value}}{\N(?m)^.*(dcmailalias|dcmailalternateaddress)="(.*?)".*$\N}{\$2}}} \
	}} \
	{\n}{,} \
}
 
GET_COMPLETE_MAIL_FOR_LOCAL_PART_UID = ${lookup ldap \
		{ldap:///uid=${quote_ldap_dn:${lc:$local_part}},LDAP_BASE?mail?base?(objectClass=dcMailUser)} \
		{${local_part}@${value}}}
 
GET_LOCAL_MAIL = ${if match_domain{$parent_domain}{+local_domains} \
	{GET_COMPLETE_MAIL_FOR_LOCAL_PART_UID} \
	{${lookup ldap \
		{ldap:///uid=${quote_ldap_dn:${lc:$local_part}},LDAP_BASE?dcSubMailAddress?sub?(&(dcSubMailAddress=${quote_ldap:$parent_local_part@$parent_domain})(dcAccountStatus=active))} \
		{$local_part@$parent_local_part@$parent_domain} \
		{GET_COMPLETE_MAIL_FOR_LOCAL_PART_UID} \
	}} \
}
 
IS_AUTH_REMOTE = ${lookup ldap { \
	user="uid=${quote_ldap_dn:AUTH_SERVER_UID},LDAP_BASE" \
    	pass=${quote:AUTH_SERVER_PASSWORD} \
	ldap:///LDAP_BASE??sub?(&(dcSubMailAddress=${quote_ldap:AUTH_SERVER_MAIL})(dcAccountStatus=active)(dcSMTPServer=*)(dcSMTPLogin=*)(dcSMTPPassword=*))} \
	{yes}fail}
 
AUTH_REMOTE_SERVER = ${lookup ldap { \
	user="uid=${quote_ldap_dn:AUTH_SERVER_UID},LDAP_BASE" \
    	pass=${quote:AUTH_SERVER_PASSWORD} \
	ldap:///LDAP_BASE?dcSMTPServer?sub?(&(dcSubMailAddress=${quote_ldap:AUTH_SERVER_MAIL})(dcAccountStatus=active)(dcSMTPServer=*)(dcSMTPLogin=*)(dcSMTPPassword=*))} \
	{$value}{}}
 
AUTH_REMOTE_LOGIN = ${lookup ldap {\
	user="uid=${quote_ldap_dn:AUTH_SERVER_UID},LDAP_BASE" \
    	pass=${quote:AUTH_SERVER_PASSWORD} \
	ldap:///LDAP_BASE?dcSMTPLogin?sub?(&(dcSubMailAddress=${quote_ldap:AUTH_SERVER_MAIL})(dcAccountStatus=active)(dcSMTPServer=*)(dcSMTPLogin=*)(dcSMTPPassword=*))} \
	{$value}{}}
 
AUTH_REMOTE_PASSWORD = ${lookup ldap {\
	user="uid=${quote_ldap_dn:AUTH_SERVER_UID},LDAP_BASE" \
    	pass=${quote:AUTH_SERVER_PASSWORD} \
	ldap:///LDAP_BASE?dcSMTPPassword?sub?(&(dcSubMailAddress=${quote_ldap:AUTH_SERVER_MAIL})(dcAccountStatus=active)(dcSMTPServer=*)(dcSMTPLogin=*)(dcSMTPPassword=*))} \
	{$value}{}}
 
AUTH_SERVER_PLAIN_AUTH = ${if ldapauth \
    {user="uid=${quote_ldap_dn:${sg{${lc:$auth2}} \
 	{\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_@.-]+)$\N}{\$1}}},LDAP_BASE" \
    pass=${quote:$auth3} \
    ldap:///}{yes}{no}}
 
AUTH_SERVER_LOGIN_AUTH = ${if ldapauth \
    {user="uid=${quote_ldap_dn:${sg{${lc:$auth1}} \
 	{\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_@.-]+)$\N}{\$1}}},LDAP_BASE" \
    pass=${quote:$auth2} \
    ldap:///}{yes}{no}}
 
AUTH_SERVER_MAIL = ${sg{${lc:${extract{1}{\/}{$authenticated_id}}}}{\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_@.-]+)$\N}{\$2}}
 
AUTH_SERVER_UID = ${sg{${lc:${extract{1}{\/}{$authenticated_id}}}}{\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_@.-]+)$\N}{\$1}}
 
AUTH_SERVER_PASSWORD = ${extract{2}{\/}{$authenticated_id}}
 
IS_SENDER_BAD = ${if match {AUTH_SERVER_MAIL}{\N^[a-zA-Z0-9_.-]+$\N} \
	{${if match {${lc:AUTH_SERVER_MAIL}} {${lc:$sender_address_local_part}} {no} \
		{${if match {${lc:$sender_address_local_part}} \
			{${lc:${tr{GET_ALIAS_FOR_AUTH}{,}{::}}}} \
			{no}{yes}}}\
	}} \
	{${if match_address {${lc:AUTH_SERVER_MAIL}} {${lc:$sender_address}} {no} \
		{${if match_address {${lc:$sender_address}} \
			{${lc:${tr{GET_ALIAS_FOR_AUTH}{,}{::}}}} \
			{no}\
			{${if and{ \
					{match_domain{$sender_address_domain}{+local_domains}} \
					{match_local_part{$sender_address_local_part}{SEC_MAIL_USER}} \
					{match_ip{$sender_host_address}{@[]}} \
				}\
				{no}\
				{yes}\
			}}\
		}}\
	}}}
 
exim_path = /usr/sbin/exim4
 
.ifndef CONFDIR
CONFDIR = /etc/exim4
.endif
 
UPEX4CmacrosUPEX4C = 1
##############################################
# the following macro definitions were created
# dynamically by /usr/sbin/update-exim4.conf
.ifndef MAIN_PACKAGE_VERSION
MAIN_PACKAGE_VERSION=4.69-5ubuntu2
.endif
.ifndef MAIN_LOCAL_DOMAINS
MAIN_LOCAL_DOMAINS=@:localhost
.endif
.ifndef MAIN_RELAY_TO_DOMAINS
MAIN_RELAY_TO_DOMAINS=empty
.endif
.ifndef ETC_MAILNAME
ETC_MAILNAME=myserver
.endif
.ifndef LOCAL_DELIVERY
LOCAL_DELIVERY=dovecot_delivery
.endif
.ifndef MAIN_RELAY_NETS
MAIN_RELAY_NETS=: 127.0.0.1 : ::::1
.endif
.ifndef DCreadhost
DCreadhost=empty
.endif
.ifndef DCsmarthost
DCsmarthost=empty
.endif
.ifndef DC_eximconfig_configtype
DC_eximconfig_configtype=local
.endif
.ifndef DCconfig_local
DCconfig_local=1
.endif
##############################################
 
domainlist local_domains = MAIN_LOCAL_DOMAINS
 
domainlist relay_to_domains = MAIN_RELAY_TO_DOMAINS
 
hostlist relay_from_hosts = MAIN_RELAY_NETS
 
.ifndef MAIN_PRIMARY_HOSTNAME_AS_QUALIFY_DOMAIN
.ifndef MAIN_QUALIFY_DOMAIN
qualify_domain = ETC_MAILNAME
.else
qualify_domain = MAIN_QUALIFY_DOMAIN
.endif
.endif
 
.ifdef MAIN_LOCAL_INTERFACES
local_interfaces = MAIN_LOCAL_INTERFACES
.endif
 
.ifndef LOCAL_DELIVERY
LOCAL_DELIVERY=mail_spool
.endif
 
gecos_pattern = ^([^,:]*)
gecos_name = $1
 
.ifndef CHECK_RCPT_LOCAL_LOCALPARTS
CHECK_RCPT_LOCAL_LOCALPARTS = ^[.] : ^.*[@%!/|`#&?]
.endif
 
.ifndef CHECK_RCPT_REMOTE_LOCALPARTS
CHECK_RCPT_REMOTE_LOCALPARTS = ^[./|] : ^.*[@%!`#&?] : ^.*/\\.\\./
.endif
 
.ifndef MAIN_LOG_SELECTOR
MAIN_LOG_SELECTOR = +tls_peerdn
.endif
 
.ifndef MAIN_ACL_CHECK_MAIL
MAIN_ACL_CHECK_MAIL = acl_check_mail
.endif
acl_smtp_mail = MAIN_ACL_CHECK_MAIL
 
.ifndef MAIN_ACL_CHECK_RCPT
MAIN_ACL_CHECK_RCPT = acl_check_rcpt
.endif
acl_smtp_rcpt = MAIN_ACL_CHECK_RCPT
 
.ifndef MAIN_ACL_CHECK_DATA
MAIN_ACL_CHECK_DATA = acl_check_data
.endif
acl_smtp_data = MAIN_ACL_CHECK_DATA
 
.ifdef MESSAGE_SIZE_LIMIT
message_size_limit = MESSAGE_SIZE_LIMIT
.endif
 
.ifdef MAIN_ALLOW_DOMAIN_LITERALS
allow_domain_literals
.endif
 
.ifndef DC_minimaldns
.ifndef MAIN_HOST_LOOKUP
MAIN_HOST_LOOKUP = *
.endif
host_lookup = MAIN_HOST_LOOKUP
.endif
 
.ifdef MAIN_HARDCODE_PRIMARY_HOSTNAME
primary_hostname = MAIN_HARDCODE_PRIMARY_HOSTNAME
.endif
 
.ifdef MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS
smtp_accept_max_nonmail_hosts = MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS
.endif
 
.ifndef MAIN_FORCE_SENDER
local_from_check = false
local_sender_retain = true
untrusted_set_sender = *
.endif
 
.ifndef MAIN_IGNORE_BOUNCE_ERRORS_AFTER
MAIN_IGNORE_BOUNCE_ERRORS_AFTER = 2d
.endif
ignore_bounce_errors_after = MAIN_IGNORE_BOUNCE_ERRORS_AFTER
 
.ifndef MAIN_TIMEOUT_FROZEN_AFTER
MAIN_TIMEOUT_FROZEN_AFTER = 7d
.endif
timeout_frozen_after = MAIN_TIMEOUT_FROZEN_AFTER
 
.ifndef MAIN_FREEZE_TELL
MAIN_FREEZE_TELL = postmaster
.endif
freeze_tell = MAIN_FREEZE_TELL
 
.ifndef SPOOLDIR
SPOOLDIR = /var/spool/exim4
.endif
spool_directory = SPOOLDIR
 
.ifndef MAIN_TRUSTED_USERS
MAIN_TRUSTED_USERS = uucp
.endif
trusted_users = MAIN_TRUSTED_USERS
.ifdef MAIN_TRUSTED_GROUPS
trusted_groups = MAIN_TRUSTED_GROUPS
.endif
 
.ifdef MAIN_TLS_ENABLE
.ifndef MAIN_TLS_ADVERTISE_HOSTS
MAIN_TLS_ADVERTISE_HOSTS = *
.endif
tls_advertise_hosts = MAIN_TLS_ADVERTISE_HOSTS
 
.ifdef MAIN_TLS_CERTKEY
tls_certificate = MAIN_TLS_CERTKEY
.else
.ifndef MAIN_TLS_CERTIFICATE
MAIN_TLS_CERTIFICATE = CONFDIR/exim.crt
.endif
tls_certificate = MAIN_TLS_CERTIFICATE
 
.ifndef MAIN_TLS_PRIVATEKEY
MAIN_TLS_PRIVATEKEY = CONFDIR/exim.key
.endif
tls_privatekey = MAIN_TLS_PRIVATEKEY
.endif
 
.ifndef MAIN_TLS_VERIFY_CERTIFICATES
MAIN_TLS_VERIFY_CERTIFICATES = ${if exists{/etc/ssl/certs/ca-certificates.crt}\
                                    {/etc/ssl/certs/ca-certificates.crt}\
				    {/dev/null}}
.endif
tls_verify_certificates = MAIN_TLS_VERIFY_CERTIFICATES
 
.ifdef MAIN_TLS_VERIFY_HOSTS
tls_verify_hosts = MAIN_TLS_VERIFY_HOSTS
.endif
 
.ifndef MAIN_TLS_TRY_VERIFY_HOSTS
MAIN_TLS_TRY_VERIFY_HOSTS = *
.endif
tls_try_verify_hosts = MAIN_TLS_TRY_VERIFY_HOSTS
 
.endif
 
.ifdef MAIN_LOG_SELECTOR
log_selector = MAIN_LOG_SELECTOR
.endif
 
begin acl
 
acl_check_not_smtp:
  accept
	condition=${if IS_SENDER_SECMAIL {yes}{no}}
	control=suppress_local_fixups
 
  accept
 
acl_local_deny_exceptions:
  accept
    hosts = ${if exists{CONFDIR/host_local_deny_exceptions}\
                 {CONFDIR/host_local_deny_exceptions}\
                 {}}
  accept
    senders = ${if exists{CONFDIR/sender_local_deny_exceptions}\
                   {CONFDIR/sender_local_deny_exceptions}\
                   {}}
  accept
    hosts = ${if exists{CONFDIR/local_host_whitelist}\
                 {CONFDIR/local_host_whitelist}\
                 {}}
  accept
    senders = ${if exists{CONFDIR/local_sender_whitelist}\
                   {CONFDIR/local_sender_whitelist}\
                   {}}
 
  .ifdef LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE
  .include LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE
  .endif
 
  .ifdef WHITELIST_LOCAL_DENY_LOCAL_ACL_FILE
  .include WHITELIST_LOCAL_DENY_LOCAL_ACL_FILE
  .endif
 
acl_check_mail:
  .ifdef CHECK_MAIL_HELO_ISSUED
  deny
    message = no HELO given before MAIL command
    condition = ${if def:sender_helo_name {no}{yes}}
  .endif
 
  deny
    message = bad sender
    log_message = bad sender (auth_id=AUTH_SERVER_MAIL mismatches sender=$sender_address)
    condition = IS_SENDER_BAD
  accept
 
acl_check_rcpt:
 
  .ifdef CHECK_RCPT_LOCAL_LOCALPARTS
  deny
    domains = +local_domains
    local_parts = CHECK_RCPT_LOCAL_LOCALPARTS
    message = restricted characters in address
  .endif
 
  .ifdef CHECK_RCPT_REMOTE_LOCALPARTS
  deny
    domains = !+local_domains
    local_parts = CHECK_RCPT_REMOTE_LOCALPARTS
    message = restricted characters in address
  .endif
 
  accept
    .ifndef CHECK_RCPT_POSTMASTER
    local_parts = postmaster
    .else
    local_parts = CHECK_RCPT_POSTMASTER
    .endif
    domains = +local_domains : +relay_to_domains
 
  .ifdef CHECK_RCPT_VERIFY_SENDER
  deny
    message = Sender verification failed
    !acl = acl_local_deny_exceptions
    !verify = sender
  .endif
 
  deny
    !acl = acl_local_deny_exceptions
    senders = ${if exists{CONFDIR/local_sender_callout}\
                         {CONFDIR/local_sender_callout}\
                   {}}
    !verify = sender/callout
 
  require
    verify = recipient
 
  accept
    authenticated = *
    condition = IS_SENDER_REMOTE
 
  require
    message = relay not permitted
    domains = +local_domains : +relay_to_domains
 
  deny
    !acl = acl_local_deny_exceptions
    recipients = ${if exists{CONFDIR/local_rcpt_callout}\
                            {CONFDIR/local_rcpt_callout}\
                      {}}
    !verify = recipient/callout
 
  deny
    message = sender envelope address $sender_address is locally blacklisted here. If you think this is wrong, get in touch with postmaster
    !acl = acl_local_deny_exceptions
    senders = ${if exists{CONFDIR/local_sender_blacklist}\
                   {CONFDIR/local_sender_blacklist}\
                   {}}
 
  deny
    message = sender IP address $sender_host_address is locally blacklisted here. If you think this is wrong, get in touch with postmaster
    !acl = acl_local_deny_exceptions
    hosts = ${if exists{CONFDIR/local_host_blacklist}\
                 {CONFDIR/local_host_blacklist}\
                 {}}
 
  .ifdef CHECK_RCPT_REVERSE_DNS
  warn
    message = X-Host-Lookup-Failed: Reverse DNS lookup failed for $sender_host_address (${if eq{$host_lookup_failed}{1}{failed}{deferred}})
     condition = ${if and{{def:sender_host_address}{!def:sender_host_name}}\
                      {yes}{no}}
  .endif
 
  .ifdef CHECK_RCPT_SPF
  deny
    message = [SPF] $sender_host_address is not allowed to send mail from ${if def:sender_address_domain {$sender_address_domain}{$sender_helo_name}}.  \
              Please see http://www.openspf.org/Why?scope=${if def:sender_address_domain {mfrom}{helo}};identity=${if def:sender_address_domain {$sender_address}{$sender_helo_name}};ip=$sender_host_address
    log_message = SPF check failed.
    !acl = acl_local_deny_exceptions
    condition = ${run{/usr/bin/spfquery --ip \"$sender_host_address\" --mail-from \"$sender_address\" --helo \"$sender_helo_name\"}\
                     {no}{${if eq {$runrc}{1}{yes}{no}}}}
 
  defer
    message = Temporary DNS error while checking SPF record.  Try again later.
    condition = ${if eq {$runrc}{5}{yes}{no}}
 
  warn
    message = Received-SPF: ${if eq {$runrc}{0}{pass}{${if eq {$runrc}{2}{softfail}\
                                 {${if eq {$runrc}{3}{neutral}{${if eq {$runrc}{4}{unknown}{${if eq {$runrc}{6}{none}{error}}}}}}}}}}
    condition = ${if <={$runrc}{6}{yes}{no}}
 
  warn
    log_message = Unexpected error in SPF check.
    condition = ${if >{$runrc}{6}{yes}{no}}
 
  warn
    message = X-SPF-Guess: ${run{/usr/bin/spfquery --ip \"$sender_host_address\" --mail-from \"$sender_address\" \ --helo \"$sender_helo_name\" --guess true}\
                                {pass}{${if eq {$runrc}{2}{softfail}{${if eq {$runrc}{3}{neutral}{${if eq {$runrc}{4}{unknown}\
                                {${if eq {$runrc}{6}{none}{error}}}}}}}}}}
    condition = ${if <={$runrc}{6}{yes}{no}}
 
  defer
    message = Temporary DNS error while checking SPF record.  Try again later.
    condition = ${if eq {$runrc}{5}{yes}{no}}
  .endif
 
  .ifdef CHECK_RCPT_IP_DNSBLS
  warn
    message = X-Warning: $sender_host_address is listed at $dnslist_domain ($dnslist_value: $dnslist_text)
    log_message = $sender_host_address is listed at $dnslist_domain ($dnslist_value: $dnslist_text)
    dnslists = CHECK_RCPT_IP_DNSBLS
  .endif
 
  .ifdef CHECK_RCPT_DOMAIN_DNSBLS
  warn
    message = X-Warning: $sender_address_domain is listed at $dnslist_domain ($dnslist_value: $dnslist_text)
    log_message = $sender_address_domain is listed at $dnslist_domain ($dnslist_value: $dnslist_text)
    !senders = ${if exists{CONFDIR/local_domain_dnsbl_whitelist}\
                    {CONFDIR/local_domain_dnsbl_whitelist}\
                    {}}
    dnslists = CHECK_RCPT_DOMAIN_DNSBLS
  .endif
 
  .ifdef CHECK_RCPT_LOCAL_ACL_FILE
  .include CHECK_RCPT_LOCAL_ACL_FILE
  .endif
 
  accept
    domains = +relay_to_domains
    endpass
    verify = recipient
 
  accept
 
acl_check_data:
 
  .ifdef CHECK_DATA_VERIFY_HEADER_SYNTAX
  deny
    message = Message headers fail syntax check
    !acl = acl_local_deny_exceptions
    !verify = header_syntax
  .endif
 
  .ifdef CHECK_DATA_VERIFY_HEADER_SENDER
  deny
    message = No verifiable sender address in message headers
    !acl = acl_local_deny_exceptions
    !verify = header_sender
  .endif
 
  .ifdef CHECK_DATA_LOCAL_ACL_FILE
  .include CHECK_DATA_LOCAL_ACL_FILE
  .endif
 
  accept
 
begin routers
 
.ifdef MAIN_ALLOW_DOMAIN_LITERALS
domain_literal:
  debug_print = "R: domain_literal for $local_part@$domain"
  driver = ipliteral
  domains = ! +local_domains
  transport = remote_smtp
.endif
 
hubbed_hosts:
  debug_print = "R: hubbed_hosts for $domain"
  driver = manualroute
  domains = "${if exists{CONFDIR/hubbed_hosts}\
                   {partial-lsearch;CONFDIR/hubbed_hosts}\
              fail}"
  same_domain_copy_routing = yes
  route_data = ${lookup{$domain}partial-lsearch{CONFDIR/hubbed_hosts}}
  transport = remote_smtp
 
system_aliases:
  debug_print = "R: system_aliases for $local_part@$domain"
  driver = redirect
  domains = +local_domains
  allow_fail
  allow_defer
  data = ${lookup{$local_part}lsearch{/etc/aliases}}
  .ifdef SYSTEM_ALIASES_USER
  user = SYSTEM_ALIASES_USER
  .endif
  .ifdef SYSTEM_ALIASES_GROUP
  group = SYSTEM_ALIASES_GROUP
  .endif
  .ifdef SYSTEM_ALIASES_FILE_TRANSPORT
  file_transport = SYSTEM_ALIASES_FILE_TRANSPORT
  .endif
  .ifdef SYSTEM_ALIASES_PIPE_TRANSPORT
  pipe_transport = SYSTEM_ALIASES_PIPE_TRANSPORT
  .endif
  .ifdef SYSTEM_ALIASES_DIRECTORY_TRANSPORT
  directory_transport = SYSTEM_ALIASES_DIRECTORY_TRANSPORT
  .endif
 
.ifndef FIRST_USER_ACCOUNT_UID
FIRST_USER_ACCOUNT_UID = 0
.endif
 
.ifndef DEFAULT_SYSTEM_ACCOUNT_ALIAS
DEFAULT_SYSTEM_ACCOUNT_ALIAS = :fail: no mail to system accounts
.endif
 
COND_SYSTEM_USER_AND_REMOTE_SUBMITTER = "\
               ${if and{{! match_ip{$sender_host_address}{:@[]}}\
                        {<{$local_user_uid}{FIRST_USER_ACCOUNT_UID}}}\
                    {1}{0}\
		}"
 
lowuid_aliases:
  debug_print = "R: lowuid_aliases for $local_part@$domain (UID $local_user_uid)"
  check_local_user
  driver = redirect
  allow_fail
  domains = +local_domains
  condition = COND_SYSTEM_USER_AND_REMOTE_SUBMITTER
  data = ${if exists{/etc/exim4/lowuid-aliases}\
              {${lookup{$local_part}lsearch{/etc/exim4/lowuid-aliases}\
              {$value}{DEFAULT_SYSTEM_ACCOUNT_ALIAS}}}{DEFAULT_SYSTEM_ACCOUNT_ALIAS}}
 
local_user_secmail:
  debug_print = "R: local_user_secmail for $local_part@$domain"
  driver = accept
  domains = +local_domains
  local_parts = ! root
  condition = ${if IS_SENDER_SECMAIL {IS_LOCAL_PART_VALID}{no}}
  transport = LOCAL_DELIVERY_SECMAIL
 
local_user:
  debug_print = "R: local_user for $local_part@$domain"
  driver = accept
  domains = +local_domains
  local_parts = ! root
  condition = IS_LOCAL_PART_VALID
  transport = LOCAL_DELIVERY
  cannot_route_message = Unknown user
 
ldap_uid_aliases:
  debug_print = "R: ldap_uid_alias for $local_part@$domain"
  driver = redirect
  data = GET_UID_FOR_RCPT
  check_ancestor
 
ldap_aliases:
  debug_print = "R: ldap_alias for $local_part@$domain"
  driver = redirect
  data = GET_ALIAS_FOR_RCPT
  check_ancestor
 
.ifdef DCconfig_satellite
hub_user:
  debug_print = "R: hub_user for $local_part@$domain"
  driver = redirect
  domains = +local_domains
  data = ${local_part}@DCreadhost
  check_local_user
 
hub_user_smarthost:
  debug_print = "R: hub_user_smarthost for $local_part@$domain"
  driver = manualroute
  domains = DCreadhost
  transport = remote_smtp_smarthost
  route_list = * DCsmarthost byname
  host_find_failed = defer
  same_domain_copy_routing = yes
  check_local_user
.endif
 
smarthost_auto:
   condition = IS_AUTH_REMOTE
   driver = manualroute
   domains = ! +local_domains
   route_data = AUTH_REMOTE_SERVER
   transport = remote_smtp_smarthost_auto
 
mail4root:
  debug_print = "R: mail4root for $local_part@$domain"
  driver = redirect
  domains = +local_domains
  data = /var/mail/mail
  file_transport = address_file
  local_parts = root
  user = mail
  group = mail
 
begin transports
 
.ifdef HIDE_MAILNAME
REMOTE_SMTP_HEADERS_REWRITE=*@+local_domains $1@DCreadhost frs : *@ETC_MAILNAME $1@DCreadhost frs
REMOTE_SMTP_RETURN_PATH=${if match_domain{$sender_address_domain}{+local_domains}{${sender_address_local_part}@DCreadhost}{${if match_domain{$sender_address_domain}{ETC_MAILNAME}{${sender_address_local_part}@DCreadhost}fail}}}
.endif
 
.ifdef REMOTE_SMTP_HELO_FROM_DNS
REMOTE_SMTP_HELO_DATA=${lookup dnsdb {ptr=$sending_ip_address}{$value}{$primary_hostname}}
.endif
 
address_file:
  debug_print = "T: address_file for $local_part@$domain"
  driver = appendfile
  delivery_date_add
  envelope_to_add
  return_path_add
 
address_pipe:
  debug_print = "T: address_pipe for $local_part@$domain"
  driver = pipe
  return_fail_output
 
address_reply:
  debug_print = "T: autoreply for $local_part@$domain"
  driver = autoreply
 
dovecot_delivery:
  debug_print = "T: dovecot_delivery_pipe for $local_part@$domain translates to GET_LOCAL_MAIL"
  driver = pipe
  command = /usr/lib/dovecot/deliver -d "GET_LOCAL_MAIL"
  message_prefix =
  message_suffix =
  delivery_date_add
  envelope_to_add
  return_path_add
  log_output
  user = secmail
  group = secmail
 
dovecot_delivery_secmail:
  debug_print = "T: dovecot_delivery_pipe_secmail for $local_part@$domain translates to GET_LOCAL_MAIL"
  driver = pipe
  command = /usr/lib/dovecot/deliver -d "GET_LOCAL_MAIL"
  message_prefix =
  message_suffix =
  delivery_date_add = false
  envelope_to_add = false
  return_path_add = false
  log_output
  user = secmail
  group = secmail
 
mail_spool:
  debug_print = "T: appendfile for $local_part@$domain"
  driver = appendfile
  file = /var/mail/$local_part
  delivery_date_add
  envelope_to_add
  return_path_add
  group = mail
  mode = 0660
  mode_fail_narrower = false
 
maildir_home:
  debug_print = "T: maildir_home for $local_part@$domain"
  driver = appendfile
  .ifdef MAILDIR_HOME_MAILDIR_LOCATION
  directory = MAILDIR_HOME_MAILDIR_LOCATION
  .else
  directory = $home/Maildir
  .endif
  .ifdef MAILDIR_HOME_CREATE_DIRECTORY
  create_directory
  .endif
  .ifdef MAILDIR_HOME_CREATE_FILE
  create_file = MAILDIR_HOME_CREATE_FILE
  .endif
  delivery_date_add
  envelope_to_add
  return_path_add
  maildir_format
  .ifdef MAILDIR_HOME_DIRECTORY_MODE
  directory_mode = MAILDIR_HOME_DIRECTORY_MODE
  .else
  directory_mode = 0700
  .endif
  .ifdef MAILDIR_HOME_MODE
  mode = MAILDIR_HOME_MODE
  .else
  mode = 0600
  .endif
  mode_fail_narrower = false
 
maildrop_pipe:
  debug_print = "T: maildrop_pipe for $local_part@$domain"
  driver = pipe
  path = "/bin:/usr/bin:/usr/local/bin"
  command = "/usr/bin/maildrop"
  return_path_add
  delivery_date_add
  envelope_to_add
 
procmail_pipe:
  debug_print = "T: procmail_pipe for $local_part@$domain"
  driver = pipe
  path = "/bin:/usr/bin:/usr/local/bin"
  command = "/usr/bin/procmail"
  return_path_add
  delivery_date_add
  envelope_to_add
 
remote_smtp:
  debug_print = "T: remote_smtp for $local_part@$domain"
  driver = smtp
.ifdef REMOTE_SMTP_HOSTS_AVOID_TLS
  hosts_avoid_tls = REMOTE_SMTP_HOSTS_AVOID_TLS
.endif
.ifdef REMOTE_SMTP_HEADERS_REWRITE
  headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE
.endif
.ifdef REMOTE_SMTP_RETURN_PATH
  return_path = REMOTE_SMTP_RETURN_PATH
.endif
.ifdef REMOTE_SMTP_HELO_FROM_DNS
  helo_data=REMOTE_SMTP_HELO_DATA
.endif
 
remote_smtp_smarthost:
  debug_print = "T: remote_smtp_smarthost for $local_part@$domain"
  driver = smtp
  hosts_try_auth = <; ${if exists{CONFDIR/passwd.client} \
        {\
        ${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$host_address}}\
        }\
        {} \
      }
.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
  hosts_avoid_tls = REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
.endif
.ifdef REMOTE_SMTP_HEADERS_REWRITE
  headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE
.endif
.ifdef REMOTE_SMTP_RETURN_PATH
  return_path = REMOTE_SMTP_RETURN_PATH
.endif
.ifdef REMOTE_SMTP_HELO_FROM_DNS
  helo_data=REMOTE_SMTP_HELO_DATA
.endif
 
remote_smtp_smarthost_auto:
  debug_print = "T: remote_smtp_smarthost_auto for $local_part@$domain from user AUTH_SERVER_MAIL"
  driver = smtp
  hosts_require_auth = AUTH_REMOTE_SERVER
 
address_directory:
  debug_print = "T: address_directory for $local_part@$domain"
  driver = appendfile
  delivery_date_add
  envelope_to_add
  return_path_add
  check_string = ""
  escape_string = ""
  maildir_format
 
begin retry
 
*                      *           F,2h,15m; G,16h,1h,1.5; F,4d,6h
 
begin rewrite
 
.ifndef NO_EAA_REWRITE_REWRITE
*@+local_domains "${lookup{${local_part}}lsearch{/etc/email-addresses}\
                   {$value}fail}" Ffrs
*@ETC_MAILNAME "${lookup{${local_part}}lsearch{/etc/email-addresses}\
                   {$value}fail}" Ffrs
.endif
 
begin authenticators
 
plain_ldapauth_server:
  driver = plaintext
  public_name = PLAIN
  .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS
    server_advertise_condition = ${if eq{$tls_cipher}{}{}{*}}
  .endif
  server_condition = AUTH_SERVER_PLAIN_AUTH
  server_set_id = $auth2/$auth3
  server_prompts = :
 
login_ldapauth_server:
  driver = plaintext
  public_name = LOGIN
  server_prompts = Username:: : Password::
  .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS
    server_advertise_condition = ${if eq{$tls_cipher}{}{}{*}}
  .endif
  server_condition = AUTH_SERVER_LOGIN_AUTH
  server_set_id = $auth1/$auth2
 
cram_md5_client:
     driver = cram_md5
     public_name = CRAM-MD5
     client_name = AUTH_REMOTE_LOGIN
     client_secret = AUTH_REMOTE_PASSWORD
 
plain_client:
      driver = plaintext
      public_name = PLAIN
      client_send = <|^AUTH_REMOTE_LOGIN^AUTH_REMOTE_PASSWORD
 
login_client:
      driver = plaintext
      public_name = LOGIN
      client_send = <| | AUTH_REMOTE_LOGIN | AUTH_REMOTE_PASSWORD

Die Konfigurationsdatei ist auf den ersten Blick sehr umfangreich, allerdings gibt es eine exzellente Dokumentation von Exim. Dort sind insbesondere die Abschnitte zu Lookups (wegen LDAP) und String Expansions interessant. Allgemeine Konfigurationshinweise für Exim unter Debian/Ubuntu hat Justin Koivisto zusammengestellt. Den Beitrag von Wolfgang Hennerbichler zur Einrichtung der TLS-Verschlüsselung der SMTP-Verbindung zusammen mit der Dokumentation von exim4-config zu diesem Thema empfand ich ebenfalls hilfreich wie auch den Forumsthread, der die Verwendung von $authenticated_id und die Anpassung des received_header_text dokumentiert. Die Mailingliste von exim enthält einen sehr guten Beitrag, mit ausführlicher Beispielkonfiguration, wie E-Mails via Authentifizierung über externe Mailserver verschickt werden können. Wie man mehrere Smarthosts mit Exim verwendt, beschreibtauch Thorsten Gunkel.
Nun testen wir die Exim-Konfiguration, ob auch alles wie gewünscht funktioniert.

exim -bt paul@myserver

sollte folgendes ausgeben

R: system_aliases for paul@myserver
R: local_user_secmail for paul@myserver
R: local_user for paul@myserver
paul@myserver
  router = local_user, transport = dovecot_delivery

analog sollte ein

exim -bt paulpanzer@gmx.de

zu folgendem Resultat führen

R: ldap_uid_alias for paulpanzer@gmx.de
R: system_aliases for paul@myserver
R: local_user_secmail for paul@myserver
R: local_user for paul@myserver
paul@myserver
    <-- paulpanzer@gmx.de
  router = local_user, transport = dovecot_delivery

Im nächsten Schritt können wir auch eine SMTP-Session testen. Dazu erzeugen wir mit dem Befehl

echo -ne '\0paul@paulpanzer@gmx.de\0test' | base64

eine Zeichenfolge zur Authentifizierung, wobei paul für den Benutzer steht, paulpanzer@gmx.de für die externe Mailaddresse und test für das Passwort von paul (es besteht keine Verbindung zu den Passwörtern von paulpanzer@gmx.de). Ich erhalte hier AHBhdWxAcGF1bHBhbnplckBnbXguZGUAdGVzdA==. Wir starten mit

openssl s_client -starttls smtp -crlf -connect myserver:25

eine verschlüsselte SMTP-Session und verschicken eine Testmail an paul@myserver, indem wir folgende Befehle eingeben (alle Zeilen, die nicht mit einer Zahl beginnen)

250 HELP
ehlo client
250-myserver Hello myserver [127.0.1.1]
250-SIZE 52428800
250-PIPELINING
250-AUTH PLAIN LOGIN
250 HELP
AUTH PLAIN AHBhdWxAcGF1bHBhbnplckBnbXguZGUAdGVzdA==
235 Authentication succeeded
mail from: paulpanzer@gmx.de
250 OK
rcpt to: paul@myserver
250 Accepted
data
354 Enter message, ending with "." on a line by itself
From: Paul Panzer <paulpanzer@gmx.de>
To: Paul <paul@myserver>
Subject: Testing SMTP
This is a test body.
.
250 OK id=1Ll9N3-0001hf-6J
quit
221 myserver closing connection
closed

Wer im Detail nachlesen möchte, was die einzelnen Befehle bewirken, dem sei die Anleitung zum Testen von SMTP per Telnet von John M. Simpson empfohlen. Als Resultat des Tests sollten wir im Verzeichnis /home/paul/mail/paul/maildir/INBOX/new/ eine Datei haben, die in etwa folgenden Inhalt hat

Return-path: <paulpanzer@gmx.de>
Envelope-to: paul@myserver
Delivery-date: Sat, 21 Mar 2009 23:18:09 +0100
Received: from myserver ([127.0.1.1] helo=la)
	by myserver with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32)
	(Exim 4.69)
	(envelope-from <paulpanzer@gmx.de>)
	id 1Ll9Vy-0001jC-N8
	for paul@myserver; Sat, 21 Mar 2009 23:18:09 +0100
From: Paul Panzer <paulpanzer@gmx.de>
To: Paul <paul@myserver>
Subject: Testing SMTP 
 
This is a test body.

Fehlerquellen in der Konfiguration finden

Falls exim nicht das gewünschte Resultat liefert oder bei der Auslieferung an eine bestimmte Addresse ein Fehler auftritt, hilft es, Exim im Debug-Modus zu starten. Beispielsweise kann man eine derartige Batch-SMTP-Session über folgenden Befehl starten

sudo exim4 -C /var/lib/exim4/config.autogenerated -v -d+all -bs

Um zu testen, wie Exim intern die Mailaddressen routet, können wir mit

sudo exim -v -d-all+lookup -bt paulpanzer@gmx.de

alle zugehörigen lookups von exim verfolgen. Durch das “-all+lookup” werden nur Informationen ausgeben, die mit lookups zu tun haben.

Umgang mit Exim

Exim besitzt eine Vielzahl an Kommandozeilenoptionen. Sich in der man-page zurechtzufinden ist daher nicht einfach, allerdings habe ich eine sehr gute Zusammenstellung einzelner Exim-Befehle gefunden. Ein Befehl fehlt dabei jedoch. Mit

sudo exim -qff

kann man das erneute Auslierfern von “frozen messages”, also als unzustellbar marktierten Mails, erzwingen.

Der vierte Teil der Konfiguration beschäftigt sich mit der Einrichtung von getmail zum Abruf externer Mails via POP3/IMAP.

Nachdem die Grundvorraussetzungen im ersten Teil geschaffen wurden, wenden wir uns in diesem Teil der Anpassung, Installation und Konfiguration von dovecot zu. Obwohl fast alles im Blog detailliert beschrieben ist, empfehle ich, die Konfigurationsdateien für das Mailsystem herunterzuladen.

Installation von Dovecot

Nach einem

sudo apt-get install dovecot-common dovecot-imapd dovecot-pop3d

sind die notwendigen Dovecot-Pakete installiert.

Anpassung der Installation

Dovecot verwendet zur Zustellung von Mails den Dovecot Local Delivery Agent (LDA). Damit dieser die Mails in allen Verzeichnissen der Benutzer ablegen kann, benötigt er root-Rechte, die wir über das Setuid-Bit vergeben. Zum Mailversand setzen wir jedoch exim als  Message Transfer Agent (MTA) ein, so dass Mails nie direkt via Dovecot-LDA, sondern immer indirekt über exim zugestellt werden. Da deshalb nur exim den Dovecot LDA aufrufen muss, wäre es sicherheitstechnisch bedenklich, könnte jeder Benutzer den Dovecot LDA mit Setuid-Bit aufrufen (eine Sicherheitslücke im Dovecot LDA würde dann sofort das gesamte System kompromittieren). Deshalb richten wir einen speziellen Benutzer namens secmail ein, der diese Rechte besitzt und dessen sich exim dann bedienen soll.

sudo adduser --system --group --disabled-login --shell /bin/false --home /home/secmail secmail

Anschließend müssen wir für unsere Konfiguration das setuid-Bit für Dovecots LDA setzen,  damit dieser zur Zustellung jeweils auf die jeweilige Benutzer-ID wechseln kann. Durch den Aufruf von dpkg-statoverride werden die Berechtigungen auch bei Paketaktualisierungen beibehalten, obwohl der Einsatz auch einige Nachteile mit sich bringt.

sudo dpkg-statoverride --update --add root secmail 4710 /usr/lib/dovecot/deliver

Konfiguration von dovecot

Zunächst kopieren wir die im ersten Teil der Anleitung erzeugten Dateien des Client-Zertifikats für dovecot in das Konfigurationsverzeichnis und passen die Berechtigungen an.

sudo cp /etc/ssl/easy-rsa/keys/dovecot-client.key /etc/ssl/easy-rsa/keys/dovecot-client.crt /etc/dovecot
sudo chown root.dovecot /etc/dovecot/dovecot-client.{key,crt}
sudo chmod 640 /etc/dovecot/dovecot-client.key

Die Konfiguration von dovecot ist im Vergleich zu anderen Mailservern wie qmail, courier-imap oder cyrus einfach und gut dokumentiert. Meine um Kommentare und Leerzeilen verkürzte Version sieht so aus:

protocols = imap imaps managesieve
log_path = /var/log/dovecot.log
log_timestamp = "%Y-%m-%d %H:%M:%S "
ssl_cert_file = /etc/ssl/certs/myserver.crt
ssl_key_file = /etc/ssl/private/myserver.key
ssl_ca_file = /etc/ssl/certs/ca.crt
ssl_verify_client_cert = yes
login_user = dovecot
login_greeting = Ready.
mail_privileged_group =
protocol imap {
  login_executable = /usr/lib/dovecot/imap-login
  mail_executable = /usr/lib/dovecot/imap
}
protocol pop3 {
  pop3_uidl_format = %08Xu%08Xv
}
protocol managesieve {
  login_executable = /usr/lib/dovecot/managesieve-login
  mail_executable = /usr/lib/dovecot/managesieve
  sieve=~/.dovecot.sieve
  sieve_storage=~/sieve
}
protocol lda {
  postmaster_address = paul@myserver
  mail_plugins = cmusieve
  mail_plugin_dir = /usr/lib/dovecot/modules/lda
  log_path = /var/log/dovecot-deliver.log
  auth_socket_path = /var/run/dovecot/auth-master
}
auth_executable = /usr/lib/dovecot/dovecot-auth
auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@
auth default {
  mechanisms = plain
  passdb ldap {
    args = /etc/dovecot/dovecot-ldap-passdb.conf
  }
  userdb ldap {
    args = /etc/dovecot/dovecot-ldap-userdb.conf
  }
  user = root
  socket listen {
    master {
      path = /var/run/dovecot/auth-master
      mode = 0660
      group = secmail
    }
  }
}
dict {
}
plugin {
}

Eine entsprechende Datei kann man einfach durch ein

cat /etc/dovecot/dovecot.conf | egrep -v '(^\t* *#|^\t* *$)'

erzeugen. Hier ist der Inhalt der referenzierten Dateien dovecot-ldap-passdb.conf und dovecot-ldap-userdb.conf.

dovecot-ldap-passdb.conf:

hosts = myserver
tls = yes
tls_ca_cert_file = /etc/ssl/certs/ca.crt
tls_cert_file = /etc/dovecot/dovecot-client.crt
tls_key_file = /etc/dovecot/dovecot-client.key
tls_require_cert = demand
auth_bind = yes
auth_bind_userdn = uid=%Ln,ou=users,o=effinger
ldap_version = 3
base = uid=%Ln,ou=users,o=effinger

dovecot-ldap-userdb.conf:

hosts = myserver
tls = yes
tls_ca_cert_file = /etc/ssl/certs/ca.crt
tls_cert_file = /etc/dovecot/dovecot-client.crt
tls_key_file = /etc/dovecot/dovecot-client.key
tls_require_cert = demand
ldap_version = 3
base = uid=%Ln,ou=users,o=effinger
scope = subtree
user_attrs = dcMailMessageStore=home=%$/%Ld,uidNumber=uid,gidNumber=gid,=mail=maildir:~/maildir:INBOX=~/maildir/INBOX
user_filter = (|(mail=%d)(&(dcSubMailAddress=%d)(dcAccountStatus=active)))

Nach einem

sudo /etc/init.d/dovecot restart

sollte man den Login testen. Dazu kann man die Anleitung zum Testen von IMAP mit telnet von A. P. Lawrence verwenden. Das sieht dann beispielsweise so aus:

$ telnet localhost 143
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
* OK Ready.
as1 login paul@paul mypassword
as1 OK Logged in.
as2 logout
* BYE Logging out
as2 OK Logout completed.
Connection closed by foreign host.

Wichtig ist dabei, beide E-Mail-Addressen zu überprüfen (lokal und extern). Im Beispiel hier muss man also die logins paul@paul sowie paul@paulpanzer@gmx.de testen.

Zum Schluss möchte ich noch auf einige Seiten hinweisen, die bei der Konfiguration von dovecot hilfreich für mich waren

In Teil 3 befassen wir uns mit der Einrichtung von Exim als MTA (Message Transfer Agent).

In diesem Blog-Eintrag geht es um die Einrichtung eines Mailservers, der dovecot, Exim, OpenLDAP und getmail verwendet. Folgendes wird mit der Konfiguration erreicht:

  • Mails können von  Benutzern, die in OpenLDAP eingetragen sind per IMAP abgerufen und per SMTP versendet werden (auch mit TLS-Verschlüsselung).
  • Benutzer können Mails von externen POP3/IMAP-Accounts direkt in ihr IMAP Postfach legen lassen
  • Benutzer können Mails mit einer externen Absenderaddresse via lokalem Mailserver verschicken, der sie über den entsprechenden externen Mailserver verschickt

Am Beispiel sollte es klarer werden. Paul ist mit der Userid paul in OpenLDAP eingetragen und hat auf dem lokalen Rechner mit der Domain myserver die Mailaddresse paul@myserver. Paul kann per IMAP Mails abrufen (Login: paul@paul Server: myserver) und ebenfalls per SMTP Mails verschicken. Außerdem hat Paul eine weitere E-Mailadresse aus der Zeit als er sich noch keine eigene Domain leisten konnte. Diese lautet paulpanzer@gmx.de. Paul möchte seine E-Mails zukünftig auf seinem lokalen Server speichern und nicht mehr bei GMX. Er bzw. der Administrator trägt dazu die POP3-Zugangsdaten von GMX in OpenLDAP ein. Danach werden alle E-Mails automatisch heruntergeladen und Paul kann über den Login paul@paulpanzer@gmx.de auf dem Server myserver seine GMX-Mails per IMAP abrufen. Trägt Paul bzw. der Administrator auch die SMTP-Daten für die E-Mailaddresse paulpanzer@gmx.de in OpenLDAP ein, so kann Paul außerdem Mails indirekt via GMX- Mailserver verschicken, indem er als SMTP-Login paul@paulpanzer@gmx.de auf seinem lokalen Server wählt. So sieht das fertige Schema mit der verwendeten Software aus:

General Software Setup - Dovecot, Exim & Co.Der Zugriff per Webinterface auf Mails und der Abruf der Mails vom externen Server bzw. das Empfangen von Mails ist hier dargestellt:

General software setup - Getmail, Roundcube & Co.

Einrichtung

Bevor man überhaupt daran denkt, ein E-Mail-Serversystem aufzusetzen, müssen zwei Bedingungen erfüllt sein. Die erste betrifft eine genaue Systemzeit, der zweite den Hostnamen. Obwohl fast alles im Blog detailliert beschrieben ist, empfehle ich, die Konfigurationsdateien für das Mailsystem herunterzuladen.

Genaue Systemzeit mit Ubuntu

Leider installiert Ubuntu standardmäßig das Paket ntpdate. Durch dieses Paket wird jedes Mal, wenn man mit dem Internet verbunden ist (genauer gesagt beim ifup), die Zeit mit einem NTP-Server im Internet abgeglichen und ggfs. die Systemzeit entsprechend geändert. An sich ja keine schlechte Sache, aber dovecot reagiert auf Zeitänderungen sehr verstimmt und quittiert den Dienst. Deshalb setze ich stets ntpd ein. Dies ist ein NTP-Server, der systematisch die Differenz zwischen Systemzeitgeber und dem Internetserver beobachtet und so systematisches zu schell bzw. zu langsam gehen des Systemzeitgebers korrigieren kann. Man erhält damit eine genauere Systemzeit und damit auch ein stabiles dovecot. Deshalb installiere ich ntpd und entferne ntpdate:

sudo apt-get autoremove --purge ntpdate && sudo apt-get install ntp

Um für den Ausfall des Ubuntu NTP-Servers gewappnet zu sein, habe ich die Server-Einträge in /etc/ntp.conf noch um Server aus dem öffentlichen NTP-Pool ergänzt:

# You do need to talk to an NTP server or two (or three).
server 0.pool.ntp.org
server 1.pool.ntp.org
server 2.pool.ntp.org
server ntp.ubuntu.com

Nach einem Speichern der Konfigurationsdatei und einem Neustart des NTP-Servers mit

sudo /etc/init.d/ntp restart

haben wir den ersten Punkt erledigt. Christoph Langner beschreibt die Installation von ntpd noch etwas ausführlicher.

Hostname für den Mailserver

Der zweite wichtige Punkt ist der Hostname. Der fully qualified domain name (FQDN) des Rechners muss bekannt sein. Nachprüfen lässt sich das über

hostname --fqdn

Bekommt man keine Ausgabe wie host.domain.de, dann muss man die /etc/hosts anpassen, so dass die Reihenfolge der Servernamen stimmt:

127.0.0.1	myserver	localhost

Bitte unbedingt beachten, dass das beispielhaft aufgeführte myserver kein FQDN ist. Ein FQDN besteht immer auch aus einer Top-Level-Domain.

Erzeugen von SSL-Zertifikaten

Damit wir mit imaps, dem durch Verschlüsselung abgesicherten IMAP, auf unseren Server zugreifen können, und auch den SMTP- und LDAP-Zugriff verschlüsseln können, benötigen wir entsprechende SSL-Zertifikate. Am einfachsten lassen sich solche Zertifikate mit easy-rsa aus dem Paktet openvpn erzeugen. Übrigens gibt es gibt es dazu gute Anleitungen von linux.neoberserker.de oder im OpenVPN-Wiki. Das Paket openvpn müssen wir jedoch nicht installieren. Es genügt, wenn wir mit

mkdir openvpn && cd openvpn && apt-get source openvpn

den Quelltext herunterladen. Wir führen alle folgenden Befehle zur Zertifikatserstellung als root aus (wichtig, damit später nicht jeder Benutzer die geheimen Dateien lesen kann). Zunächst kopieren wir das entsprechende Unterverzeichnis in /etc/ssl und löschen anschließend die nicht mehr benötigten Verzeichnisse mit

sudo -s
cp -R openvpn-2.1~rc11/easy-rsa/2.0 /etc/ssl/easy-rsa
cd .. && rm -rf openvpn
cd /etc/ssl/easy-rsa

Nun editieren wir die Datei vars und passen Sie entsprechend an. Bei mir habe ich folgende Zeilen am Ende angepasst:

export KEY_COUNTRY="DE"
export KEY_PROVINCE="RP"
export KEY_CITY="Ludwigshafen"
export KEY_ORG="Effinger"
export KEY_EMAIL="nospam@effinger.org"

Anschließend führen wir folgende Schritte durch, um die CA-Dateien zur Ausstellung eigener Zertifikate zu erzeugen. Beim Schritt ./build-ca kann man alle Punkte mit Enter bestätigen bis auf common name. Hier sollte man einen einfachen Namen, z.B. MyCA, angeben (am Besten nur Buchstaben und Zahlen verwenden – keine Leerzeichen oder sonstige Sonderzeichen).

. ./vars
./clean-all
./build-ca
./build-dh

Im nächsten Schritt erstellen wir für unseren Mailserver ein Server-Schlüsselpaar mit dem Befehl

./build-key-server myserver

myserver sollte dabei durch den DNS-Eintrag des Servers ersetzt werden (Thunderbird fragt ansonsten jedes Mal sicherheitshalber nach, ob das Zertifikat akzeptiert werden soll, weil der Zertifikatsname nicht mit dem Hostnamen übereinstimmt). Auch hier bestätigen wir wieder alles mit Enter bis auf den Punkt Sign the certificate? Hier antworten wir mit ja (y) und bestätigen die darauf erfolgende Rückfrage ebenfalls mit y. Ein Client-Zertifikat kann man mit

./build-key myclient

analog erzeugen. Dieses benötigt man jedoch nur, wenn man ausschließlich Clients mit gültigem Zertifikat auf den Mailserver zugreifen lassen möchte. Bei dovecot ist das der Fall, wenn der Parameter ssl_require_client_cert=yes gesetzt ist. Da dovecot sich mit dem LDAP-Server verbindet, können wir dazu ebenfalls ein Client-Zertifikat verwenden. Wir erzeugen es mit

./build-key dovecot-client

Im Unterverzeichnis keys sind nun einige Dateien, die wir noch in das richtige Verzeichnis kopieren müssen. Wichtig ist, dass niemand unbefugt auf die geheimzuhaltenden Dateien zugreifen kann, die allesamt mit der Erweiterung .key enden. Am Besten ist es, vor dem Kopieren die Berechtigungen zu prüfen. Die öffentlichen Zertifikate werden in das Verzeichnis /etc/ssl/certs und die geheimen Zertifikate in /etc/ssl/private kopiert mit

cp /etc/ssl/easy-rsa/keys/myserver.crt /etc/ssl/easy-rsa/keys/ca.crt /etc/ssl/certs/
cp /etc/ssl/easy-rsa/keys/myserver.key /etc/ssl/private/
chown root.ssl-cert /etc/ssl/private/myserver.key
chmod 640 /etc/ssl/private/myserver.key

Die letzten beiden Zeilen dienen dazu, Exim, Dovecot und LDAP den Zugriff auf die geheime Key-Datei zu gewähren. Die entsprechendenBenutzer müssen dazu in der Gruppe ssl-cert sein (Anleitung erfolgt bei der Installation des jeweiligen Programms). Falls man später doch noch OpenVPN nutzen möchte, kann man den Diffie-Hellman Parameter ebenfalls kopieren

cp /etc/ssl/easy-rsa/keys/dh1024.pem /etc/ssl/

Die Client-Zertifikate muss man nun natürlich dem E-Mail-Programm bekannt machen. Bei Thunderbird fügt man über Extras>Einstellungen>Erweitert>Zertifikate>Zertifikate>Zertifizierungsstellen>Importieren die Datei ca.crt hinzu, wechselt anschließend auf den Reiter Ihre Zertifikate, um dort dann die Dateien myclient.p12 importieren. Letzere Datei erzeugt man durch ein

openssl pkcs12 -export -name "myclient" -in myclient.crt -inkey myclient.key -out myclient.p12

OpenLDAP installieren

Als nächstes installieren wir OpenLDAP und die ldap-utils nach meinem OpenLDAP 1×1. Hier die Schritte in Kurzform (falls Schritte unklar sind – im OpenLDAP 1×1 ist alles sehr ausführlich erklärt):

  1. Alle folgenden Befehle als root ausführen mit einem
    sudo bash

    oder

    sudo -s
  2. apt-get install slapd ldap-utils

    Unbedingt das Administrator-Passwort bei der Einrichtung merken.

  3. /etc/init.d/slapd stop
  4. Die automatisch bei der Einrichtung erzeugte Datenbank löschen (Vorsicht, wenn OpenLDAP bereits im Einsatz ist! Dieser Befehl kann die aktive Datenbank löschen)
  5. rm /etc/ldap/slapd.d/cn\=config/olcDatabase\=\{1\}hdb.ldif && rm /var/lib/ldap/*
  6. Die folgende Datei database.ldif passen:
    # Database settings
    dn: olcDatabase=hdb,cn=config
    objectClass: olcDatabaseConfig
    objectClass: olcHdbConfig
    olcDatabase: hdb
    # The base of your directory
    olcSuffix: o=effinger
    # rootdn directive for specifying a superuser on the database. This is needed
    # for syncrepl.
    olcRootDN: cn=admin,o=effinger
    # Superuser Password for the database
    # {SSHA}pEvotN6PmSjx0JV/mZl5BWeSVOKR1Ejt equals "test"
    # CHANGE this for your installation!!!
    olcRootPW: {SSHA}pEvotN6PmSjx0JV/mZl5BWeSVOKR1Ejt
    # Where the database file are physically stored
    olcDbDirectory: /var/lib/ldap
    # The dbconfig settings are used to generate a DB_CONFIG file the first
    # time slapd starts.  They do NOT override existing an existing DB_CONFIG
    # file.  You should therefore change these settings in DB_CONFIG directly
    # or remove DB_CONFIG and restart slapd for changes to take effect.
    # For the Debian package we use 2MB as default but be sure to update this
    # value if you have plenty of RAM
     
    olcDbConfig: set_cachesize 0 2097152 0
    # Sven Hartge reported that he had to set this value incredibly high
    # to get slapd running at all. See http://bugs.debian.org/303057 for more
    # information.
    # Number of objects that can be locked at the same time.
    olcDbConfig: set_lk_max_objects 1500
    # Number of locks (both requested and granted)
    olcDbConfig: set_lk_max_locks 1500
    # Number of lockers
    olcDbConfig: set_lk_max_lockers 1500
    # Indexing options
    olcDbIndex: objectClass eq
    # Save the time that the entry gets modified
    olcLastMod: TRUE
    # Checkpoint the BerkeleyDB database periodically in case of system
    # failure and to speed slapd shutdown.
    olcDbCheckpoint: 512 30
    # The userPassword by default can be changed
    # by the entry owning it if they are authenticated.
    # Others should not be able to see it, except the
    # admin entry below
    # These access lines apply to database #1 only
    olcAccess: to attrs=userPassword,shadowLastChange by dn="cn=admin,o=effinger" write by anonymous auth by self write by * none
    # Ensure read access to the base for things like
    # supportedSASLMechanisms.  Without this you may
    # have problems with SASL not knowing what
    # mechanisms are available and the like.
    # Note that this is covered by the 'access to *'
    # ACL below too but if you change that as people
    # are wont to do you'll still need this if you
    # want SASL (and possible other things) to work
    # happily.
    olcAccess: to dn.base="" by * read
    # The admin dn has full write access, everyone else
    # can read everything.
    olcAccess: to * by dn="cn=admin,o=effinger" write by * read
    # For Netscape Roaming support, each user gets a roaming
    # profile for which they have write access to
    #olcAccess: to dn=".*,ou=Roaming,o=morsnet" by dn="cn=admin,o=effinger" write by dnattr=owner write

    Bitte unbedingt das Passwort (olcRootPW) ändern.
    Falls gewünscht auch die RootDN (hier “o=effinger”) anpassen. Dadurch müssen einige der folgenden Befehle/Dateien angepasst werden.

  7. Eine neue Datenbank mit Hilfe der database.ldif erzeugen (Administratorpasswort aus Schritt 2 wird benötigt)
    /etc/init.d/slapd start
    ldapadd -f database.ldif -x -D "cn=admin,cn=config" -W

Jetzt haben wir eine saubere Datenbank mit der RootDN “o=effinger” und dem entsprechenden Administrator “cn=admin,o=effinger”, die wir nun weiter konfigurieren können. Bevor wir damit loslegen, muss man sich jedoch Gedanken machen, wie die Daten in OpenLDAP strukturiert werden sollen. Ich habe mich für folgendes Setup entschieden:

  • Benutzer werden im Kontext ou=users,o=effinger gespeichert also z.B. uid=paul,ou=users,o=effinger. Hier wird auch die lokale Mail-Addresse paul abgelegt. Die Domainendung (@myserver) wird hier weggelassen, da teilweise die Domain nicht angegeben ist bzw. oft anders addressiert ist, z.B. paul@localhost
  • Externe Mail-Accounts des Benutzers werden jeweils unter dem zugehörigen Benutzereintrag gespeichert, also z.B. dcSubMailAddress=paulpanzer@gmx.de,uid=paul,ou=users,o=effinger, zusammen mit den Angaben zu Logins für SMTP und den Mailabruf, z.B. mit POP3.
  • Da dovecot jedoch nicht ganz flexibel mit LDAP umgehen kann, müssen wir Parameter wie uid, Angaben zum Speicherort der Mails, die unter uid=paul,ou=users,o=effinger verfügbar sind auch unter dcSubMailAddress=paulpanzer@gmx.de,uid=paul,ou=users,o=effinger verfügbar machen. Das geht mit dem DynList/DynGroup Overlay von OpenLDAP. Eine Alternative wäre das slapo-rwm Overlay gewesen, das allerdings in der aktuellen Ubuntu-Version noch einen Bug aufweist und deshalb außen vor bleibt.

Nach den konzeptionellen Überlegungen machen wir uns nun an die Arbeit. Wir konfigurieren das DynList-Overlay, wobei mir eine Anleitung für Gentoo und die kurze Einführung für Ubuntu sehr geholfen haben und ergänzen OpenLDAP mit einem von mir erstellten Schema (dovecot.schema.ldif).

  1. Folgenden Inhalt unter dem Namen dyngroup.schema.ldif abspeichern:
    dn: cn=dyngroup,cn=schema,cn=config
    objectClass: olcSchemaConfig
    cn: dyngroup
    olcObjectIdentifier: NetscapeRoot 2.16.840.1.113730
    olcObjectIdentifier: NetscapeLDAP NetscapeRoot:3
    olcObjectIdentifier: NetscapeLDAPattributeType NetscapeLDAP:1
    olcObjectIdentifier: NetscapeLDAPobjectClass NetscapeLDAP:2
    olcObjectIdentifier: OpenLDAPExp11 1.3.6.1.4.1.4203.666.11
    olcObjectIdentifier: DynGroupBase OpenLDAPExp11:8
    olcObjectIdentifier: DynGroupAttr DynGroupBase:1
    olcObjectIdentifier: DynGroupOC DynGroupBase:2
    olcAttributeTypes: ( NetscapeLDAPattributeType:198 NAME 'memberURL' DESC 'Identifies an URL associated with each member of a group. Any type of labeled URL can be used.' SUP labeledURI )
    olcAttributeTypes: ( DynGroupAttr:1 NAME 'dgIdentity' DESC 'Identity to use when processing the memberURL' SUP distinguishedName SINGLE-VALUE )
    olcAttributeTypes: ( DynGroupAttr:2 NAME 'dgAuthz' DESC 'Optional authorization rules that determine who is allowed to assume the dgIdentity' EQUALITY authzMatch SYNTAX 1.3.6.1.4.1.4203.666.2.7 X-ORDERED 'VALUES' )
    olcObjectClasses: ( NetscapeLDAPobjectClass:33 NAME 'groupOfURLs' SUP top STRUCTURAL MUST cn MAY ( memberURL $ businessCategory $ description $ o $ ou $ owner $ seeAlso ) )
    olcObjectClasses: ( DynGroupOC:1 NAME 'dgIdentityAux' SUP top AUXILIARY MAY ( dgIdentity $ dgAuthz ) )

    und mit einem

    ldapadd -D "cn=admin,cn=config" -x -W -f dyngroup.schema.ldif

    hinzufügen (Administrator-Passwort wird benötigt).

  2. Als nächstes folgenden Inhalt unter dem Namen dovecot.schema.ldif abspeichern
    dn: cn=dovecot,cn=schema,cn=config
    objectClass: olcSchemaConfig
    cn: dovecot
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.1.1.1 NAME 'dcMailMessageStore' DESC 'Path to the maildir/mbox on the mail system' EQUALITY caseExactIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.1.1.2 NAME 'dcMailAlias' DESC 'Secondary (alias) mailaddresses for a user' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.1 NAME 'dcSubMailAddress' DESC 'A users secondary e-mail address for which mail from on another Mailserver has to be fetched' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.2 NAME 'dcAccountStatus' DESC 'The status of a user account: active, noaccess, disabled, deleted' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.3 NAME 'dcSMTPServer' DESC 'Outgoing mails should be delivered to this Mailserver via SMTP.' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.4 NAME 'dcSMTPLogin' DESC 'Login credential to send Mail with the SMTP server' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.5 NAME 'dcSMTPPassword' DESC 'A separate text that stores the SMTP account password in clear text' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.6 NAME 'dcRetrieveType' DESC 'Tells getmail what mail account to retrieve mail from, and how to access that account, e.g. SimplePOP3Retriever and BrokenUIDLPOP3SSLRetriever' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.7 NAME 'dcRetrieveServer' DESC 'Incoming mails have to be downloaded from this server' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.8 NAME 'dcRetrieveLogin' DESC 'Login credential to receive Mail from the server' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.9 NAME 'dcRetrievePassword' DESC 'Password for mail retrieval in clear text' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.10 NAME 'dcMailQuota' DESC 'The size of space the user can have until further messages get bounced.' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.11 NAME 'dcMailSizeMax' DESC 'The maximum size of a single messages the user accepts.' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.2.1.12 NAME 'dcMailAlternateAddress' DESC 'Secondary (alias) mailaddresses for an external Mail Account' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
    olcAttributeTypes: ( 1.3.6.1.4.1.32589.1.3.1.1 NAME 'dcPosixOwnerURL' DESC 'Identifies an URL associated with the posixOwner of the entry. Any type of labeled URL can be used.' SUP labeledURI )
    olcObjectClasses: ( 1.3.6.1.4.1.32589.1.1.2.1 NAME 'dcMailUser' DESC 'Dovecot-LDAP User' SUP top AUXILIARY MUST dcMailMessageStore MAY dcMailAlias )
    olcObjectClasses: ( 1.3.6.1.4.1.32589.1.2.2.1 NAME 'dcExternalMailAccount' DESC 'Dovecot-LDAP external mail account' SUP top STRUCTURAL MUST ( dcSubMailAddress $ dcAccountStatus ) MAY ( dcSMTPServer $ dcSMTPLogin $ dcSMTPPassword $ dcRetrieveType $ dcRetrieveServer $ dcRetrieveLogin $ dcRetrievePassword $ dcMailQuota $ dcMailSizeMax $ dcMailAlternateAddress ) )
    olcObjectClasses: ( 1.3.6.1.4.1.32589.1.3.2.1 NAME 'dcPosixSubAccount' DESC 'LDAP-URL for retrieving the respective posixAccount of an entry' SUP top AUXILIARY MAY dcPosixOwnerURL )

    und ebenfalls in die Konfiguration übernehmen mit

    ldapadd -D "cn=admin,cn=config" -x -W -f dovecot.schema.ldif
  3. Jetzt aktivieren wir das DynList-Modul und speichern dazu Folgendes als dynlist_moduleLoad.ldif
    dn: cn=module{0},cn=config
    changetype: modify
    add: olcModuleLoad
    olcModuleLoad: dynlist.so

    um es anschließend zur OpenLDAP-Konfiguration hinzuzufügen mit einem

    ldapmodify -D "cn=admin,cn=config" -x -W -f dynlist_moduleLoad.ldif
  4. Dem Dynlist-Overlay müssen wir außerdem mitteilen, dass das Attribut dcPosixOwnerURL jeweils auf den zugehörigen Benutzer verweist. Das machen wir, indem wir den folgenden Inhalt als dynlist_activateOnSuffix.ldif abspeichern
    dn: olcOverlay=dynlist,olcDatabase={1}hdb,cn=config
    objectClass: olcOverlayConfig
    objectClass: olcDynamicList
    olcDLattrSet: dcPosixSubAccount dcPosixOwnerURL
    olcOverlay: dynlist

    und dann

    ldapadd -D "cn=admin,cn=config" -x -W -f dynlist_activateOnSuffix.ldif

    ausführen.

  5. Nun müssen wir einen Grundeintrag in LDAP vornehmen, bevor wir starten können. Außerdem benötigen wir einen Benutzer secmail, um Mails von externen Servern in festen Intervallen abzurufen und in das jeweilige lokale IMAP-Postfach abzulegen. Daher legen wir mit der folgenden LDIF-Datei database-content.ldif zunächst den Grundeintrag und den Benutzer secmail an (Passwort wieder unbedingt mit slappasswd anpassen) an
    # effinger
    dn: o=effinger
    objectclass: organization
    objectclass: top
    o: effinger
     
    # users, effinger
    dn: ou=users,o=effinger
    objectClass: organizationalUnit
    objectClass: top
    ou: users
     
    # secmail, users, effinger
    dn: uid=secmail,ou=users,o=effinger
    objectClass: posixAccount
    objectClass: account
    objectClass: top
    cn: secmail
    gidNumber: 134
    homeDirectory: /home/secmail
    uid: secmail
    uidNumber: 121
    # This password equals test
    userPassword: {SSHA}R+pQv9aIQINrPYdgljEJ0B7jzCp2cCzz

    und fügen sie mit einem

    ldapadd -D "cn=admin,o=effinger" -x -W -f database-content.ldif

    zum LDAP-Verzeichnis hinzu (Achtung Passwort verwenden, das für database.ldif erzeugt wurde)

  6. SSL/TLS aktivieren, dazu folgenden Inhalt als ssl-tls_init.ldif abspeichern
    dn: cn=config
    changetype: modify
    add: olcTLSCACertificateFile
    olcTLSCACertificateFile: /etc/ssl/certs/ca.crt
     
    dn: cn=config
    changetype: modify
    add: olcTLSCertificateFile
    olcTLSCertificateFile: /etc/ssl/certs/myserver.crt
     
    dn: cn=config
    changetype: modify
    add: olcTLSCertificateKeyFile
    olcTLSCertificateKeyFile: /etc/ssl/private/myserver.key

    und folgende Befehle ausführen:

    ldapmodify -D "cn=admin,cn=config" -x -W -f ssl-tls_init.ldif
    sudo adduser openldap ssl-cert

    Ein Neustart ist ebenfalls erforderlich, da ich die Erfahrung gemacht habe, dass ohne einen Neustart der Zugriff über TLS nicht funktioniert.

    /etc/init.d/slapd restart
  7. Im nächsten Schritt der LDAP-Konfiguration richten wir Zugriffsrechte ein. Generell soll auf die Login-Daten bei externen Mailservern nur der jeweilige Benutzer selbst und der LDAP-Administrator lesend und schreibend zugreifen können, während der secmail Benutzer nur Leserechte benötigt. Diese Zugriffsrechte werden in der Datei add_acl.ldif mit dem Inhalt
    dn: olcDatabase={1}hdb,cn=config
    changetype: modify
    add: olcAccess
    # The information to send and receive mails from remote servers
    # can only be modified by the user itself and the admin
    # the secmail user which will retrieve mails must have read access
    olcAccess: {1}to dn.regex=".*uid=([^,]+),ou=users,o=effinger" attrs=dcRetrieveType,dcRetrieveLogin,dcRetrievePassword,dcRetrieveServer,dcSMTPLogin,dcSMTPPassword,dcSMTPServer by dn="cn=admin,o=effinger" write by dn.exact,expand="uid=$1,ou=users,o=effinger" write by dn="uid=secmail,ou=users,o=effinger" read by * none
    # Users shall have write access to their attributes
    # admin shall have write access as well
    # all other users have only read access
    olcAccess: {2}to dn.regex=".*uid=([^,]+),ou=users,o=effinger" attrs=dcMailAlternateAddress by dn="cn=admin,o=effinger" write by dn.exact,expand="uid=$1,ou=users,o=effinger" write by * read

    durch den Befehl

    ldapmodify -D "cn=admin,cn=config" -x -W -f add_acl.ldif

    zum LDAP-Verzeichnis hinzugefügt.

  8. Im letzten Schritt indizieren wir wichtige Felder für die Suche im LDAP-Verzeichnis. Das schont Ressourcen und sorgt außerdem dafür,  dass die dezenten Hinweise von OpenLDAP in der Syslog, dass einzelne Attribute indiziert werden sollten, verschwinden. Was die einzelnen Indexoptionen bedeuten ist auf zytrax.com erklärt. Wir legen die Datei add_attribute_indices.ldif mit dem Inhalt
    dn: olcDatabase={1}hdb,cn=config
    changetype: modify
    add: olcDbIndex
    olcDbIndex: cn pres,eq,sub
    olcDbIndex: sn pres,eq,sub
    olcDbIndex: uid pres,eq
    olcDbIndex: mail pres,eq,sub
    olcDbIndex: dcMailAlias pres,eq
    olcDbIndex: givenName pres,eq,sub
    olcDbIndex: dcSubMailAddress pres,eq
    olcDbIndex: dcMailAlternateAddress pres,eq
    olcDbIndex: dcAccountStatus pres,eq

    an und fügen sie mit dem Befehl

    ldapmodify -D "cn=admin,cn=config" -x -W -f add_attribute_indices.ldif

    dem Verzeichnis hinzu.

Zugriff auf OpenLDAP-Server absichern

Durch die Anpassung der Datei ldap.conf können wir festlegen, an welchen LDAP-Server Anfragen standardmäßig gerichtet werden sollen und unter welchen Bedingungen eine Verbindung mit diesem akzeptiert wird. Wir möchten die Konfiguration so anpassen, dass der OpenLDAP-Server ein gültiges Zertifikat vorweisen muss und standardmäßig der gerade eingerichtete LDAP-Server befragt wird. Standardmäßig werden die Anfragen zwar sowieso an den lokalen Rechner gerichtet, aber die Angabe des DNS-Namens ist notwendig, da sonst die Gültigkeitsprüfung für das Serverzertifikat fehlschlagt. In der Datei /etc/ldap/ldap.conf tragen wir folgende Zeilen ein (myserver durch den DNS-Namen ersetzen):

URI             ldap://myserver
TLS_CACERT      /etc/ssl/certs/ca.crt
TLS_REQCERT     demand

Ein anschließender Test mit dem Befehl

ldapsearch -x -b "o=effinger" -ZZ

sollte Einträge des LDAP-Servers zurückgeben. Eigentlich wäre es auch das Beste, wenn der LDAP-Server nur TLS-verschlüsselte Verbindungen akzeptieren würde. Das kann man über ACL mit den Security Strength Factors (SSF) einstellen, allerdings unterstützt Exim bislang keine TLS-verschlüsselten LDAP-Verbindungen, so dass wir hierauf verzichten.

LDAP-Einträge hinzufügen

Jetzt können wir Einträge in OpenLDAP anlegen. Sehr komfortabel kann man dazu JXplorer verwenden (zur Installation siehe Abschnitt Die nächsten Schritt mit LDAP im OpenLDAP 1×1). Wir starten JXplorer und wählen im Menü Datei>Verbinden. Dort tragen wir folgendes ein (localhost bzw. myserver anpassen):
Connection Dialog from JXplorer

Die Daten noch mal im Überblick:

  • Host: myserver Port:389 (myserver anpassen)
  • Base DN: o=effinger (ggfs. anpassen)
  • Benutzer DN: cn=admin,o=effinger (ggfs. anpassen)
  • Kennwort: Das Passwort, das wir für die Datei database.ldif gewählt haben (s.o.).

Nach der erfolgreichen Verbindungsherstellung sehen wir die LDAP-Hierarchie und erweitern den Baum unter o=effinger, so dass wir folgendes sehen:
LDAP Hierarchie nach dem Hinzufügen von users

Im nächsten Schritt fügen wir unseren ersten Benutzer Paul hinzu. Dazu Rechtsklick auf users im LDAP-Baum und Neu auswählen. Im nachfolgenden Dialog ändern wir die RDN auf uid=paul und fügen die Klassen top, person, organizationalPerson, inetOrgPerson, posixAccount und dcMailUser hinzu.
Adding a user to the LDAP directory with JXplorer

Nun sehen wir im nächsten Dialog einige fett gedruckte Attribute – diese sind Pflichtattribute und müssen daher ausgefüllt werden.
Adding necessary user attributes with JXplorer

  • cn steht für common name und ist einfach eine Bezeichnung für den Eintrag, am einfachsten ist es, man wählt hier Vornamen und Nachnamen des Benutzers
  • dcMailMessageStore gibt  das Grundverzeichnis an, in welchem die E-Mails abgelegt werden sollen. Wir werden Dovecot später so konfigurieren, dass wir dieses Verzeichnis (z.B. /home/paul/mail) um die E-Mail-Addresse ergänzen, so dass man z.B. /home/paul/mail/paul/ erhält. Letzeres wird in Dovecot das Home-Verzeichnis sein, in dem u.a. die .dovecot.sieve gespeichert wird. Die Mails werden später als Maildir im Unterverzeichnis maildir abgelegt, also /home/paul/mail/paul/maildir
  • gidNumber gibt die GruppenID des Benutzers Paul an. Paul sollte bereits als Benutzer auf dem Rechner angelegt sein, so dass man über ein
    id paul

    die gid herausfinden kann.

  • homeDirectory das Heimverzeichnis des Benutzers Paul. Den korrekten Wert kann man herausfinden durch ein
    cat /etc/passwd | grep paul | cut -d: -f6
  • sn steht für surname, also den Nachnamen des Benutzers
  • givenName steht für den Vornamen des Benutzers, ist allerdings ein optionales Attribut
  • uidNumber die BenutzerID von Paul. Der korrekte Wert ist analog zur gidNumber herauszufinden – statt gid dann den Wert von uid verwenden.
  • userPassword Damit Paul sich einloggen kann, legen wir ein Passwort für ihn fest. Das Passwort sollte keinen Slash “/” enthalten, da in der Exim-Konfiguration dieses Zeichen zur Trennung einer zusammengesetzten Zeichenfolge aus Login und Passwort verwendet wird.
  • mail Dieses Attribut steht für die lokale E-Mail-Addresse von Paul. Die lokale E-Mail-Addresse wird dabei ohne die Domain angegeben. In diesem Fall genügt also der Eintrag “paul” für die Addresse paul@myserver

Danach klicken wir auf den Button Abschicken und Paul ist als Benutzer in LDAP verfügbar.

Jetzt richten wir noch den externen MailAccount von Paul ein, damit er auch seine Mails von GMX abrufen bzw. über GMX schicken kann. Dazu erweitern wir die Ansicht der LDAP-Hierarchie, so dass wir mit einem Rechtsklick auf paul erneut den Eintrag Neu wählen können.
LDAP tree after adding paul as a user
Im erscheinenden Dialogfeld wählen wir die Klassen dcExternalMailAccount und dcPosixSubAccount aus. RDN setzen wir auf dcSubMailAddress=paulpanzer@gmx.de. Folgende Attribute können bzw. müssen wir eintragen:

  • dcSubMailAddress steht für die Mail-Addresse des externen Accounts. Lokale Mails an diese Addresse werden ohne den Umweg über den externen Mailprovider zugestellt.
  • dcAccountStatus kann die Werte active, noaccess, disabled und deleted annehmen. Wir wählen active.
  • dcMailQuota ist ein Attribut, das  wir nicht verwenden werden, allerdings könnte man hier zukünftig eine Größenbeschränkung für die paulpanzer@gmx.de-Mailbox  einrichten.
  • dcMailSizeMax verwenden wir ebenfalls nicht, allerdings könnte man hier zukünftig eine Beschränkung der Größe der zu versendenden E-Mails festlegen.
  • dcRetrieveType gibt den Protokoll/Typ an, mit dem die Mails abgerufen werden sollen. Beispielhafte Werte sind SimplePOP3Retriever, BrokenUIDLPOP3Retriever oder SimpleIMAPSSLRetriever. Eine detaillierte Auflistung findet sich in der Dokumentation von getmail.
  • dcRetrieveLogin der Benutzername für den Mailabruf, bei GMX üblicherweise die E-Mail-Addresse
  • dcRetrievePassword das zugehörige Passwort, um Mails abzurufen.
  • dcRetrieveServer der Name/IP des Servers für das Abrufen von Mails. Bei GMX mit POP3 ist es pop.gmx.net.
  • dcSMTPLogin der Benutzername für den SMTP-Server, bei GMX üblicherweise die E-Mail-Addresse.
  • dcSMTPPassword das zugehörige Passwort, um Mails zu versenden.
  • dcSMTPServer der Name/IP des SMTP-Servers. Bei GMX ist es mail.gmx.net.
  • dcMailAlternateAddress steht für eventuelle Alias-Addressen der bei dcSubMailAddress angegebenen E-Mail-Addresse.  Besitzt Paul Panzer also für die Addresse paulpanzer@gmx.de noch den Alias p.panzer@gmx.de kann er die Mail hier eintragen und Mails über den lokalen Server werden direkt ohne Umwege über GMX zugestellt.
  • dcPosixOwnerURL dient dazu, dass dovecot wichtige Parameter, wie uid, uidNumber,gidNumber und dcMailMessageStore vom übergeordneten Benutzereintrag von Paul bekommt. Hier tragen wir folgende LDAP-URL ein:
    ldap:///uid=paul,ou=users,o=effinger?uid,uidNumber,gidNumber,dcMailMessageStore?base?(&(objectClass=posixAccount)(objectClass=dcMailUser))

Und so sieht das bei mir aus:
Adding an external mail account to the LDAP directory
Nun wieder auf Abschicken klicken und der Eintrag sollte vorhanden sein. Wichtig ist, jetzt nochmal zu prüfen, ob auch das Dynlist-Overlay funktioniert. Das machen wir mit einem

ldapsearch -b "dcSubMailAddress=paulpanzer@gmx.de,uid=paul,ou=users,o=effinger" -x

Dieser Befehl sollte unter anderem die Zeilen mit den Attributen uid, uidNumber,gidNumber und dcMailMessageStore augeben:

dcMailMessageStore: /home/paul
gidNumber: 1000
uidNumber: 1000
uid: paul

Testen und Mitschneiden von Anfragen an OpenLDAP

Zum Testen und Debuggen ist es oft hilfreich, zu überprüfen, welche LDAP Anfragen an den OpenLDAP-Server gestellt wurden. Dazu kann man unter cn=config (mit cn=admin,cn=config einloggen) den Parameter olcLogLevel von none auf einen numerischen Wert ändern. 256 hat sich für mich als gut bewährt, bei Terrence Miao findet man aber eine detaillierte Auflistung der einzelnen Loglevels. Die LDAP-Anfragen werden dann in die syslog geschrieben.

Da der Artikel nun schon ziemlich lang ist, folgt die Konfiguration von dovecot in einem zweiten Teil.

Auch dieses Jahr gibt es im Oktober ja wieder eine Ubucon, und ich überlege mir gerade ob ich nicht wieder einen (mehr oder weniger guten) Vortrag über irgendwas halten sollte!

Ich weis nur noch nicht über was, den schon wieder über LVM ist vielleicht auf Dauer etwas langweilig...

Macht doch einfach mal ein paar Vorschläge, mal sehen was ich dann daraus machen kann ;-)

Auch dieses Jahr gibt es im Oktober ja wieder eine Ubucon, und ich überlege mir gerade ob ich nicht wieder einen (mehr oder weniger guten) Vortrag über irgendwas halten sollte!

Ich weis nur noch nicht über was, den schon wieder über LVM ist vielleicht auf Dauer etwas langweilig...

Macht doch einfach mal ein paar Vorschläge, mal sehen was ich dann daraus machen kann ;-)