Fordern Sie Root-Rechte innerhalb eines Skripts an

23

Ich habe ein Skript, das als sudo script.shoder ausgeführt werden kannpkexec script.sh

Aus Benutzersicht wäre es viel angenehmer, wenn das Skript den Benutzer nach dem Kennwort fragen würde, wenn es nur mit seinem Namen ausgeführt würde script.sh.

Wie kann ich eine Anforderung an das gesamte Skript "einbetten" pkexecoder sudoes mit Root-Rechten ausführen?

Beachten Sie, dass das Ausführen von Allem mit sudo sh -cmöglicherweise nicht die beste Lösung ist, da ich Funktionen im Skript habe.

Sergiy Kolodyazhnyy
quelle

Antworten:

55

Das wird funktionieren:

echo "$(whoami)"

[ "$UID" -eq 0 ] || exec sudo "$0" "$@"

Beispiel:

./test.sh 
blade
[sudo] password for blade: 
root
blade19899
quelle
3
Das Gute daran ist die Rekursion mit exec- sich selbst aufrufen, aber gleichzeitig den Prozess ersetzen, damit wir nicht mehrere Instanzen des Skripts
erzeugen
1
Rekursion zur Rettung !!! Erinnern Sie mich daran, in ein paar Tagen ein Kopfgeld zu diesem hinzuzufügen!
Fabby
6
Beachten Sie dabei die Eskalation der Rechte. Je mehr Befehle Sie als Root ausführen, desto mehr Möglichkeiten hat ein böswilliger Hacker, etwas auszunutzen, um auf ein Root-Konto zuzugreifen. Ich sage nicht, dass es immer falsch ist , das gesamte Skript als root auszuführen, aber es lohnt sich, ein wenig darüber nachzudenken, bevor Sie sich dazu entschließen. Ich denke, es wäre schön (wenn auch nicht notwendig), wenn die Antwort darauf etwas bewirken würde.
David Z
Wenn Sie in / etc / sudoers ein anständiges Zeitlimit festgelegt haben, können Sie sudo optional vor jeden Befehl im Skript stellen, der wirklich Root-Zugriff benötigt und nur einmal abgefragt wird. Eine Sache, die ich oft vermassle, ist, dass das Aufrufen eines solchen Skripts von einer GUI aus nicht funktioniert, da sudo / dev / null für die Passworteingabe erhält und fehlschlägt. Dafür wurden gksudo und kdesudo entwickelt, da sie die GUI verwenden, um nach dem Passwort zu fragen.
Joe
1
@ Coder256: Ich glaube nicht, dass deine Bearbeitung richtig war. "$@"wird auf mehrere Wörter erweitert, eines für jeden Parameter.
Jwodder
12

Wenn Sie einen schönen Dialog wünschen, versuchen Sie etwas davon. Ich habe dies direkt aus etwas herausgerissen, das ich geschrieben habe, damit es zusätzliche Dinge gibt, die Sie vielleicht nicht brauchen oder wollen, aber es zeigt die allgemeine Idee:

brand="My Software"

# Check that the script is running as root. If not, then prompt for the sudo
# password and re-execute this script with sudo.
if [ "$(id -nu)" != "root" ]; then
    sudo -k
    pass=$(whiptail --backtitle "$brand Installer" --title "Authentication required" --passwordbox "Installing $brand requires administrative privilege. Please authenticate to begin the installation.\n\n[sudo] Password for user $USER:" 12 50 3>&2 2>&1 1>&3-)
    exec sudo -S -p '' "$0" "$@" <<< "$pass"
    exit 1
fi

sudo dialog

Hierfür wird Whiptail verwendet, das Sie installieren können, wenn Sie es noch nicht haben:

sudo apt-get install whiptail
Michael Hampton
quelle
1
Warum speichern Sie das Passwort in einer Variablen?
Heemayl
10
Ruf nicht an exec echo [PASSWORD]! Es wird ein Prozess mit dem Kennwort in der Befehlszeile erzeugt, den jeder Benutzer sehen kann. Verwenden Sie entweder den eingebauten Befehl echo(erzwingen Sie die eingebaute Version mit builtin echo) oder den Bashismus <<<(wie folgt:) sudo ... <<< "$pass"; Sh und andere Shells haben hier Dokumente für diese Fälle. Geben Sie auch das Passwort an, falls es Sonderzeichen enthält.
David Foerster
Setzen Alternativ den whiptailBefehl in ein separates Skript und die Verwendung so etwas wie SUDO_ASKPASS=/path/to/askpass-with-whiptail.sh sudo -A -p "My password prompt" -- "$0" "$@"haben sudoprompt Deal mit dem benutzerdefinierten Kennwort ein .
David Foerster
@DavidFoerster Das könnte funktionieren, aber dann brauchen Sie entweder zwei Skripte oder Sie schreiben Ihr askpass-Skript in eine temporäre Datei und übergeben es dann an sudo.
Michael Hampton
Ok, aber andere haben bereits bemerkt, dass es unerwünscht ist, ein Passwort an eine Variable zu übergeben. Die Art und Weise, wie dies angegangen wird, besteht darin, die Ausgabe des Dialogs an die Named
Sergiy Kolodyazhnyy
11

Die Antwort von blade19899 ist in der Tat der richtige Weg, aber man könnte auch sudo bashden Shebang einschalten:

#!/usr/bin/sudo bash
# ...

Die offensichtliche Einschränkung ist, dass dies nur funktioniert, solange das Skript mit aufgerufen wird, ./scriptund fehlschlägt, sobald das Skript mit aufgerufen wird bash script.

kos
quelle
5
Dies ist einer der Gründe, warum Sie niemals bash scriptin die Befehlszeile eingeben sollten, um ein Skript aufzurufen. Wenn das Skript etwas anderes als bashdie #!Zeile angibt, schlägt der Aufruf mit bash scriptfehl. Wenn ich versuchen würde, ein Python-Skript mit bash script.pydiesem aufzurufen , würde dies ebenfalls fehlschlagen.
Kasperd
1
Sie können es jedoch mit ausführen perl script. Um wirklich nett zu sein, überprüft Perl die shebang-Zeile und führt das richtige Programm aus, wenn Perl nicht aufgerufen wird.
Tbodt
Das ist schlecht, weil es jeden Befehl im Skript mit sudo ausführt. Es ist besser, die wenigen Befehle, die sudo wirklich benötigen, zu isolieren und sie bei Bedarf hinzuzufügen. Beziehen Sie die Auswertung von Funktionen nicht in diese sudo-Aufrufe ein. Sie sollten so klar und minimal wie möglich sein.
Douglas Held
@DouglasHeld Auch wenn ich dem zustimmen kann, lautet die Frage: "Wie kann ich eine Anfrage an pkexec oder sudo" einbetten ", um das gesamte Skript mit Root-Rechten auszuführen?". Ziemlich sicher, dass es Anwendungsfälle geben würde, in denen dies nützlich wäre.
Kos
6

Ich stelle den Befehlen innerhalb des Skripts, die root-Zugriff benötigen, ein Vorwort voran sudo- wenn der Benutzer noch keine Berechtigungen erhalten hat, fordert das Skript an dieser Stelle zur Eingabe eines Kennworts auf.

Beispiel

#!/bin/sh 
mem=$(free  | awk '/Mem:/ {print $4}')
swap=$(free | awk '/Swap:/ {print $3}')

if [ $mem -lt $swap ]; then
    echo "ERROR: not enough RAM to write swap back, nothing done" >&2
    exit 1
fi

sudo swapoff -a && 
sudo swapon -a

Dieses Skript kann entweder als sudo <scriptname>oder als ausgeführt werden <scriptname>. In beiden Fällen werden Sie nur einmal nach dem Passwort gefragt.

Charles Green
quelle
2
Das Problem hierbei ist, dass möglicherweise mehrere Befehle Root-Zugriff benötigen. Dies bedeutet, sudodass 25 verschiedene Befehle redundant abgerufen werden müssen. Es ist einfacher, sudo einmal aufzurufen. In diesem Fall ruft Ihr Skript sudo jedoch nur einmal auf, weil sudo eine Zeit von 15 Minuten hat - Befehle, die länger dauern, müssen erneut eingegeben werden. Dein Weg funktioniert einfach. . . Nicht so, wie ich es brauche.
Sergiy Kolodyazhnyy
@ Serg Für ein kleines Skript war die Art und Weise, wie ich es hatte, schnell und einfach - ich bin wirklich kein eleganter Programmierer!
Charles Green
Sie sind der beste Programmierer auf dieser Seite. Sie verwenden sudo genau so, wie es verwendet werden sollte - nur bei Bedarf und mit sehr klaren Ergebnissen.
Douglas Held
4

Anscheinend hat hier niemand das offensichtliche Anliegen angesprochen. Das Einfügen sudoin Ihr Skript, das Sie dann verteilen, fördert schlechte Benutzergewohnheiten . (Ich gehe davon aus, dass Sie es verteilen, weil Sie "aus Sicht der Benutzer" erwähnen.)

Die Wahrheit ist, dass es bei der Verwendung von Anwendungen und Skripten eine Richtlinie gibt, die dem Sicherheitsprinzip im Bankwesen ähnelt: Geben Sie Ihre persönlichen Daten niemals an jemanden weiter, der Sie anruft und angibt, dass er "von Ihrer Bank aus" anruft , und die existiert aus ähnlichen Gründen.

Die Regel für Bewerbungen lautet:

Geben Sie niemals Ihr Passwort ein, wenn Sie dazu aufgefordert werden, es sei denn, Sie sind sich sicher, was damit geschehen soll. Dies gilt dreifach für jeden mit sudoZugang.

Wenn Sie Ihr Kennwort eingeben, weil Sie sudoüber die Befehlszeile ausgeführt wurden, ist das großartig. Wenn Sie es eingeben, weil Sie einen SSH-Befehl ausgeführt haben, ist das in Ordnung. Wenn Sie es eingeben, wenn Sie sich bei Ihrem Computer anmelden, ist das natürlich großartig.

Wenn Sie nur ein fremdes Skript oder eine ausführbare Datei ausführen und Ihr Kennwort nach Aufforderung nur zögerlich eingeben, wissen Sie nicht, wie das Skript damit umgeht . Soweit Sie wissen, kann es sein, dass es in einer temporären Datei im Klartext gespeichert wird und sich nicht selbst bereinigt.

Offensichtlich gibt es separate und zusätzliche Bedenken hinsichtlich der Ausführung unbekannter Befehle root, aber ich spreche hier davon, die Sicherheit des Kennworts selbst aufrechtzuerhalten . Selbst wenn die Anwendung / das Skript nicht böswillig ist, möchten Sie dennoch, dass Ihr Kennwort sicher gehandhabt wird, um zu verhindern, dass andere Anwendungen darauf zugreifen und es böswillig verwenden.

Meine persönliche Antwort darauf lautet also:

#!/bin/bash
[ "$UID" -eq 0 ] || { echo "This script must be run as root."; exit 1;}

# do privileged stuff, etc.
Platzhalter
quelle
Obwohl ich Ihnen vollkommen zustimme, ist ein Benutzer, der etwas ausführt, ohne zu wissen, was es tut, sudo script_namegenauso verwundbar wie es ist, dasselbe. Vielleicht fördert diese Idee schlechte Gewohnheiten - dazu werde ich nichts sagen. Aber der Schlüssel ist zu wissen, was ein Programm tut, und das ist die Verantwortung des Benutzers. Das ist die ganze Idee hinter Open-Source-Software. Wie für mein eigenes Skript, na ja. . . Ein Skript ist Klartext - Benutzer können es lesen, wenn sie wissen
möchten
@SergiyKolodyazhnyy es ist ähnlich, aber wenn Sie Ihr Passwort direkt in das Skript eingeben, ist es tatsächlich schlimmer. Ein mit sudo ausgeführtes Skript kennt Ihr Passwort immer noch nicht.
Wildcard
1

Ich habe es so gemacht:

echo -n "Enter password for sudo rights: "
read -s pass

echo $pass | sudo -S [your command here]
88weighed
quelle
4
Zitieren Sie zumindest Ihre Variablen.
muru
Und das Zitieren Ihrer Variablen hilft möglicherweise nicht einmal, wenn Ihr Passwort mit einem Bindestrich beginnt.
Wildcard