Diese Frage wurde in anderen Foren anders gestellt. Aber es gab keine anständige Erklärung, warum Sie das Folgende in Bash nicht tun können.
#!/bin/bash
command1
SWITCH_USER_TO rag
command2
command3
Normalerweise ist der vorgeschlagene Weg
#!/bin/bash
command1
sudo -u rag command2
sudo -u rag command3
Aber warum ist es nicht möglich bash
, irgendwann während der Ausführung des Bash-Skripts zu einem anderen Benutzer zu wechseln und den Rest der Befehle als anderer Benutzer auszuführen?
Antworten:
Die Informationen sind bereits in meiner anderen Antwort enthalten , aber sie sind dort etwas vergraben. Also dachte ich, ich würde es hier hinzufügen.
bash
Es ist nicht vorgesehen, Benutzer zu wechseln, dies ist jedoch derzsh
Fall.In
zsh
ändern Sie Benutzer, indem Sie diesen Variablen Werte zuweisen:$EUID
: Ändern Sie die effektive Benutzer-ID (und sonst nichts). Normalerweise können Sie Ihre EUID zwischen Ihrer tatsächlichen Benutzer-ID und der gespeicherten Set-Benutzer-ID ändern (wenn sie von einer ausführbaren Setuid-Datei aufgerufen wird) oder zu einer beliebigen ändern, wenn Ihre EUID 0 ist.$UID
: Ändern Sie die effektive Benutzer-ID, die tatsächliche Benutzer-ID und die gespeicherte Benutzer-ID auf den neuen Wert. Wenn dieser neue Wert nicht 0 ist, gibt es kein Zurück mehr. Da alle 3 auf denselben Wert eingestellt wurden, kann er nicht mehr geändert werden.$EGID
und$GID
: dasselbe, aber für Gruppen-IDs.$USERNAME
. Das ist wie mitsudo
odersu
. Es setzt Ihre euid, ruid, ssuid auf die uid dieses Benutzers. Außerdem werden die Gruppen egid, rgid und ssgid sowie die zusätzlichen Gruppen basierend auf den in der Benutzerdatenbank definierten Gruppenmitgliedschaften festgelegt. Wie für$UID
, es sei denn, Sie setzen$USERNAME
aufroot
, es gibt kein Zurück, aber wie für$UID
, können Sie den Benutzer nur für eine Subshell ändern.Wenn Sie diese Skripte als "root" ausführen:
Um den Benutzer wie in
sudo
oder zu ändernsu
, können wir dies nur mit Unterschalen tun, andernfalls können wir es nur einmal tun:quelle
Kernel Angebote
man 2 setuid
und Freunde.Jetzt funktioniert es beim Aufruf des Prozesses. Noch wichtiger ist, dass Sie Ihre Privilegien nicht erhöhen können. Deshalb
su
undsudo
SETUID - Bit gesetzt haben , so dass sie immer mit höchsten Privilegien ausführen (root
) und entsprechend gewünschten Benutzer löschen.Diese Kombination bedeutet, dass Sie die Shell-UID nicht ändern können, indem Sie ein anderes Programm ausführen, um dies zu tun (deshalb können Sie nicht erwarten,
sudo
dass ein anderes Programm dies tut), und Sie können es (als Shell) nicht selbst tun, es sei denn, Sie sind bereit, als root oder als derselbe Benutzer zu arbeiten, zu dem Sie wechseln möchten, was keinen Sinn ergibt. Darüber hinaus gibt es keinen Weg zurück, sobald Sie Berechtigungen fallen lassen.quelle
Nun, Sie könnten immer tun:
(ʘ‿ʘ)
Das begann zunächst als Witz, da es implementiert, was angefordert wird, obwohl es wahrscheinlich nicht genau wie erwartet ist, und praktisch nicht nützlich ist. Aber da es sich zu etwas entwickelt hat, das bis zu einem gewissen Grad funktioniert und ein paar nette Hacks beinhaltet, hier eine kleine Erklärung:
Wie Miroslav sagte , besteht die einzige Möglichkeit für einen nicht privilegierten Prozess, die UID zu ändern, darin, eine ausführbare Setuid-Datei auszuführen , wenn wir die Linux- Funktionen außer Acht lassen (was auch hier sowieso nicht wirklich hilfreich wäre).
Sobald Sie jedoch das Superuser-Privileg erhalten haben (indem Sie beispielsweise eine ausführbare Setuid-Datei ausführen, deren Eigentümer root ist), können Sie die effektive Benutzer-ID zwischen Ihrer ursprünglichen Benutzer-ID 0 und einer anderen ID hin und her wechseln, es sei denn, Sie geben Ihre gespeicherte Set-Benutzer-ID auf ( wie Dinge wie
sudo
oder in dersu
Regel tun).Zum Beispiel:
Jetzt habe ich einen
env
Befehl, mit dem ich jeden Befehl mit einer effektiven Benutzer-ID und einer gespeicherten Benutzer-ID von 0 ausführen kann (meine tatsächliche Benutzer-ID ist immer noch 1000):perl
hat Wrapper fürsetuid
/seteuid
(diese$>
und$<
Variablen).Zsh auch:
Obwohl oben diese
id
Befehle mit einer echten Benutzer-ID und einer gespeicherten Set-Benutzer-ID von 0 aufgerufen werden (obwohl, wenn ich meine./env
stattdessen verwendetsudo
hätte, nur die gespeicherte Set-Benutzer-ID gewesen wäre, während die echte Benutzer-ID 1000 geblieben wäre), was bedeutet, dass Wenn es sich um nicht vertrauenswürdige Befehle handelt, können sie dennoch Schaden anrichten. Schreiben Sie sie stattdessen wie folgt:(das heißt, alle UIDs (effektive, reale und gespeicherte Menge) nur für die Ausführung dieser Befehle.
bash
hat keine Möglichkeit, die Benutzer-IDs zu ändern. Selbst wenn Sie eine ausführbare setuid-Datei hätten, mit der Sie Ihrbash
Skript aufrufen könnten , würde dies nicht helfen.Mit
bash
bleibt Ihnen die Möglichkeit, jedes Mal, wenn Sie die UID ändern möchten, eine ausführbare Setuid-Datei auszuführen.Die Idee im obigen Skript besteht darin, SWITCH_TO_USER aufzurufen, um eine neue Bash-Instanz auszuführen und den Rest des Skripts auszuführen.
SWITCH_TO_USER someuser
ist mehr oder weniger eine Funktion, die das Skript erneut als anderer Benutzer ausführt (mitsudo
), aber den Start des Skripts bis überspringtSWITCH_TO_USER someuser
.Schwierig wird es, dass wir den Status der aktuellen Bash beibehalten möchten, nachdem wir die neue Bash als anderer Benutzer gestartet haben.
Lassen Sie es uns zusammenfassen:
Wir brauchen Aliase. Einer der Tricks in diesem Skript besteht darin, den Teil des Skripts bis zum zu überspringen
SWITCH_TO_USER someuser
, mit etwas wie:Dieses Formular ähnelt dem
#if 0
in C verwendeten, mit dem Sie Code vollständig auskommentieren können.:
ist ein No-Op, das true zurückgibt. So in: || :
dem zweiten:
wird nie ausgeführt. Es wird jedoch analysiert. Und das<< 'xxx'
ist eine Form des Here-Dokuments, bei dem (weilxxx
zitiert wird) keine Erweiterung oder Interpretation vorgenommen wird.Wir hätten tun können:
Aber das hätte bedeutet, dass das Here-Dokument geschrieben und als Standard übergeben werden müsste
:
.:||:
vermeidet das.Nun, wo es hacky wird, ist, dass wir die Tatsache verwenden, dass
bash
Aliase sehr früh in seinem Parsing-Prozess erweitert werden. Zu haben ,skip
ist ein Alias für den:||: << 'SWITCH_TO_USER someuther'
Teil des Kommentierung-out - Konstrukts.Lass uns weitermachen:
Hier ist die Definition der Funktion SWITCH_TO_USER . Wir werden unten sehen, dass SWITCH_TO_USER irgendwann ein Alias sein wird, der um diese Funktion gewickelt ist.
Diese Funktion führt den Großteil der erneuten Ausführung des Skripts aus. Am Ende sehen wir, dass es (im selben Prozess wegen
exec
)bash
mit der_x
Variablen in seiner Umgebung erneut ausgeführt wird (wir verwenden esenv
hier, weil essudo
normalerweise seine Umgebung bereinigt und es nicht erlaubt, beliebige env vars über zu übergeben). Dasbash
wertet den Inhalt dieses$_x
Variable als Bash - Code und Quellen Skript selbst._x
ist früher definiert als:Alle die
declare
,alias
,shopt -p
set +o
ein Abbild des inneren Zustands der Schale bilden ausgegeben. Das heißt, sie speichern die Definition aller Variablen, Funktionen, Aliase und Optionen als Shell-Code, der ausgewertet werden kann. Darüber hinaus fügen wir die Einstellung der Positionsparameter ($1
,$2
...) basierend auf dem Wert des$_a
Arrays hinzu (siehe unten) und einige Bereinigungen, damit die große$_x
Variable für die verbleibenden nicht in der Umgebung bleibt des Skripts.Sie werden feststellen, dass der erste Teil bis zu
set +x
in eine Befehlsgruppe eingeschlossen ist, deren stderr zu/dev/null
({...} 2> /dev/null
) umgeleitet wird . Das liegt daran, dass wir , wenn das Skriptset -x
(oderset -o xtrace
) irgendwann ausgeführt wird, nicht möchten, dass diese Präambel Spuren generiert, da wir sie so wenig aufdringlich wie möglich gestalten möchten. Wir führen also eine ausset +x
(nachdem wir zuvor sichergestellt haben, dass die Optionen (einschließlichxtrace
) Einstellungen gespeichert werden), in denen die Traces an / dev / null gesendet werden.Der
eval "$_X"
stderr wird aus ähnlichen Gründen auch nach / dev / null umgeleitet, aber auch, um die Fehler beim Schreiben in spezielle schreibgeschützte Variablen zu vermeiden.Fahren wir mit dem Skript fort:
Das ist unser oben beschriebener Trick. Beim ersten Skriptaufruf wird er abgebrochen (siehe unten).
Nun der Alias-Wrapper um SWITCH_TO_USER. Der Hauptgrund besteht darin, die Positionsparameter (
$1
,$2
...) an die neuen übergeben zu könnenbash
, die den Rest des Skripts interpretieren. Wir konnten es in derSWITCH_TO_USER
Funktion nicht tun, da sich innerhalb der Funktion"$@"
die Argumente für die Funktionen befinden, nicht die der Skripte. Die stderr-Umleitung nach / dev / null dient erneut zum Ausblenden von xtraces und zum Umgeheneval
eines Fehlersbash
. Dann rufen wir dieSWITCH_TO_USER
Funktion auf .Dieser Teil bricht den
skip
Alias ab (ersetzt ihn durch den:
Befehl no-op), sofern die$_u
Variable nicht festgelegt ist.Das ist unser
skip
Pseudonym. Beim ersten Aufruf wird es nur sein:
(das No-Op). Bei erneuten Aufrufen von Subsequenzen wird es so etwas wie ::||: << 'SWITCH_TO_USER root'
.Als Beispiel rufen wir an diesem Punkt das Skript als
root
Benutzer erneut auf, und das Skript stellt den gespeicherten Status wieder her, springt zu dieserSWITCH_TO_USER root
Zeile und fährt fort.Das bedeutet, dass es genau wie stat geschrieben werden muss, mit
SWITCH_TO_USER
am Anfang der Zeile und mit genau einem Leerzeichen zwischen den Argumenten.Der größte Teil von state, stdin, stdout und stderr bleibt erhalten, nicht jedoch die anderen Dateideskriptoren, da sie
sudo
normalerweise geschlossen werden, sofern dies nicht ausdrücklich so konfiguriert ist. Also zum Beispiel:wird normalerweise nicht funktionieren.
Beachten Sie außerdem Folgendes:
Das funktioniert nur, wenn Sie das Recht auf
sudo
asalice
undalice
das Recht aufsudo
asbob
undbob
as habenroot
.In der Praxis ist das also nicht wirklich nützlich. Die Verwendung von
su
anstelle vonsudo
(oder einersudo
Konfiguration, beisudo
der der Zielbenutzer anstelle des Anrufers authentifiziert wird) ist möglicherweise etwas sinnvoller, aber das würde immer noch bedeuten, dass Sie die Kennwörter all dieser Typen kennen müssen.quelle
ioshcc
? Sie sollten in nur einer Zeile tho eingegeben haben.Mit dem Befehl "sudo -u ram sh" können Sie zum Benutzer "ram" wechseln, indem Sie den Befehl "sh" oder shell ausführen. Mit dem Befehl "exit" kehren Sie zum ursprünglichen Benutzer zurück.
quelle