web-dev-qa-db-fra.com

Utiliser Sudo avec un script Python

J'essaie d'écrire un petit script pour monter un dossier partagé VirtualBox chaque fois que j'exécute le script. Je veux le faire avec Python, parce que j'essaie de l'apprendre pour le script.

Le problème est que j'ai besoin de privilèges pour lancer la commande mount. Je pourrais exécuter le script en tant que Sudo, mais je préfère le faire par lui-même.

Je sais déjà qu'il n'est pas sûr d'écrire votre mot de passe dans un fichier .py, mais nous parlons d'une machine virtuelle qui n'est pas du tout critique: je veux simplement cliquer sur le script .py et le faire fonctionner.

Ceci est ma tentative:

#!/usr/bin/env python
import subprocess

sudoPassword = 'mypass'
command = 'mount -t vboxsf myfolder /home/myuser/myfolder'

subprocess.Popen('Sudo -S' , Shell=True,stdout=subprocess.PIPE)
subprocess.Popen(sudoPassword , Shell=True,stdout=subprocess.PIPE)
subprocess.Popen(command , Shell=True,stdout=subprocess.PIPE)

Ma version de python est 2.6

28
Roman Rdgz

Beaucoup de réponses se concentrent sur la façon de faire fonctionner votre solution, alors que très peu suggèrent que votre solution est une très mauvaise approche}. Si vous voulez vraiment "pratiquer pour apprendre", pourquoi ne pas vous entraîner à utiliser de bonnes solutions? Le codage en dur de votre mot de passe permet d’apprendre l’approche mal!

Si vous voulez vraiment une mount sans mot de passe pour ce volume, peut-être que Sudo n'est pas nécessaire du tout! Alors, puis-je suggérer d'autres approches?

  • Utilisez /etc/fstab comme mensi suggéré. Utilisez les options user et noauto pour permettre aux utilisateurs normaux de monter ce volume.

  • Utilisez Polkit pour les actions sans mot de passe: Configurez un fichier .policy pour votre script avec <allow_any>yes</allow_any> et déposez-le à /usr/share/polkit-1/actions

  • Éditez /etc/sudoers pour permettre à votre utilisateur d'utiliser Sudo sans saisir votre mot de passe.

Tout ce qui précède autorise les privilèges root sans mot de passe, aucun ne vous oblige à coder en dur votre mot de passe. Choisissez n'importe quelle approche et je peux l'expliquer plus en détail.

En ce qui concerne pourquoi c'est une très mauvaise idée de coder en dur les mots de passe, voici quelques liens utiles à la lecture:

40
MestreLion

Pour passer le mot de passe à la variable stdin de Sudo:

#!/usr/bin/env python
from subprocess import Popen, PIPE

Sudo_password = 'mypass'
command = 'mount -t vboxsf myfolder /home/myuser/myfolder'.split()

p = Popen(['Sudo', '-S'] + command, stdin=PIPE, stderr=PIPE,
          universal_newlines=True)
Sudo_Prompt = p.communicate(Sudo_password + '\n')[1]

Remarque: vous pouvez probablement configurer la commande Sudo ou Sudo_ASKPASS sans mot de passe au lieu de coder en dur votre mot de passe dans le code source.

16
jfs
  • Utilisez l'option -S dans la commande Sudo qui indique de lire le mot de passe à partir de 'stdin' à la place du terminal.

  • Dites à Popen de lire stdin de PIPE.

  • Envoyez le mot de passe au PIP stdin du processus en l’utilisant comme argument pour communiquer avec la méthode. N'oubliez pas d'ajouter un nouveau caractère de ligne, '\ n', à la fin du mot de passe.

sp = Popen(cmd , Shell=True, stdin=PIPE)
out, err = sp.communicate(_user_pass+'\n')   
3
Hubert Vijay

subprocess.Popen crée un processus et ouvre des pipes et des choses. Ce que vous faites est:

  • Démarrer un processus Sudo -S
  • Démarrer un processus mypass
  • Démarrer un processus mount -t vboxsf myfolder /home/myuser/myfolder

ce qui ne va évidemment pas au travail. Vous devez passer les arguments à Popen. Si vous regardez sa documentation , vous remarquerez que le premier argument est en fait une liste d'arguments.

3
mensi

S'il vous plaît essayer le module pexpect. Voici mon code:

import pexpect
remove = pexpect.spawn('Sudo dpkg --purge mytool.deb')
remove.logfile = open('log/expect-uninstall-deb.log', 'w')
remove.logfile.write('try to dpkg --purge mytool\n')
if remove.expect(['(?i)password.*']) == 0:
    # print "successfull"
    remove.sendline('mypassword')
    time.sleep(2)
    remove.expect(pexpect.EOF,5)
else:
    raise AssertionError("Fail to Uninstall deb package !")
1
user2951688

Pour limiter ce que vous utilisez en tant que Sudo, vous pouvez exécuter

python non_Sudo_stuff.py
Sudo -E python -c "import os; os.system('Sudo echo 1')"

sans avoir besoin de stocker le mot de passe. Le paramètre -E transmet l'env de votre utilisateur actuel au processus. Notez que votre Shell aura des privilèges Sudo après la deuxième commande, donc utilisez avec prudence!

1
crizCraig

nécessite parfois un retour de voiture: 

os.popen("Sudo -S %s"%(command), 'w').write('mypass\n')
0
user2095717

Je sais qu'il est toujours préférable de ne pas coder en dur le mot de passe Sudo dans le script. Cependant, pour une raison quelconque, si vous n’avez pas l’autorisation de modifier /etc/sudoers ou de changer le propriétaire du fichier, Pexpect est une alternative réalisable.

Voici une fonction Python Sudo_exec pour votre référence:

import platform, os, logging
import subprocess, pexpect

log = logging.getLogger(__name__)

def Sudo_exec(cmdline, passwd):
    osname = platform.system()
    if osname == 'Linux':
        Prompt = r'\[Sudo\] password for %s: ' % os.environ['USER']
    Elif osname == 'Darwin':
        Prompt = 'Password:'
    else:
        assert False, osname

    child = pexpect.spawn(cmdline)
    idx = child.expect([Prompt, pexpect.EOF], 3)
    if idx == 0: # if prompted for the Sudo password
        log.debug('Sudo password was asked.')
        child.sendline(passwd)
        child.expect(pexpect.EOF)
return child.before
0
Jeremy Kao

Je l'ai utilisé pour Python 3.5. Je l'ai fait en utilisant SOUS-PROCESSUS module.L'utilisation du mot de passe comme ceci est très non sécurisé.

Le module sous-processus prend la commande en tant que liste de chaînes. Vous devez donc créer une liste au préalable à l'aide de split () ou transmettre la liste complète ultérieurement. Lisez la documentation pour plus d'informations.

#!/usr/bin/env python
import subprocess

sudoPassword = 'mypass'
command = 'mount -t vboxsf myfolder /home/myuser/myfolder'.split()

cmd1 = subprocess.Popen(['echo',sudoPassword], stdout=subprocess.PIPE)
cmd2 = subprocess.Popen(['Sudo','-S'] + command, stdin=cmd1.stdout, stdout=subprocess.PIPE)

output = cmd2.stdout.read.decode()
0
Nandesh