Zugriffsrechtepruefung neu organisiert.
Die Pruefung der Zugriffsrechte wurde in eine separate Funktion
zusammengefasst, um die Lesbarkeit und die Wartbarkeit zu
verbessern.
Hierbei wurde auch die Option vorbereitet, feiner granulierte
Zugriffsrechte einzufuehren.
Change-Id: Ie87deb3e5aa56a5e3f7c29cba31c34aceb48427c
diff --git a/std/thing/properties.c b/std/thing/properties.c
index b9b2372..45f520a 100644
--- a/std/thing/properties.c
+++ b/std/thing/properties.c
@@ -55,46 +55,85 @@
set_next_reset(-1);
}
-// Welche externen Objekte duerfen zugreifen?
-nomask private int allowed()
+// Prueft, ob ein Zugriff auf eine Property erlaubt ist.
+// Properties, die SECURED oder PROTECTED sind, duerfen nur vom Objekt
+// selber, EM+ oder ROOT veraendert werden.
+#define SAVE_OBJECT 1
+#define PROP_SET 2
+#define PROTECTED_SET 3
+#define PROTECTED_DELETE 4
+#define SECURED_SET 5
+#define SECURED_DELETE 6
+nomask private int prop_check_privilege(int drop_priv, int mode,
+ int op=PROP_SET)
{
- if ( (previous_object() && IS_ARCH(getuid(previous_object())) &&
- this_interactive() && IS_ARCH(this_interactive())) ||
- (previous_object() && getuid(previous_object()) == ROOTID &&
- geteuid(previous_object()) == ROOTID) )
- return 1;
- return 0;
-}
+ // Wenn closure_call in diesem Ausfuehrungsthread (Top-Level-Call) gesetzt
+ // wurde, zaehlt der Aufruf immer als drop_priv, auch wenn drop_priv 0 sein
+ // sollte.
+ drop_priv ||= (closure_call == driver_info(DI_EVAL_NUMBER));
+ // Interne Calls oder eigenes Objekt (als letzter 'externer' Aufrufer via
+ // Callother) darf alles
+ if (!drop_priv || previous_object() == this_object())
+ return 1;
+
+ // Ab hier nur noch fremde Objekte
+ switch(op)
+ {
+ case SAVE_OBJECT:
+ // Eigentlich nur vom jeweils aktiven simul_efun-Objekt gerufen, aber
+ // der einfacheit halber sind alle ROOT-Objekte erlaubt. Aber nur
+ // direkten Caller pruefen, *nicht* ROOT_SECURITY!
+ if (get_euid(previous_object()) == ROOTID)
+ return 1;
+
+ case SECURED_DELETE:
+ // Das SECURED-Flag darf bei Properties nicht mehr geloescht werden
+ return 0;
+
+ case SECURED_SET:
+ if (geteuid(previous_object()) == ROOTID || ARCH_SECURITY)
+ return 1;
+
+ case PROTECTED_DELETE:
+ case PROTECTED_SET:
+ case PROP_SET:
+ // Properties, die schon SECURED oder PROTECTED sind, duerfen
+ // nur vom Objekt selber manipuliert werden
+ if (!(mode & (PROTECTED|SECURED)) // nicht geschuetzt
+ || (geteuid(previous_object()) == ROOTID || ARCH_SECURITY))
+ return 1;
+ }
+ return 0;
+}
// Set() -- provides direct access to a property, no filters
// Type=F_VALUE und drop_priv=extern_call() by default
public mixed Set(string name, mixed Value, int Type, int drop_priv)
{
- if (!objectp(this_object()))
- return 0;
-
- // Properties, die SECURED oder PROTECTED sind, duerfen nur vom Objekt
- // selber, EM+ oder ROOT veraendert werden.
+ int mode = prop[F_MODE][name];
// Es ist verfuehrerisch, das 'drop_priv||extern_call()' durch 'drop_priv' zu
// ersetzen, weil extern_call() das default-argument fuer <drop_priv> ist.
// Das ist keine gute Idee, weil <drop_priv> unter der Kontrolle des Aufrufers
// ist und dieser 0 uebergeben kann. Sprich: wenn es 0 ist, muessen wir
// dennoch selber pruefen. Wir glauben aber immer, wenn es 1 ist, der
// Aufrufer hat nichts davon und das eigene Objekt darf Privilegien abgeben.
- drop_priv = drop_priv||extern_call()||closure_call==driver_info(DI_EVAL_NUMBER);
- if ((prop[F_MODE][name]&(PROTECTED|SECURED))
- && drop_priv && previous_object() != this_object() && !allowed())
- return -1;
+ drop_priv = drop_priv||extern_call();
- // Das SECURED-Flag darf bei Properties nicht mehr geloescht werden
- if ((prop[F_MODE][name]&SECURED)&&
- (Type==F_MODE||Type==F_MODE_AD)&&(Value & SECURED))
+ // Erstmal pruefen, ob Aenderung der Prop erlaubt ist.
+ if (!prop_check_privilege(drop_priv, mode, PROP_SET))
+ return -1;
+ // Bemerkung: aktuell koennen alle Objekte PROTECTED setzen. Loeschen
+ // koennen es ROOT, EM+ und ME ueber den Check oben.
+
+ // Soll SECURED geloescht werden und ist das erlaubt?
+ if ((Type==F_MODE||Type==F_MODE_AD) && (Value & SECURED)
+ && !prop_check_privilege(drop_priv, mode, SECURED_DELETE))
return -2;
- // Setzen duerfen das SECURED-Flag nur das Objekt selber, EM+ oder ROOT
+ // Soll SECURED gesetzt werden und ist das erlaubt?
if ((Type==F_MODE||Type==F_MODE_AS) && (Value&SECURED)
- && drop_priv && previous_object() != this_object() && !allowed() )
+ && !prop_check_privilege(drop_priv, mode, SECURED_SET) )
return -3;
switch(Type)
@@ -187,7 +226,7 @@
else // Erfolgreicher call
{
if (mode & SETMAPPED) // SM hat noch nicht selber gesetzt
- result = Set( name, result, F_VALUE, extern||extern_call() );
+ result = Set( name, result, F_VALUE, drop_priv||extern_call() );
}
// Wenn dieser Aufruf closure_call gesetzt hat, wieder loeschen.
@@ -233,7 +272,7 @@
int set_closure_call = closure_call != driver_info(DI_EVAL_NUMBER);
if (set_closure_call)
closure_call = driver_info(DI_EVAL_NUMBER);
-
+
// Dann Mal die Closure aufrufen. Bei Fehler selbige loeschen
if (catch(result=funcall(func, prop[F_VALUE][name]);publish))
{
@@ -247,11 +286,10 @@
// Und zurueckgeben
return result;
}
-
// _query_*-Methode vorhanden? falls ja, aufrufen.
- if (call_resolved(&result,this_object(),"_query_"+name))
+ else if (call_resolved(&result,this_object(),"_query_"+name))
return result;
-
+
// Hilft alles nichts. Es ist eine 'normale' Property ...
return prop[F_VALUE][name];
}
@@ -292,33 +330,28 @@
// Andere objekt-externe Nutzung ausdruecklich **NICHT** supportet!
public void SetProperties( mapping props )
{
- string *names;
- int i, j, same_object;
-
+ int i, j;
+
// Kein Mapping? Schlecht ...
if(!mappingp(props)) return;
- // Setzen wir selber?
- same_object = (closure_call!=driver_info(DI_EVAL_NUMBER) &&
- (!extern_call()||previous_object()==this_object()||
- allowed()));
- names = m_indices(props);
-
+ string *names = m_indices(props);
+
// Das SECURED-Flag darf nur durch das Objekt selber gesetzt werden:
- // Alle SECURED-Flags aus props loeschen
- if (!same_object)
- {
- j=sizeof(names);
- while(j--) props[names[j], F_MODE] &= ~SECURED;
- }
+ // mode ist hier egal. Antwort cachen fuer den Loop
+ int no_secure = !prop_check_privilege(extern_call(), 0, SECURED_SET);
j=sizeof(names);
while(j--)
{
- // Properties, die schon SECURED oder PROTECTED sind, duerfen
- // nur vom Objekt selber manipuliert werden
- if (same_object||!(prop[F_MODE][names[j]] & (PROTECTED|SECURED)) )
+ if (prop_check_privilege(extern_call(), prop[F_MODE][names[j]],
+ PROP_SET))
{
+ // Prop-Setzen erlaubt, aber ggf. SECURED flag loeschen, wenn nicht
+ // das nicht erlaubt ist (s.o.).
+ if (no_secure)
+ props[names[j], F_MODE] &= ~SECURED;
+ // jetzt die einzelnen Teile der Prop seztzen.
i=F_PROP_ENTRIES;
while(i--)
{
@@ -337,6 +370,8 @@
// genutzt von simul_efun im save_object() zur Abfrage aller Properties, um
// hieraus die gespeicherten zu bestimmen.
// Andere objekt-externe Nutzung ausdruecklich **NICHT** supportet!
+// TODO fuer zukuenftige Features (wie private Properties) auf die simul_efun
+// beschraenken.
public mapping QueryProperties()
{
mapping props;
@@ -344,7 +379,7 @@
string *names;
props = m_allocate( sizeof(prop[F_VALUE]), F_PROP_ENTRIES );
-
+
if (pointerp(prop))
{
i=F_PROP_ENTRIES;