Open Source im professionellen Einsatz

Root oder nicht

Damit der Daemon in Listing 1 den SMTP-Port 25 mit »bind()« an sich reißen kann, muss er unter der Benutzerkennung »root« laufen, und um das damit verbundene Sicherheitsrisiko zu mindern, gibt er diese Privilegien später wieder ab. Ein mit »sudo« gestartetes Programm führt in der Environment-Variablen »SUDO_USER« den Nutzer, der den Sudo-Befehl ausführte. Auf die Rechte dieses unprivilegierten Users stutzt das Skript später seine Rechte zurück. Der Befehl »sudo_me()« in Zeile 8 aus dem CPAN-Modul Sysadm::Install prüft, ob »root« das Skript gestartet hat, und holt dies im Bedarfsfall mit »sudo« nach.

Listing 1:
»minimail«

01 #!/usr/local/bin/perl -w
02 use strict;
03 use Sysadm::Install qw(:all);
04 use App::Daemon qw(daemonize);
05 use Log::Log4perl qw(:easy);
06
07 BEGIN {
08   sudo_me();
09   $App::Daemon::as_user = "root";
10   $App::Daemon::logfile =
11                      "/var/log/minimail.log";
12   $App::Daemon::loglevel = $INFO;
13   daemonize();
14 };
15
16 use POE;
17 use PoCoForwarder;
18 use PoCoTimedProcess;
19
20 my $port_from      = 25;
21 my $port_to        = 25;
22 my $tunnel_port    = 1025;
23 my $real_smtp_host = 'host.provider.com';
24
25 my $process = PoCoTimedProcess->new(
26   heartbeat => 10,
27   timeout   => int(rand(25)) + 10,
28   command   => ["ssh", '-N', '-L',
29     "$tunnel_port:localhost:$port_to",
30     $real_smtp_host],
31 );
32
33 my $forwarder = PoCoForwarder->new(
34     port_from => $port_from,
35     port_to   => $tunnel_port,
36     port_bound => sub {
37        INFO "Dropping privileges";
38        $< = $> = getpwnam($ENV{SUDO_USER});
39     },
40     client_connect => sub {
41       $process->launch();
42     },
43 );
44
45 $process->spawn();
46 $poe_kernel->run();

Das Dämonen-Werkzeug App::Daemon vom CPAN exportiert die Funktion »daemonize()«, die dafür sorgt, dass der Daemon die Befehle »minimail start|stop« kennt und sang- und klanglos im Hintergrund arbeitet, sobald er die Startsequenz durchlaufen hat - nur die Logdatei zeigt an, was er gerade treibt. Das Log4perl-Logfile setzt »-l« (oder die Variable »App::Daemon::logfile«). Wird der Daemon mit »-X« im Vordergrund gestartet, erscheint die Logausgabe auf »Stderr«.

Der »BEGIN«-Block ab Zeile 7 sorgt dafür, dass das POE-Modul in Zeile 16 erst nach dem Dämonisieren des Prozesses (Zeile 13) geladen wird. Das sei wichtig, so erklärte mir eine hilfreiche Seele auf der POE-Mailingliste, denn sonst schießt POE von ihm erzeugte Kindprozesse nicht richtig ab.

Da App::Daemon selbst ein Feature zum Abgeben der Root-Privilegien bietet, weist Zeile 9 des Moduls der Variablen »$as_user« den Wert »root« zu und überlässt damit den Sicherheits-Umschwung dem Skript, das ihn direkt nach dem Binden des Daemon an Port 25 ab Zeile 37 ausführt.

POE zur Hilfe

Ein selbst geschriebener Netzwerkdaemon kostet normalerweise mächtig Schweiß und Tränen, doch zum Glück bietet das CPAN einige POE-Komponenten, die ich nur wie Legosteine aneinanderstecken muss. So formt »minimail« aus den Komponenten POE::Component::Client::TCP und POE::Component::Server::TCP den Port-Forwarder »PoCoForwarder«. Er hängt sich an den lokalen »$port_from« und leitet alles dort Ankommende an den Tunnelport »$tunnel_port« weiter - und umgekehrt ebenso. Das ist keine triviale Angelegenheit, denn am lokalen Port können mehrere Mailclients gleichzeitig hängen. Die sind dann parallel zu bedienen.

Die zweite Komponente, also »PoCoTimedProcess«, fährt einen Prozess wie den Tunnel mit der Methode »launch()« für eine vorbestimmte Zeit hoch oder verlängert seine Lebenszeit, falls er schon läuft. Jedes Mal, wenn der Forwarder einen neu angedockten Client feststellt, ruft er im »client_connect()«-Callback die Methode »launch()« auf. Diese schnappt sich das SSH-Kommando

ssh -N -L 1025:localhost:25 U
host.provider.com

in Zeile 28 und verbindet sich so mit dem Host »host.provider.com« über das verschlüsselte SSH-Protokoll, loggt sich dort ein, startet aber dank der Option »-N« keine interaktive Shell, sondern hängt nur so da und leitet die Datenströme vor- und zurück.

Der Port 1025 ist das Desktop-seitige Ende des Tunnels, der »localhost« im SSH-Befehl bezieht sich allerdings auf »host.provider.com«, da SSH sich jetzt dort befindet. Die dem Doppelpunkt folgende »25« ist der SMTP-Port des gehosteten Rechners. Falls der Username auf dem Hosting-Rechner nicht der gleiche ist wie auf dem Desktop, darf ihn der Aufruf mit »mschilli@host.provider.com« voranstellen, damit SSH Bescheid weiß.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 6 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook