MIDGARD · Multi User Dungeon Alpha 0.1

Kapitel 11: Sicherheit & Stabilität

Sicherheit ist eines der wichtigsten, aber am wenigsten verstandenen Themen für LPC-Anfänger. In diesem Kapitel lernst du Schritt für Schritt, warum UID und EUID existieren, wie die Mudlib dich schützt und wie du selbst sicheren Code schreibst, ohne Angst haben zu müssen, etwas „kaputt zu machen“.

Weiter zu Kapitel 12

Best Practices, typische Fehler & saubere LPC-Architektur

11.1 Warum Sicherheit im MUD überhaupt nötig ist

In einem Singleplayer-Programm ist Sicherheit oft nebensächlich. In einem MUD wie dem Midgard laufen jedoch hunderte oder tausende Objekte gleichzeitig – geschrieben von vielen verschiedenen Magiern. Jedes Objekt kann prinzipiell mit jedem anderen Objekt interagieren.

Ohne Sicherheitsmechanismen könnte:

  • jedes Objekt beliebige andere Objekte zerstören
  • Spielerwerte manipuliert werden
  • Quests gefälscht oder zurückgesetzt werden
  • Spieler teleportiert, gefesselt oder blockiert werden
  • der gesamte MUD instabil werden

Deshalb gibt es im Midgard MUD ein ausgefeiltes Sicherheitsmodell, das auf UID, EUID und klaren Verantwortlichkeiten basiert. Als Anfänger musst du dieses Modell nicht bis ins letzte Detail beherrschen, aber du musst die Grundidee verstehen.

11.2 UID – Die Identität eines Objekts

Die UID (User ID) eines Objekts sagt: „Zu wem gehört dieser Code?“

Im Midgard MUD ist die UID normalerweise an den Verzeichnispfad gekoppelt. Ein Objekt unter /players/alice/ hat in der Regel die UID alice.

Wichtige Eigenschaften der UID

  • Die UID wird vom Driver/Master gesetzt
  • Sie ist nicht frei änderbar
  • Sie bestimmt Besitz und Verantwortlichkeit
  • Sie ist Grundlage für viele Sicherheitsprüfungen

Als Faustregel: Die UID sagt, wem der Code gehört – nicht, was er darf.

Beispiel: UID abfragen


// Debug-Ausgabe der UID eines Objekts
write("UID: " + getuid(this_object()) + "\n");
      

Als Anfänger wirst du getuid() selten brauchen, aber es ist wichtig zu wissen, dass diese Identität existiert.

11.3 EUID – Die effektive Berechtigung

Die EUID (Effective User ID) ist entscheidender als die UID. Sie beantwortet die Frage: „Mit welchen Rechten handelt dieses Objekt gerade?“

Ein Objekt kann Code „im Auftrag“ einer anderen UID ausführen. Genau das ermöglicht sichere Delegation.

Vergleich aus der realen Welt

  • UID: Dein Name im Ausweis
  • EUID: Dein Dienstausweis für eine bestimmte Aufgabe

Beispiel: Ein Standardobjekt gehört dem Magier alice, darf aber zeitweise mit der EUID root arbeiten, um eine kontrollierte Aufgabe auszuführen.

EUID abfragen


// Effektive UID anzeigen
write("EUID: " + geteuid(this_object()) + "\n");
      

In der Praxis wird die EUID meist automatisch von der Mudlib gesetzt. Als Anfänger solltest du sie fast nie selbst ändern.

11.4 Warum es gefährlich wäre, alles zu erlauben

Stell dir vor, jedes Objekt dürfte jederzeit:


destruct(other_object);
other_object->SetProp(P_LEVEL, 100);
clone_object("/secure/master");
      

Dann könnte:

  • ein Bug einen Spieler zerstören
  • ein fehlerhaftes Item Quests ruinieren
  • ein böswilliges Objekt massiven Schaden anrichten

Deshalb prüft der Driver bei vielen Operationen: „Darf dieses Objekt das?“ – und nutzt dafür UID/EUID.

11.5 Typische sicherheitsrelevante Operationen

Bestimmte Aktionen gelten als „gefährlich“ und sind besonders geschützt:

  • destruct() – Objekt zerstören
  • move() – Objekte teleportieren
  • seteuid() – Rechte ändern
  • call_other() auf sensitive Objekte
  • Zugriff auf /secure/

Wenn du als Anfänger versuchst, so etwas „einfach zu machen“, wirst du oft kryptische Fehlermeldungen sehen. Das ist kein Bug – das ist Schutz.

11.6 Defensive Programmierung: Dein bester Schutz

Sicherheit bedeutet nicht nur UID/EUID, sondern auch robusten Code.

Grundregeln

  • Vertraue niemals Eingaben blind
  • Prüfe objectp(), mappingp(), pointerp()
  • Rechne damit, dass Objekte verschwinden
  • Baue klare Abbruchbedingungen ein

Beispiel: Unsicherer Code


// UNSICHER
void do_something(object ob) {
  ob->SetProp(P_HP, 0);
}
      

Sichere Variante


// SICHERER
void do_something(object ob) {
  if (!objectp(ob)) return;
  if (!living(ob)) return;
  if (!interactive(ob)) return;

  ob->SetProp(P_HP, 0);
}
      

Defensive Checks sind kein Overhead – sie sind Pflicht in einer verteilten, persistenten Spielwelt.

11.7 Zugriff kontrollieren: Wer darf eine Funktion nutzen?

Häufig willst du verhindern, dass „irgendwer“ eine Funktion aufruft. Typisches Beispiel: Debug- oder Admin-Funktionen.

Einfache Prüfung


void reset_room() {
  if (!this_player() || !IS_ARCH(this_player())) {
    write("Das darfst du nicht.\n");
    return;
  }
  // Reset-Logik
}
      

Wichtig: Verlasse dich nicht darauf, dass eine Funktion „schon niemand ruft“. In LPC kann jedes Objekt prinzipiell jede Funktion aufrufen, sofern sie nicht geschützt ist.

11.8 Häufige Anfängerfehler bei Sicherheit

Fehler 1: „Das sieht keiner“

Falsch. Objekte können Funktionen direkt aufrufen, auch ohne Spielerbefehl.

Fehler 2: setuid/seteuid ohne Verständnis

Das ist extrem gefährlich. Als Anfänger: Finger weg, außer ein Mentor sagt dir explizit, was du tun sollst.

Fehler 3: Vertrauen in fremde Objekte

Nur weil ein Objekt „offiziell“ aussieht, heißt das nicht, dass es sich korrekt verhält. Prüfe immer, was du bekommst.

Fehler 4: Keine Fehlerbehandlung

catch() ist dein Freund, wenn du fremden Code aufrufst.

11.9 catch() – Sicherheit bei fremdem Code

Wenn du Code aufrufst, den du nicht kontrollierst, solltest du ihn absichern.


// Sicherer Funktionsaufruf
mixed res;
if (catch(res = other_object->DoSomething())) {
  write("Ein Fehler ist aufgetreten.\n");
  return;
}
      

Ohne catch() könnte ein Laufzeitfehler dein Objekt oder den Raum lahmlegen.

11.10 Zusammenfassung

Sicherheit im Midgard MUD ist kein Selbstzweck. Sie ermöglicht, dass viele unabhängige Entwickler gemeinsam an einer stabilen Welt arbeiten können.

  • UID sagt, wem Code gehört
  • EUID sagt, was ein Objekt darf
  • Viele Operationen sind bewusst eingeschränkt
  • Defensive Programmierung ist Pflicht
  • Vertraue nie blind fremdem Code

Wenn du diese Prinzipien beachtest, wirst du nicht nur sichereren Code schreiben, sondern auch weniger schwer auffindbare Bugs produzieren.

Weiter zu Kapitel 12

Im letzten Kapitel fassen wir alles zusammen: Best Practices, saubere Architektur, typische Anfängerfehler und wie du langfristig guter LPC-Code schreibst.

Kapitel 12 lesen

Best Practices & saubere LPC-Architektur