Server-Notfallprogramm für Unterwegs

… oder: Krisenmanagement für arme Admins.

Am Mittwoch geht es für mich auf zum diesjährigen Summer Breeze Metal Open Air in Dinkelsbühl. Das bedeutet leider nicht nur Genuss für meine Ohren, sondern auch Stress: Der Admin in mir macht sich Gedanken, ob denn auch alle Server ohne Störungen über die Festivalzeit kommen werden. Unterwegs habe ich nur mein Smartphone mit einer wackeligen Mobilfunkverbindung. Darauf ist ein SSH-Client installiert, der mir Zugriff auf meine Server erlaubt. Und weil mir alleine der Gedanke daran schon weh tut, root-Login darauf zu ermöglichen, kann sich das Smartphone nur als normaler Benutzer zum Server verbinden. Via Publickey-Auth, versteht sich.

Nun stehe ich allerdings vor dem Problem, dass ja ein normaler Benutzer keine Dienste neu starten kann, weil ihm die Rechte dazu fehlen. Möglicherweise werde ich beispielsweise meinen XMPP-Server einmal neu starten müssen, weil die zuletzt getroffenen Maßnahmen nicht gewirkt haben und er wieder einmal keine Logins mehr zulässt. Ein “systemctl restart prosody” ist mit diesem Account nicht möglich. Nun könnte man mit sudo arbeiten und die Ausführung des Kommandos speziell für diesen User erlauben. Meine Debian-Server kommen allerdings ohne sudo und das soll auch so bleiben. Also kein sudo für mich.

Unter Linux gibt es allerdings noch eine andere Möglichkeit, Befehle mit höheren Rechten auszuführen: setuid. Ist dieses Bit für eine ausführbare Datei gesetzt, wird diese immer mit den Rechten des Dateibesitzers ausgeführt - egal, wer die Ausführung initiiert. Leider funktioniert das mit neueren Linux-Kerneln nicht mehr für Scripts, sodass ich mich kurz dazu entschlossen habe, ein einfaches C-Programm zu schreiben, das den Neustart diverser Dienste übernehmen kann:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

char *prosody = "prosody";
char *php = "php";
char *nginx = "nginx";

int main(int argc, char *argv[]) {
    setuid(0);   // be root

    if(argc == 2){
        // check content of second argument (first is program name)

        if( strcmp( argv[1], prosody ) == 0) {
            printf( "Restarting Prosody ..." );
            system( "systemctl restart prosody" );
        }
        else if( strcmp( argv[1], php ) == 0) {
            printf( "Restarting PHP ..." );
            system( "systemctl restart php5-fpm" );
        }
        else if( strcmp(argv[1], nginx) == 0) {
            printf( "Restarting Nginx ..." );
            system( "systemctl restart nginx" );
        }
    }

    return 0;
}

Ich will Prosody, Nginx und PHP neu starten können. Das kleine Programm lässt sich natürlich für beliebig viele weitere Dienste erweitern. Programm kompilieren:

$ gcc -o emergency emergency.c

Die Binärdatei “emergency” wird nun an passender Stelle auf dem Server abgelegt und bekommt vom root-User das SetUID-Bit (4) verpasst:

# chmod 4755 emergency

Nun kann ein einfacher Benutzer das Programm z.B. wie folgt aufrufen:

$ ./emergency prosody

Damit wird der Prosody-Dienst mit root-Rechten neu gestartet.

Sollte mein XMPP-Server bis Sonntag wieder zicken, habe ich zumindest die Möglichkeit, Prosody mal eben neu zu starten. Bei größeren Problemen hilft mir mein SSH-Zugang dann zwar nicht, aber schließlich will ich ja auch nicht stundenlang auf einem Laptop herumhacken, wenn ich schon einmal auf einem Festival unterwegs bin ;-) Dann lasst uns mal alle hoffen, dass Prosody keinen Ärger macht, während ich weg bin …