如何从Python调用一个需要使用sudo(在stdin上还有密码)在stdin上提供数据的程序?

如何从Python调用一个需要使用sudo(在stdin上还有密码)在stdin上提供数据的程序?,python,python-2.7,shell,subprocess,Python,Python 2.7,Shell,Subprocess,当我运行代码时,我遇到了这个错误“sudo:no tty present and no askpass program spcified”。这是第二个子流程调用的行,我尝试更改密码。用户创建得很完美,但密码不是,只是给出了给定的错误。我想做的是,在创建用户后,将向用户提供书面密码 import subprocess def new(username, password): subprocess.call("echo passd23 | sudo -S adduser '{usernam

当我运行代码时,我遇到了这个错误“sudo:no tty present and no askpass program spcified”。这是第二个子流程调用的行,我尝试更改密码。用户创建得很完美,但密码不是,只是给出了给定的错误。我想做的是,在创建用户后,将向用户提供书面密码

import subprocess

def new(username, password):
    subprocess.call("echo passd23 | sudo -S adduser '{username}'".format(username=username), shell=True)
    subprocess.call("echo passd23 | sudo '{username}':'{password}' | chpasswd".format(username=username, password=password), shell=True)

new("username", "password")    

这是一种不好的做法,但比它所取代的做法更安全:

def new(username, password, sudopass):
    p1 = subprocess.Popen(['sudo', '-S', 'adduser', username], stdin=subprocess.PIPE)
    p1.communicate(sudopass)
    if p1.retval != 0:
        return False
    p2 = subprocess.Popen(['sudo', '-S', 'chpasswd'], stdin=subprocess.PIPE)
    p2.communicate('%s\n%s:%s\n' % (sudopass, username, password))
    return p2.retval == 0

new('username', 'password', 'passd23')
值得注意的是:

  • shell不会将任何用户提供的字符串解析为代码。
    sudo
    密码作为stdin传递,而不是在生成的命令行上,用户提供的用户名和密码尤其不会由shell计算
  • 使用
    chpasswd
    ,stdin上会依次提供
    sudo
    密码和用户的用户名:密码

也就是说,在一个真实的例子中,你的脚本在内存中根本不应该有明文密码;相反,它应该在
/etc/sudoers
中配置为具有无密码权限升级。

sudo
不从stdin读取密码——它也不应该读取密码,因为您的
echo passd23
天生就不安全……因此,该行为正确地阻止了您执行这种极度不安全的操作,这将向系统上可以读取进程表的每个程序公开您的密码。(说到极度不安全——密码可以包含文字引号,因此尝试使用文字引号在直接替换到shell命令行的代码中转义shell密码是鲁莽的。如果新用户在此GUI中将其密码指定为
'$(rm-rf/*),
——使命令
sudo'username':''$(rm rf/*)“
,在硬编码代码中打开的引号在密码本身中关闭,你会有非常非常糟糕的一天。”@Charles Duffy我没有在这里写下真正的密码,是我编造的,但我写的更像是我代码的一个例子,这里的任何信息都不应该被认真对待:)这一切都是为了大学,不适用于公司它没有在StackOverflow中发布,这使得它不安全。它被发布在操作系统的进程列表中(系统上的每个用户都可以读取,包括
nobody
——用于未经验证和不可信代码的帐户),这使得密码不安全。决不能在命令行上传递密码。