Usando sudo con script en Python

Estoy intentando escribir un pequeño script para montar una carpeta compartida de VirtualBox cada vez que ejecuto el script. Quiero hacerlo con Python, porque estoy tratando de aprenderlo para scripting.

El problema es que necesito privilegios para iniciar el comando de assembly. Podría ejecutar el script como sudo, pero prefiero que lo haga el sudo por sí mismo.

Ya sé que no es seguro escribir su contraseña en un archivo .py, pero estamos hablando de una máquina virtual que no es crítica en absoluto: solo quiero hacer clic en el script .py y hacer que funcione.

Este es mi bash:

#!/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) 

Mi versión de python es 2.6

 sudoPassword = 'mypass' command = 'mount -t vboxsf myfolder /home/myuser/myfolder' p = os.system('echo %s|sudo -S %s' % (sudoPassword, command)) 

Intenta esto y hazme saber si funciona. 🙂

Y éste:

os.popen("sudo -S %s"%(command), 'w').write('mypass')

Muchas respuestas se centran en cómo hacer que su solución funcione, mientras que muy pocas sugieren que su solución sea un enfoque muy malo . Si realmente quiere “practicar para aprender”, ¿por qué no practicar el uso de buenas soluciones? ¡Codificar tu contraseña está aprendiendo el enfoque equivocado !

Si lo que realmente quieres es un mount contraseña para ese volumen, ¡tal vez no se necesite sudo en absoluto ! Entonces, ¿puedo sugerir otros enfoques?

  • Use /etc/fstab como mensi sugirió. Use las opciones user y noauto para permitir que los usuarios normales monten ese volumen.

  • Use Polkit para acciones sin contraseña: configure un archivo .policy para su script con yes y yes en /usr/share/polkit-1/actions

  • Edite /etc/sudoers para permitir que su usuario use sudo sin escribir su contraseña.

Todo lo anterior permite el privilegio de root sin contraseña, ninguno requiere que codifique su contraseña. Elige cualquier enfoque y puedo explicarlo con más detalle.

En cuanto a por qué es una muy mala idea para las contraseñas de código duro, aquí hay algunos buenos enlaces para leer más:

Para pasar la contraseña a la entrada 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] 

Nota: probablemente podría configurar sudo sin contraseña o el comando SUDO_ASKPASS lugar de codificar su contraseña en el código fuente.

subprocess.Popen crea un proceso y abre canalizaciones y cosas. Lo que estás haciendo es:

  • Iniciar un proceso sudo -S
  • Iniciar un proceso mypass
  • Iniciar un proceso de mount -t vboxsf myfolder /home/myuser/myfolder

Lo que obviamente no va a funcionar. Necesitas pasar los argumentos a Popen. Si observa su documentación , notará que el primer argumento es en realidad una lista de los argumentos.

  • Use la opción -S en el comando sudo que le dice que lea la contraseña desde ‘stdin’ en lugar del dispositivo terminal.

  • Dile a Popen que lea la entrada estándar de PIPE.

  • Envíe la contraseña a la PIPE estándar del proceso usándola como un argumento para comunicar el método. No olvide agregar un nuevo carácter de línea, ‘\ n’, al final de la contraseña.

 sp = Popen(cmd , shell=True, stdin=PIPE) out, err = sp.communicate(_user_pass+'\n') 

Por favor intente módulo pexpect. Aquí está mi código:

 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 !") 

Para limitar lo que corres como sudo, puedes correr

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

sin necesidad de almacenar la contraseña. El parámetro -E pasa el env de su usuario actual al proceso. Tenga en cuenta que su shell tendrá privilegios de sudo después del segundo comando, ¡así que use con precaución!

A veces se requiere un retorno de carro:

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

Sé que siempre es preferible no codificar la contraseña de sudo en el script. Sin embargo, por alguna razón, si no tiene permiso para modificar /etc/sudoers o cambiar el propietario del archivo, Pexpect es una alternativa viable.

Aquí hay una función de Python sudo_exec para su referencia:

 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 

Utilicé esto para python 3.5. Lo hice usando el módulo de subproceso. Usar una contraseña como esta es muy inseguro .

El módulo de subproceso toma el comando como una lista de cadenas, así que cree una lista de antemano utilizando split () o pase la lista completa más tarde. Lea la documentación para más información.

 #!/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()