Cómo cambiar una contraseña de usuario de Linux desde Python

Estoy teniendo problemas para cambiar la contraseña de un usuario de Linux desde python. He intentado muchas cosas, pero no pude resolver el problema, aquí está la muestra de cosas que ya he intentado:

sudo_password es la contraseña para sudo, sudo_command es el comando que quiero que ejecute el sistema, el usuario obtiene una lista y es el usuario para el que quiero cambiar la contraseña, y newpass es el pase que quiero asignar a “usuario”

user = list.get(ANCHOR) sudo_command = 'passwd' f = open("passwordusu.tmp", "w") f.write("%s\n%s" % (newpass, newpass)) f.close() A=os.system('echo -e %s|sudo -S %s < %s %s' % (sudo_password, sudo_command,'passwordusu.tmp', user)) print A windowpass.destroy() 

‘A’ es el valor de retorno para la ejecución de os.system, en este caso 256. Intenté también

  A=os.system('echo %s|sudo -S %s < %s %s' % (sudo_password, sudo_command,'passwordusu.tmp', user)) 

pero devuelve el mismo código de error. Intenté varias otras formas con el comando ‘passwd’, pero sin éxito. Con el comando ‘chpasswd’ he intentado esto:

  user = list.get(ANCHOR) sudo_command = 'chpasswd' f = open("passwordusu.tmp", "w") f.write("%s:%s" % (user, newpass)) f.close() A=os.system('echo %s|sudo -S %s < %s %s' % (sudo_password, sudo_command,'passwordusu.tmp', user)) print A windowpass.destroy() 

también con:

  A=os.system('echo %s|sudo -S %s:%s|%s' % (sudo_password, user, newpass, sudo_command)) @;which returns 32512 A=os.system("echo %s | sudo -S %s < \"%s\"" % (sudo_password, sudo_command, "passwordusu.tmp")) @;which returns 256 

Intenté ‘mkpasswd’ y ‘usermod’ también así:

  user = list.get(ANCHOR) sudo_command = 'mkpasswd -m sha-512' os.system("echo %s | sudo -S %s %s > passwd.tmp" % (sudo_password,sudo_command, newpass)) sudo_command="usermod -p" f = open('passwd.tmp', 'r') for line in f.readlines(): newpassencryp=line f.close() A=os.system("echo %s | sudo -S %s %s %s" % (sudo_password, sudo_command, newpassencryp, user)) @;which returns 32512 

pero, si vas a https://www.mkpasswd.net , hash el ‘newpass’ y sustituye a ‘newpassencryp’, devuelve 0, lo que teóricamente significa que salió bien, pero hasta ahora no cambia la contraseña.

He buscado en internet y stackoverflow este problema o algo similar y probé las soluciones expuestas, pero nuevamente, sin éxito.

Realmente apreciaría cualquier ayuda, y por supuesto, si necesita más información, estaré encantado de proporcionarla.

Gracias por adelantado.

Intente usar la opción ‘–stdin’ para el comando passwd en sus tuberías. Para citar de la página man:

     --stín
       Esta opción se utiliza para indicar que passwd debe leer el nuevo
       Contraseña de entrada estándar, que puede ser una tubería.

Otra opción, si su Linux tiene el comando usermod, como root (o vía sudo) puede establecer explícitamente la contraseña (encriptada) usando la opción ‘-p’.

versión basada en usermod :

 #!/usr/bin/env python from crypt import crypt from getpass import getpass from subprocess import Popen, PIPE sudo_password_callback = lambda: sudo_password # getpass("[sudo] password: ") username, username_newpassword = 'testaccount', '$2&J|5ty)*X?9+KqODA)7' # passwd has no `--stdin` on my system, so `usermod` is used instead # hash password for `usermod` try: hashed = crypt(username_newpassword) # use the strongest available method except TypeError: # Python < 3.3 p = Popen(["mkpasswd", "-m", "sha-512", "-s"], stdin=PIPE, stdout=PIPE, universal_newlines=True) hashed = p.communicate(username_newpassword)[0][:-1] # chop '\n' assert p.wait() == 0 assert hashed == crypt(username_newpassword, hashed) # change password p = Popen(['sudo', '-S', # read sudo password from the pipe # XXX: hashed is visible to other users 'usermod', '-p', hashed, username], stdin=PIPE, universal_newlines=True) p.communicate(sudo_password_callback() + '\n') assert p.wait() == 0 

Hoy me encontré con el mismo problema y escribí una envoltura simple alrededor del subprocess para llamar al comando passwd y alimentar la stdin con la nueva contraseña. Este código no es infalible y solo funciona cuando se ejecuta como root que no solicita la contraseña antigua.

 import subprocess from time import sleep PASSWD_CMD='/usr/bin/passwd' def set_password(user, password): cmd = [PASSWD_CMD, user] p = subprocess.Popen(cmd, stdin=subprocess.PIPE) p.stdin.write(u'%(p)s\n%(p)s\n' % { 'p': password }) p.stdin.flush() # Give `passwd` cmd 1 second to finish and kill it otherwise. for x in range(0, 10): if p.poll() is not None: break sleep(0.1) else: p.terminate() sleep(1) p.kill() raise RuntimeError('Setting password failed. ' '`passwd` process did not terminate.') if p.returncode != 0: raise RuntimeError('`passwd` failed: %d' % p.returncode) 

Si necesita la salida de passwd, también puede pasar stdout=subprocess.PIPE a la llamada de Popen y leer desde ella. En mi caso, solo estaba interesado si la operación tuvo éxito o no, así que simplemente me salté esa parte.

Consideración de seguridad: no use algo como echo -n 'password\npassword\n | passwd username' echo -n 'password\npassword\n | passwd username' ya que esto hará que la contraseña sea visible en la lista de procesos.

SUDO

Ya que desea utilizar sudo passwd recomendaría agregar una nueva línea a su /etc/sudoers (use visudo para eso!)

 some_user ALL = NOPASSWD: /usr/bin/passwd 

Sudo no solicitará la contraseña para some_user y la secuencia de comandos se ejecutará como se esperaba.

Alternativamente, simplemente agregue una línea extra p.stdin.write(u'%s\n' % SUDO_PASSWORD) . De ese modo, sudo recibirá primero la contraseña del usuario y luego passwd recibirá la nueva contraseña del usuario.

El usuario con el que está ejecutando esto debe tener permiso sudo para ejecutar el comando passwd sin una contraseña.

 >>> from subprocess import Popen >>> proc = Popen(['/usr/bin/sudo', '/usr/bin/passwd', 'test', '--stdin']) >>> proc.communicate('newpassword') 

Como se mencionó antes, pasar las contraseñas en la línea de comandos no es muy seguro, lamentablemente. Además, algo como ” --stdin ” para passwd no está disponible en todas las implementaciones de passwd . Por eso aquí hay una versión más segura usando chpasswd :

 def setPassword(userName:str, password:str): p = subprocess.Popen([ "/usr/sbin/chpasswd" ], universal_newlines=True, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = p.communicate(userName + ":" + password + "\n") assert p.wait() == 0 if stdout or stderr: raise Exception("Error encountered changing the password!") 

Explicación:

Con subprocess.Popen lanzamos una instancia de chpasswd . chpasswd el nombre de usuario y la contraseña a una instancia de chpasswd . chpasswd cambiará la contraseña utilizando la configuración definida para el sistema operativo actual. chpasswd permanecerá completamente en silencio si no se produce ningún error. Por lo tanto, el código anterior generará una excepción si se produce algún tipo de error (sin tener una mirada más cercana al error real).