sudo in nicht interaktivem Skript

9

Ich habe ein Skript, das drei Funktionen ausführt : A && B && C.

Die Funktion Bmuss als Superuser ausgeführt werden, während Aund Cnicht.

Ich habe mehrere Lösungen, aber keine davon ist zufriedenstellend:

  1. sudo das gesamte Skript: sudo 'A && B && C'

    Das scheint eine schlechte Idee zu sein Aund Cals Superuser, wenn es nicht benötigt wird

  2. Machen Sie das Skript interaktiv: A && sudo B && C

    Möglicherweise muss ich mein Passwort eingeben, aber ich möchte, dass mein Skript nicht interaktiv ist, da jede Funktion einige Zeit in Anspruch nehmen kann und ich nicht möchte, dass das Skript auf mich wartet. Nun, das ist auch der Grund, warum es überhaupt ein Skript ist, also muss ich nicht zusehen, wie es läuft.

  3. Die blöde Lösung: sudo : && A && sudo -n B && C

    Zuerst scheint es dumm, zuerst ein No-Op zu machen sudo, und ich muss auch die Daumen drücken, dass A nicht mehr als dauern wird $sudo_timeout.

  4. Hypothetische Lösung (ich wünschte, Sie würden mir sagen, dass es existiert):

    sudo --store-cred 'A && sudo --use-cred-from-parent-sudo B && C'

    Das würde zu Beginn nach meinem Passwort fragen und diese Anmeldeinformationen dann nur bei Bedarf verwenden.

Was ist deine Meinung zu all dem? Ich wäre sehr überrascht, dass es keine Lösung für dieses Problem gibt, da ich denke, dass es ein ziemlich häufiges Problem ist (was ist mit make all && sudo make install) ?

Antoine Pelisse
quelle
3
Sie können ein Skript erstellen, das Sie mit sudo ausführen, aber im Skript führen Sie die Aund CTeile explizit mit aus su -l some_non_priviliged_user. Keine Timeout-Probleme und keine Privilegien für A und C. Ich denke nicht, dass 4 möglich ist, sudoscheint ein "globaler Zustand" für einen Benutzer zu sein.
Anthon

Antworten:

7

Ich denke, das Beste, was Sie tun können, ist, das Skript mit zu sudostarten und dann die Prozesse zu starten, die Sie als normaler Benutzer explizit mit su useroder ausführen möchten sudo -u user:

#!/usr/bin/env bash

## Detect the user who launched the script
usr=$(env | grep SUDO_USER | cut -d= -f 2)

## Exit if the script was not launched by root or through sudo
if [ -z $usr ] && [ $USER = "root" ]
then
    echo "The script needs to run as root" && exit 1
fi

## Run the job(s) that don't need root
sudo -u $usr commandA

## Run the job that needs to be run as root
commandB
terdon
quelle
9

Fügen Sie der /etc/sudoersDatei Ihr Skript mit dem NOPASSWDAttribut hinzu, damit es ausgeführt werden kann, ohne dass Sie zur Eingabe eines Kennworts aufgefordert werden. Sie können dies an einen bestimmten Benutzer (oder eine Gruppe von Benutzern) binden oder zulassen, dass es sudovon jedem auf Ihrem System ausgeführt wird.

Eine Beispielzeile für ein Skript mit dem Namen /usr/local/bin/bossykönnte ungefähr so ​​aussehen

ALL ALL = (root) NOPASSWD: /usr/local/bin/bossy

Und dann würden Sie so etwas verwenden

A && sudo bossy && C

Für dieses Beispiel habe ich PATHIncludes angenommen /usr/local/bin. Wenn nicht, verwenden Sie einfach den vollständigen Pfad zum Skript, dhsudo /usr/local/bin/bossy

Roaima
quelle
Upvote für den sichersten Ansatz.
eyoung100
0

Möglicherweise möchten Sie die !requirettyOption sowohl in sudoals auch in der NOPASSWDOption verwenden. Beachten Sie jedoch, dass dies die Sicherheit verringert.

Steve Wills
quelle
1
Da das Problem nicht will das Skript definiert ist interaktiv sein, # 2 mit /etc/sudoersBefehlseingabe für den Benutzer auszuführen , Bmit NOPASSWDist die richtige Antwort.
Andrew
Das ist "Sie könnten X oder Y machen", es war "Sie könnten X und Y machen". Nur beide lösen das Problem. Vielleicht sollte ich meine Antwort umformulieren.
Steve Wills
0

Aufbauend auf meiner Antwort auf die Vorautorisierung von sudo? (Damit es später ausgeführt werden kann) , schreiben Sie zwei Skripte:

  • ABC_script::

    #!/bin/sh
    sudo -b ./B_script
    A  &&  > A_is_done
    while [ ! -f B_is_done ]
    do
            sleep 60
    done
    rm -f B_is_done
    C
  • B_script::

    #!/bin/sh
    while [ ! -f A_is_done ]
    do
            sleep 60
    done
    rm -f A_is_done
    B  &&  > B_is_done

Ausführen ./ABC_script:

  • Es wird laufen sudo -b ./B_script. Dies fragt nach dem Passwort ( unmittelbar nach dem Ausführen ABC_script). Unter der Annahme , dass das richtige Passwort eingegeben wird, erzeugt er B_scriptin dem b ackground (weil -bals Root angegeben wurde). Dies scheint gleichbedeutend zu sein sudo sh -c "./B_script &".
  • B_scriptwird parallel zu asynchron ausgeführt ABC_scriptB_scriptprüft auf das Vorhandensein einer aufgerufenen Datei A_is_done und führt eine Schleife durch, bis sie angezeigt wird.
  • Parallel ABC_scriptläuft A. Wenn / wenn der AVorgang erfolgreich abgeschlossen wurde, erstellt das Skript eine Datei mit dem Namen A_is_done.
  • ABC_scriptAnschließend wird geprüft, ob eine aufgerufene Datei vorhanden ist, B_is_done und es werden Schleifen ausgeführt, bis sie angezeigt wird.
  • B_scriptErkennt parallel das Vorhandensein von A_is_doneund bricht aus der Schleife aus. Es löscht die A_is_doneDatei und wird ausgeführt B. Denken Sie daran, B_scriptwird als root ausgeführt, sodass es Bals root ausgeführt wird. Wenn / wenn der BVorgang erfolgreich abgeschlossen wurde, erstellt das Skript eine aufgerufene Datei B_is_doneund wird beendet.
  • ABC_scriptErkennt parallel das Vorhandensein von B_is_doneund bricht aus der Schleife aus. Es löscht die B_is_doneDatei. Denken Sie daran, dass es B_scriptals root ausgeführt wurde, also B_is_doneim Besitz von root ist und Sie es verwenden möchten, um rm -fzu vermeiden, dass Sie eine Bestätigungsanforderung erhalten. ABC_scriptläuft dann Cund geht.

Hinweise zur weiteren Verfeinerung:

  • ABC_scriptsollte wahrscheinlich B_scripteher auf einem absoluten Pfad laufen als ./.
  • Anstatt A_is_doneund B_is_done, ABC_scriptsollte wahrscheinlich zufällig, eindeutige Dateinamen generieren.
  • Es muss eine Bestimmung vorhanden sein, damit das Skript, das auf das Warten wartet, benachrichtigt wird, wenn das Programm, auf das es wartet, beendet wurde, aber fehlgeschlagen ist. (Im Moment, wenn dies Afehlschlägt, gehen beide Skripte einfach in eine Endlosschleife.) Dies kann so einfach wie das Ändern sein

    A  &&  > A_is_done

    zu

    A; echo $? > A_is_done

    Ändern Sie anschließend die Spin-Waits, um die X_is_doneDateien zu lesen , und fahren Sie fort, wenn sie 0 enthalten, und beenden Sie sie anderweitig.

Scott
quelle
-3

Sei dumm. benutze viele Zeilen.

if A; then

    if sudo B ; then
        C
    fi
fi
Robert Jacobs
quelle
Wie löst das meine Bedenken? Das Problem hat nichts damit zu tun&&
Antoine Pelisse
&& stoppt die Ausführung, wenn der erste Befehl fehlschlägt. Die if-Anweisungen tun dies ausführlicher. Mein Ziel ist es, Ihre Arbeit zu erledigen, auch wenn sie nicht schön ist.
Robert Jacobs
1
Dies ist nichts weiter als eine ausführlichere Version von Option 2 : A && sudo B && C. Genau wie Antoine in der Frage erklärt; Dies fragt nicht nach dem Passwort, bis Aes fertig ist, und er möchte nicht darauf warten müssen oder das Skript auf ihn warten lassen.
Scott