* Jan Trippler schrieb am 28.Nov.2002:
Hmm, jetzt müsste man IMHO mal tiefer in die System-Calls
einsteigen. Dein fopen() klappt ohne setuid() (auch in /var/run),
der system() klappt nur mit setuid() - siehe meine andere Mail.
Andere Funktionen (wie z. B. ein stat("/etc/shadow", R_OK) - das
hatte ich vor ein paar Wochen mal in einem anderen Thread benutzt)
klappen auch nur _mit_ setuid().
man setuid() sagt auch aus, dass hier die _effektive_ User-ID
gesetzt wird.
Ich habe mir das ganze mal angetan, und mal Manpages gelesen und ein
wenig rumprobiert. Schon alles etwas gaga.
Insgesamt gibt es vier verschiedene UIDs. GIDs habe ich nicht
untersucht, wird wohl so ähnlich sein, höchstens noch etwas
komplizierter, weil es neben der primäre Gruppe noch andere Gruppen
geben kann.
Die /etc/passwd wird bei allen Systemaufrufen nicht berücksichtigt.
Es ist vollkommen ohne Belang, ob es den jeweiligen UID in der
/etc/passwd gibt, oder nicht.
Die vier UIDs sind:
Der reale UID kurz ruid.
Der effektive UID, kurz euid.
Der abgesicherte UID, kurz suid. Hat direkt nichts mit dem SUID-Bit
zu tun, wird aber leider allgemein so bezeichnet, für savedUID. Ich
habe es so belassen. Den Namen sollte man nicht allzuviel Bedeutung
bemessen.
Der fsuid, was immer das heißen mag.
Der Prozeß hat Superuserprivilegien, sobald der euid gleich 0 ist.
Die Rechte einer Datei werden anhand des fsuid ausgewertet. Hier
nützt die 0 im euid nichts, hier zählt nur der fsuid.
Wenn ein Prozeß gestartet wird, dann werden alle vier UIDs
beibehalten. Wenn das SUID-Bit gesetzt ist, so wird nur der ruid
beibehlaten. euid, suid und fsuid bekommen den UID der Datei, die
ausgeführt wird. Wenn diese Datei root gehört, so werden sie somit
auf 0 gesetzt. Insbesondere auch der euid.
Zur Veränderung der UIDs gibt es folgende Systemaufrufe:
setuid
seteuid
setresuid
setfsuid
setreuid
Zur Anzeige die folgende:
getuid
geteuid
getresuid
getuid und geteuid haben keine Argumente und geben den ruid, bzw.
den euid aus. getresuid bekommt als Argument drei Zeiger, in dem
ersten wird der ruid, im zweiten der euid und im dritten der suid
abgelegt.
Besonders schön ist es, daß es anscheinend keine Funktion gibt, die
den sfuid ausgibt.
Von den ganzen set-Funktionen verhält sich imho setresuid am
vernünftigsten. setresuid bekommt drei Argumente mit, die neuen
ruid, euid und suid. Wenn die Funktion erfolgreich war, wird eine 0
zurückgegeben, sonst eine -1 und errno wird gesetzt.
Wenn der bisherige euid 0 war, so darf alles mögliche gesetzt
werden. Ansonten darf alles gesetzt werden, was bisher in ruid, euid
und suid standen. Es darf alles gleich gesetzt werden, es darf auch
munter permutiert werden. Es kann somit sein, daß der neue ruid der
alte euid ist, der neue euid der alte suid und der neue suid der
alte ruid. Oder auch umgekehrt.
Wenn in einem der UIDs eine -1 gesetzt wird, dann wird der bisherige
UID beibehalten. Gilt so für alle drei UIDs. Wird der euid
verändert, so wird wie sonst auch immer der fsuid mit verändert.
Bemerkenswert ist, wenn der alte euid ungleich 0 ist, aber etwa der
alte ruid und/oder der alte suid gleich 0, so dürfen die UIDs
trotzdem nicht beliebig gesetzt werden, sondern nur aus der Auswahl
von ruid, euid und suid. Da da aber eine 0 dabei war, darf der euid
auf 0 gesetzt werden, und in einem nächsten Schritt darf dann
beliebig gesetzt werden.
Etwas merkwürdiger verhält sich die Funktion setuid. Falls der euid
ungleich 0 ist, wird der euid verändert, und wie immer, damit auch
der fsuid. Dies darf aber nur der bisherige ruid oder der bisherige
suid sein. Ansonsten gibt es einen Fehler. Dies gilt
merkwürdigerweise auch, wenn der neue euid gleich dem alten ist,
aber ungleich von ruid und suid.
Ganz anders verhält sich setuid, wenn der alte euid gleich 0 ist.
Dann werden alle vier UIDs auf dem Argument von setuid gesetzt, das
jetzt beliebig sein kann.
Ebenfalls merkwürdig verhält sich setreuid. setreuid hat zwei
Argumente. Das erste Argument ist der neue ruid, und das zweite der
neue euid. Wenn der alte euid gleich 0 ist, darf auch hier wieder
mal beliebig gesetzt werden. Ist der euid aber ungleich 0, so darf
der ruid nur auf dem alten ruid oder dem alten euid gesetzt werden,
der euid darf auf dem alten ruid oder dem alten euid oder dem alten
suid gesetzt werden. Der ruid darf aber nicht auf dem alten suid
gesetzt werden, wenn er nicht zufälligerweise gleich dem alten ruid
oder euid ist, oder der alte euid gleich 0. Auch hier wird der fsuid
auf dem neuen euid gesetzt.
Als wenn das nicht schon alles merkwürdig genug wäre, noch
merkwürdiger ist das Verhalten vom suid. Meist wird der suid auch
auf den Wert von euid gesetzt. Dies ist nicht der Fall, wenn der
ruid beibehalten wird, und der euid entweder ebenfalls beibehalten
wird (dann macht die Funktion aber rein gar nichts) oder aber wenn
der euid auf dem alten ruid gesetzt wird. Dann bleibt der alte suid
erhalten, ansonsten wird der suid auf dem neuen euid gesetzt.
Dabei bleibt der ruid und auch der euid beibehalten wenn im Argument
eine -1 steht. Wird der gleiche Wert gesetzt, auf dem der jeweilige
UID sowieso schon steht, so gilt das nicht als beibehalten und suid
wird trotzdem auf dem neuen euid gesetzt.
*heul*
seteuid (arg) soll laut manpage nichts anderes sein als
setreuid (-1, arg) Habe ich jetzt nicht überprüft. Daraus ergibt
sich, daß der ruid beibehalten wird, der suid dann beibehalten wird,
wenn der euid auf dem alten ruid gesetzt wird, ansonsten aber
ebenfalls auf dem neuen euid gesetzt wird.
Der fsuid wird immer verändert, wenn auch der euid verändert wird.
Die einzige Chance, daß da mal was anderes steht ist die Funktion
setfsuid. Diese Funktion hat als einziges Argument den Wert des
neuen fsuid und gibt als Rückgabewert den alten fsuid zurück. Und
zwar immer, auch im Fehlerfalle. Alle anderen Funktionen geben in
diesem Fall eine -1 zurück. Auch wird im Fehlerfall errno nicht
gesetzt. Mit anderen Worten: Es läßt sich nicht feststellen, ob ein
Fehler aufgetreten ist, oder nicht.
*schrei*
Wenn der euid 0 ist, so kann auch hier jeder Wert genommen werden.
Ansonsten ruid, euid oder suid.
Ich habe nicht alles überprüft, aber doch das meiste. Und irgendwie
ist mir jetzt schlecht. Weiß auch nicht, was das alles soll.
Wichtig ist der euid und der fsuid. Der ist aber sowieso immer der
gleiche wie der euid, solange setfsuid nicht angefaßt wird.
Bernd
--
ROTFL = Rolling On The Floor, Laughing = Auf dem Boden wälzen, lachend.
SCNR = Sorry, Could Not Resist = Sorry, Ich konte nicht wiederstehen.
AFAIK = As Far As I Know = So weit ich weis|BTW = By The Way = Nebenbei bemerkt
IMHO = In My Humble Opinion = meiner bescheidenen Meinung nach |Zufallssig. 9