sudo dans un script non interactif

9

J'ai un script qui exécute trois fonctions: A && B && C.

La fonction Bdoit être exécutée en tant que super-utilisateur, tandis que Aet Cnon.

J'ai plusieurs solutions mais aucune n'est satisfaisante:

  1. sudo le script entier: sudo 'A && B && C'

    Cela semble être une mauvaise idée à exécuter Aet en Ctant que super-utilisateur si ce n'est pas nécessaire

  2. rendre le script interactif: A && sudo B && C

    Je devrai peut-être taper mon mot de passe, mais je veux que mon script ne soit pas interactif, car chaque fonction peut prendre un certain temps, et je ne veux pas que le script m'attende. Eh bien, c'est aussi pourquoi c'est un script en premier lieu, donc je n'ai pas à le regarder fonctionner.

  3. La solution stupide: sudo : && A && sudo -n B && C

    D'abord, il semble stupide de sudocommencer par un no-op en premier, et je dois aussi croiser le doigt que A ne va pas en prendre plus $sudo_timeout.

  4. Solution hypothétique (j'aimerais que vous me disiez qu'elle existe):

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

    Cela demanderait mon mot de passe au début, puis n'utiliserait ces informations d'identification qu'en cas de besoin.

Quelle est votre opinion sur tout cela? Je serais très surpris qu'il n'y ait pas de solution à ce problème, car je pense que c'est un problème assez courant (qu'en est-il make all && sudo make install)

Antoine Pelisse
la source
3
Vous pouvez créer un script que vous exécutez avec sudo, mais dans le script, exécutez explicitement les parties Aet . Pas de problèmes de timeout, et pas de privilèges pour A et C. Je ne pense pas que 4 soit possible, semble un "état global" pour un utilisateur. Csu -l some_non_priviliged_usersudo
Anthon

Réponses:

7

Je pense que la meilleure chose que vous pouvez faire est de lancer le script avec sudopuis de lancer explicitement les processus que vous souhaitez exécuter en tant qu'utilisateur normal avec su userou 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
la source
9

Ajoutez votre script au /etc/sudoersfichier avec l' NOPASSWDattribut, afin qu'il puisse s'exécuter sans demander de mot de passe. Vous pouvez lier cela à un utilisateur spécifique (ou à un ensemble d'utilisateurs), ou autoriser son exécution sudopar n'importe qui sur votre système.

Un exemple de ligne pour un script appelé /usr/local/bin/bossypourrait ressembler à ceci

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

Et vous utiliseriez alors quelque chose comme ça

A && sudo bossy && C

Pour cet exemple, je suppose que PATHcomprend /usr/local/bin. Sinon, utilisez simplement le chemin complet du script, c.-à-d.sudo /usr/local/bin/bossy

roaima
la source
Upvote pour l'approche la plus sécurisée.
eyoung100
0

Vous souhaiterez peut-être utiliser l' !requirettyoption dans sudoainsi que l' NOPASSWDoption. Mais gardez à l'esprit que cela réduit la sécurité.

Steve Wills
la source
1
Comme le problème est défini comme ne voulant pas le script pour être interactif, # 2 avec /etc/sudoersentrée pour l'utilisateur d'exécuter la commande Bavec NOPASSWDest la bonne réponse.
Andrew
C'est "vous pourriez faire X ou Y", c'était "vous pourriez faire X et Y". Seuls les deux résoudront le problème. Je devrais peut-être reformuler ma réponse.
Steve Wills
0

S'appuyant sur ma réponse pour pré-autoriser sudo? (Pour qu'il puisse être exécuté plus tard) , écrivez deux scripts:

  • 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

Exécuter ./ABC_script:

  • Cela fonctionnera sudo -b ./B_script. Cela vous demande le mot de passe ( immédiatement après avoir exécuté ABC_script). En supposant que le mot de passe correct est entré, il apparaît B_scriptdans le b ackground (car il a -bété spécifié) en tant que root. Cela semble être équivalent à sudo sh -c "./B_script &".
  • B_scriptdémarre en mode asynchrone, en parallèle avec ABC_scriptB_scriptteste l'existence d'un fichier appelé A_is_done et boucle jusqu'à ce qu'il apparaisse.
  • En parallèle, ABC_scripts'exécute A. Si / quand se Atermine avec succès, le script crée un fichier appelé A_is_done.
  • ABC_scriptteste ensuite l'existence d'un fichier appelé B_is_done et boucle jusqu'à ce qu'il apparaisse.
  • En parallèle, B_scriptdétecte l'existence A_is_doneet sort de la boucle. Il supprime le A_is_donefichier et s'exécute B. N'oubliez pas, B_scripts'exécute en tant que root, il s'exécute donc en Btant que root. Si / quand se Btermine avec succès, le script crée un fichier appelé B_is_doneet se ferme.
  • En parallèle, ABC_scriptdétecte l'existence B_is_doneet sort de la boucle. Il supprime le B_is_donefichier. N'oubliez pas, B_scriptexécuté en tant que root, il B_is_doneappartient donc à root et vous souhaitez l'utiliser rm -fpour éviter d'obtenir une demande de confirmation. ABC_scriptpuis court Cet sort.

Notes à affiner:

  • ABC_scriptdevrait probablement fonctionner B_scriptpar un chemin absolu plutôt que ./.
  • Plutôt que A_is_doneet B_is_done, ABC_scriptdevrait probablement générer des noms de fichiers aléatoires et uniques.
  • Il doit y avoir une disposition pour que le script en attente de rotation soit notifié si le programme qu'il attend est terminé mais a échoué. (En ce moment, en cas d' Aéchec, les deux scripts entrent simplement dans une boucle d'attente infinie.) Cela pourrait être aussi simple que de changer

    A  &&  > A_is_done

    à

    A; echo $? > A_is_done

    puis en modifiant les spin-waits pour lire les X_is_donefichiers, et continuez s'il contient 0 et quittez sinon.

Scott
la source
-3

Soyez stupide. utilisez plusieurs lignes.

if A; then

    if sudo B ; then
        C
    fi
fi
Robert Jacobs
la source
comment cela résout-il mes préoccupations? Le problème n'a rien à voir avec&&
Antoine Pelisse
&& arrête l'exécution lorsque la première commande échoue. Les instructions if le font plus verbalement. Mon but est de faire votre travail, même si ce n'est pas joli.
Robert Jacobs
1
Ceci est rien de plus qu'une version plus détaillée de l' option 2: A && sudo B && C. Tout comme Antoine l'explique dans la question; cela ne demande pas le mot de passe jusqu'à ce qu'il Asoit terminé, et il ne veut pas avoir à attendre cela, ni faire attendre le script.
Scott