4

我在从 python 更改 Linux 用户密码时遇到问题。我已经尝试了很多东西,但我无法解决这个问题,这是我已经尝试过的示例:

sudo_password 是 sudo 的密码,sudo_command 是我希望系统运行的命令,用户是从列表中获取的,是我要更改密码的用户,newpass 是我要分配给“用户”的密码

    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' 是执行 os.system 的返回值,在本例中为 256。我也试过

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

但它返回相同的错误代码。我用“passwd”命令尝试了其他几种方法,但都没有成功。使用“chpasswd”命令我试过这个:

    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()

还有:

    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

我也像这样尝试了“mkpasswd”和“usermod”:

    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

但是,如果您访问https://www.mkpasswd.net,对“newpass”进行哈希处理并替换为“newpassencryp”,它会返回 0,这在理论上意味着它已经正确,但到目前为止它并没有更改密码。

我已经在互联网和 stackoverflow 上搜索了这个问题或类似问题,并尝试了暴露的解决方案,但同样没有成功。

我真的很感激任何帮助,当然,如果您需要更多信息,我很乐意提供!

提前致谢。

4

6 回答 6

4

运行此命令的用户必须具有 sudo 权限才能在passwd没有密码的情况下运行该命令。

>>> from subprocess import Popen
>>> proc = Popen(['/usr/bin/sudo', '/usr/bin/passwd', 'test', '--stdin'])
>>> proc.communicate('newpassword')
于 2012-11-01T20:28:23.170 回答
3

尝试对管道中的 passwd 命令使用“--stdin”选项。引用手册页:

    --stdin
      此选项用于指示 passwd 应该读取新的
      来自标准输入的密码,可以是管道。

另一种选择,如果您的 Linux 有 usermod 命令,作为 root(或通过 sudo),您可以使用“-p”选项显式设置(加密)密码。

于 2012-11-01T16:52:08.663 回答
2

我今天遇到了同样的问题,我写了一个简单的包装器subprocess来调用passwd命令并stdin输入新密码。此代码不是万无一失的,仅在以不提示输入旧密码的 root 身份运行时才有效。

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)

如果您需要 passwd 的输出,您也可以传递stdout=subprocess.PIPEPopen调用并从中读取。就我而言,我只对操作是否成功感兴趣,所以我只是跳过了那部分。

安全考虑:不要使用类似的东西,echo -n 'password\npassword\n | passwd username'因为这会使密码在进程列表中可见。

须藤

既然你想使用sudo passwd <username>我建议你添加一个新行/etc/sudoersvisudo用于那个!)

some_user ALL = NOPASSWD: /usr/bin/passwd

Sudo 不会询问密码,some_user脚本将按预期运行。

或者,只需添加一个额外的p.stdin.write(u'%s\n' % SUDO_PASSWORD)行。这样sudo会先收到用户密码,然后再passwd收到新的用户密码。

于 2013-07-21T14:28:55.850 回答
1

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
于 2012-11-02T10:59:35.373 回答
1

对于那些 --stdin 不是一个选项的人:

import subprocess
cmd = "bash -c \"echo -e 'NewPassword\\nNewPassword' | passwd root\""
subprocess.check_call(cmd, shell=True)
于 2020-03-17T21:32:09.327 回答
0

如前所述,不幸的是,在命令行上传递密码并不是很安全。此外,并非每个实现都可以使用“ --stdin” for 之类的东西。因此这里有一个更安全的版本,使用:passwdpasswdchpasswd

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

解释:

随着subprocess.Popen我们启动一个chpasswd. 我们通过管道将用户名和密码传递给chpasswd. chpasswd然后将使用为当前操作系统定义的设置更改密码。chpasswd如果没有发生错误,将保持完全沉默。因此,如果发生任何类型的错误,上面的代码将引发异常(无需仔细查看实际错误)。

于 2019-02-18T22:33:43.803 回答