Warum führt "sudo su" in einem Shell-Skript den Rest des Skripts nicht als root aus?

36

Ein Beispielskript kann wie folgt aussehen:

#!/bin/bash
sudo su
ls /root

Wenn Sie ./test.shals normaler Benutzer arbeiten und stattdessen lsals Superuser ausführen und beenden, wird zu root gewechselt. und wenn ich mich abmelde, wird es ls /rootals normaler Benutzer ausgeführt.

Kann mir jemand etwas über den Mechanismus erzählen?

Hongxu Chen
quelle
13
sudo sumacht meine Augen weh.
Gelraen
Es wird verwendet, weil die Leute sudo nicht gut genug kennen und daher eine Möglichkeit benötigen, su auf Systemen auszuführen, auf denen root durch ein absichtlich beschädigtes Passwort geschützt ist. Aber ja sudo "redundiert" die Verwendung von su.
Johan
1
Kannst du das nicht einfach benutzen sudo -s?
Joe Z.
@Johan, ich benutze es oft, sudo suweil ich mehr an die Optionen von gewöhnt bin suals an die von sudo. Ich kenne die Optionen von sudo gut genug, aber ich kann die su-Optionen schneller eingeben. Aber ja, das heißt, ich kenne sudo nicht gut genug.
user606723
1
Ich habe gerade die sudo-Manpage durchgesehen. Es scheint sudo -iso, su -als sudo -sob es funktioniert wie su(ohne Bindestrich)
Johan

Antworten:

49

Die Befehle in einem Skript werden einzeln und unabhängig voneinander ausgeführt. Das Skript selbst ist als übergeordnetes Element aller Befehle im Skript ein weiterer unabhängiger Prozess, und der Befehl su ändert es nicht und kann es nicht in root ändern: Der Befehl su erstellt einen neuen Prozess mit Root-Rechten.

Nachdem der Befehl su ausgeführt wurde, führt der übergeordnete Prozess, der immer noch als derselbe Benutzer ausgeführt wird, den Rest des Skripts aus.

Sie möchten ein Wrapper-Skript schreiben. Die privilegierten Befehle gehen beispielsweise in das Hauptskript ein~/main.sh

#!/bin/sh
ls /root

Das Wrapper-Skript ruft das Hauptskript mit den folgenden Root-Berechtigungen auf

#!/bin/sh
su -c ~/main.sh root

Um diesen Prozess zu starten, führen Sie den Wrapper aus, der seinerseits das Hauptskript startet, nachdem der Benutzer zum Root-Benutzer gewechselt wurde.

Mit dieser Wrapper-Technik können Sie das Skript in einen Wrapper um sich selbst verwandeln. Überprüfen Sie im Allgemeinen, ob es als Root ausgeführt wird. Andernfalls verwenden Sie "su", um sich selbst neu zu starten.

$ 0 ist eine praktische Methode, um ein Skript auf sich selbst verweisen zu lassen, und der whoami-Befehl kann uns sagen, wer wir sind (sind wir root?)

So wird das Hauptskript mit eingebautem Wrapper

#!/bin/sh
[ `whoami` = root ] || exec su -c $0 root
ls /root

Beachten Sie die Verwendung von exec. Es bedeutet "dieses Programm ersetzen durch", wodurch die Ausführung effektiv beendet wird und das neue Programm, das von su mit root gestartet wurde, von oben ausgeführt wird. Die Ersetzungsinstanz ist "root", sodass sie nicht die rechte Seite des || ausführt

Johan
quelle
1
fwiw, ein nachtrag zu diesem punkt. Wenn ich ein Skript wie dieses schreiben würde, würde ich am Anfang nur eine if-Anweisung ausführen, die $ EUID prüft, und wenn es nicht null ist, sudo selbst und exit, andernfalls mit der Skriptausführung fortfahren.
Bratchley
Einverstanden, und ich werde die Antwort aktualisieren, um dies zu erklären.
Johan
2
Vielleicht ist es ein bisschen archaisch, aber ich liebe absolute Pfade zu jeder ausführbaren Datei, so dass jemand das Skript ~ / main.sh nicht in etwas Schändliches verwandeln kann. Angreifen des USER-Teils des Skripts
Artifex
2
Möglicherweise möchten Sie auch die Argumente
erfassen
@JoelDavis Ich stoße immer auf die Wand von "Was ist, wenn die Argumente Leerzeichen enthalten?". Ich habe noch nie eine zufriedenstellende Lösung gefunden. Einmal habe ich ein Skript geschrieben, das seine Argumente in eine temporäre Datei geschrieben hat, ein Argument pro Zeile. Dann habe ich aufgerufen, was immer es brauchte, und an dieses endgültige Skript das Argument übergeben, in welcher Datei nach den ursprünglichen Argumenten
Johan
20

Verwenden Sie im Skript Folgendes.

sudo su <<HERE
ls /root
HERE

Der Code zwischen dem HERE-Block wird als root ausgeführt.

Ankit
quelle
6
sudo suruft zwei Programme auf. Verwenden Sie sudo -s <<HEREDOCoder su user <<HEREDOC... Dumme 5-Minuten-Grenze.
Johan
6

Ohne weitere Argumente suwird die Login-Shell für root ausgeführt. Genau das macht die erste Zeile Ihres Skripts. Wenn Sie verlassen, um die Login - Shell schließen, so kehrt und Ihr Skript wird die Ausführung, die mit der zweiten Zeile ist: ls /root. Ich denke du kannst einfach sudo ls /rootmachen was du willst.

Bananguin
quelle
Ja, ich weiß, dass ich das tun kann ls, aber das ist nur ein Beispiel. Tatsächlich muss ich noch viel mehr mit Root-Rechten machen :-) Also bevorzuge ich die Antwort von @ Ankit.
Hongxu Chen
1

Sobald Sie sudo sueinen neuen Prozess mit dem Effekt " userid (euid=EUID)Super User Forked" starten, wird eine neue Bash mit einer anderen Prozess-ID ausgeführt (pid=PID), die demselben Terminal zugeordnet ist (tname=TTY).

Erläuterung

Angenommen, ps -A | grep bashSie haben nach dem Abfeuern eine 21460 pts/2 00:00:00 bashAusgabe. Jetzt, wenn Sie ./test.shbeide Befehle ausführen sudo suund ls /rootauf gespoolt werden PID 21460. Nach der Ausführung, wenn Sie rootals aktiver Benutzer ps -A | grep basherneut getroffen haben , wird eine neue Bash ausgeführt PID say, 21570. Das Beenden von beendet root bashdie neu gegabelte Bash user's bashund führt den Spool-Befehl aus, ls /rootbevor die Eingabeaufforderung freigegeben wird.

sundeep
quelle
Wenn su oder sudo in bash (oder anderswo) "persistent" wäre, würde dies viel mehr Probleme verursachen, als es gelöst hat. Sie müssen so wenig wie möglich als Root für Sicherheit und Schutz tun. Das Wichtigste bei su und sudo (außer Sicherheit!) Ist, dass Sie sich genau überlegen, welche Root-Rechte erforderlich sind.
Joe