Zugriff verweigern ohne Supervisorobjekt.

Ohne SV-Objekte wird asser_supervisor() die Ebene loeschen,
daher in dem Fall auch den Zugriff im Anschluss verweigern.
Ausserdem viele Kommentare ergaenzt, um das Zusammenspiel
und Verhalten zu erklaeren.

Change-Id: If618a38badcc659cbd564befaa3fa228bf844cdd
diff --git a/p/daemon/channeld.c b/p/daemon/channeld.c
index 185ff73..122f37a 100644
--- a/p/daemon/channeld.c
+++ b/p/daemon/channeld.c
@@ -616,9 +616,11 @@
 #define MASTER_OB(x) channels[x][I_MASTER]
 #define ACC_CLOSURE(x) channels[x][I_ACCESS]
 
-// Stellt sicher, dass einen Ebenen-Supervisor gibt.
-// Wenn dies nicht moeglich ist (z.b. leere Ebene), dann wird die Ebene
-// geloescht und 0 zurueckgegeben.
+// Stellt sicher, dass einen Ebenen-Supervisor gibt. Wenn dies nicht moeglich
+// ist (z.b. leere Ebene), dann wird die Ebene geloescht und 0
+// zurueckgegeben. Allerdings kann nach dieser Funktion sehr wohl die I_ACCESS
+// closure 0 sein, wenn der SV keine oeffentliche definiert! In diesem Fall
+// wird access() den Zugriff immer erlauben.
 private int assert_supervisor(string ch)
 {
   // Es ist keine Closure vorhanden, d.h. der Ebenenbesitzer wurde zerstoert.
@@ -633,9 +635,11 @@
       string err = catch(new_acc_cl=
                           symbol_function("check_ch_access", MASTER_OB(ch));
                           publish);
-      /* Wenn sich die Closure fehlerfrei erstellen liess, dann wird sie als
-         neue Zugriffskontrolle eingetragen und auch der Ebenenbesitzer neu
-         gesetzt. */
+      /* Wenn das SV-Objekt neu geladen werden konnte, wird es als Mitglied
+       * eingetragen. Auch die Closure wird neu eingetragen, allerdings kann
+       * sie 0 sein, wenn das SV-Objekt keine oeffentliche check_ch_access()
+       * mehr definiert. In diesem Fall gibt es zwar ein SV-Objekt, aber keine
+       * Zugriffrechte(pruefung) mehr. */
       if (!err)
       {
         ACC_CLOSURE(ch) = new_acc_cl;
@@ -644,6 +648,7 @@
         // er sich ja selber genehmigen koennte), und auch um eine Rekursion
         // zu vermeiden.
         add_member(ch, find_object(MASTER_OB(ch)));
+        // Rueckgabewert ist 1, ein neues SV-Objekt ist eingetragen.
       }
       else
       {
@@ -653,8 +658,13 @@
         return 0;
       }
     }
-    // TODO: kaputte Objekte raussortieren, neuen Master bestimmen, wenn
-    // dieser nicht mehr existiert.
+    else
+    {
+      // In diesem Fall muss ein neues SV-Objekt gesucht und ggf. eingetragen
+      // werden. Wir nehmen das aelteste Mitglied der Ebene.
+      // TODO: kaputte Objekte raussortieren, neuen Master bestimmen, wenn
+      // dieser nicht mehr existiert.
+    }
   }
   return 1;
 }
@@ -678,6 +688,10 @@
   if(!pointerp(channels[ch]))
     return 0;
 
+  // Dieses Objekt, Supervisor-Objekt und Root-Objekte duerfen auf der Ebene
+  // senden, ohne Mitglied zu sein. Das ist die Folge der zurueckgegebenen 2.
+  // TODO: Im Falle des SV-Objekts ist das aber IMHO quatsch und sollte
+  // entfernt werden.
   if ( !previous_object(1) || !extern_call() ||
        previous_object(1) == this_object() ||
        (stringp(MASTER_OB(ch)) &&
@@ -685,6 +699,8 @@
         getuid(previous_object(1)) == ROOTID)
     return 2;
 
+  // Nur dieses Objekt darf Meldungen im Namen anderer Objekte faken,
+  // ansonsten muss <pl> der Aufrufer sein.
   if (!objectp(pl) ||
       ((previous_object(1) != pl) && (previous_object(1) != this_object())))
     return 0;
@@ -692,7 +708,12 @@
   if (IsBanned(pl, cmd))
     return 0;
 
+  // Wenn kein SV-Objekt mehr existiert und kein neues bestimmt werden konnte,
+  // wurde die Ebene ausfgeloest. In diesem Fall auch den Zugriff verweigern.
   if (!assert_supervisor(ch))
+    return 0;
+  // Wenn closure jetzt dennoch 0, wird der Zugriff erlaubt.
+  if (!ACC_CLOSURE(ch))
     return 1;
 
   return funcall(ACC_CLOSURE(ch), ch, pl, cmd, &txt);