使用 python 中的子进程自动从普通用户切换到 root

Automating switching from normal user to root with subproccess in python

问题:

我正在尝试执行一个从 PostgreSQL 数据库读取的命令。我可以手动切换到 root,然后切换到 postgre 用户并访问我想要的信息。

我遇到的问题是,当我 运行 这个时,它只是挂起,没有任何反应。

我有 root 密码,从当前用户切换时需要这个密码,但系统没有提示我输入它。

如何才能让它不挂起并提示输入密码?

为简单起见,下面的代码只执行 'ls'。

代码:

def popen_cmd_shell(command):
    print command
    process = subprocess.Popen(command,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.STDOUT,
                               shell=True)

    proc_stdout = process.communicate()[0].strip()    
    return proc_stdout

if __name__ == '__main__':
    querylist = popen_cmd_shell('su - root; ls;')

    print querylist

更新一:

我无法在 Linux SUSE 上使用 python 2.7 未附带的任何库。我只需要执行一个命令然后退出。

更新二:

我无法 运行 以 root 用户身份执行脚本,因为我需要执行其他要求我不是 root 用户的任务。

更新三:

根据 LeBarton 的建议,我已经获得了登录 root 的脚本,尽管 ls 命令从未以 root 身份执行,但它以我最初的用户身份执行。当我 运行 命令时,系统提示我输入 root 密码并从 "@host" 转移到 "host" 谁不能执行除退出以外的任何命令。当我退出所有执行的命令时,出现输出。

我不想像 LeBarton 那样在代码中存储用户密码。我如何以 root 身份执行命令并返回 return 并继续脚本的其余部分,而不会被新用户锁定并需要键入 'exit'.

"stderr=subprocess.STDOUT" 似乎是导致它挂起的原因。

代码:

if __name__ == '__main__':
    def subprocess_cmd(command):
        process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True)
        proc_stdout = process.communicate()[0].strip()
        print proc_stdout

    subprocess_cmd('echo a; su - root; ls; cd;ls;')

...continue with rest of script where I execute commands as original user 

答案:

感谢tripleee的精彩解答。

我已经实现了我打算用以下代码做的事情:

if __name__ == '__main__':
    def subprocess_cmd(command):
        process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=False)
        proc_stdout = process.communicate()[0].strip()
        print proc_stdout

    subprocess_cmd(['su','-','root','-c','su -s /bin/sh  postgres -c \'psql -U msa ..........])

我只需要将我以 root 身份执行的命令放在 -c 之后。所以它现在切换到 postgres 用户并从 root returning 到普通用户后找到它需要的数据。

您只想访问 PostgreSQL 数据库吗?如果是这样,你根本不需要使用命令行...

Python 库 psycopg2 将允许向 PostgreSQL 服务器发送命令,更多信息请参见此处:https://wiki.postgresql.org/wiki/Psycopg2_Tutorial

但是我推荐一个 ORM,例如 SQLAlchemy,它们使与数据库的通信成为一项微不足道的任务。

你的命令是这样的

su - root; ls;

shell 将其解释为

"su -root; ls;"

您的文件中可能没有带空格的确切名称的可执行文件。

尝试将其分成

列表
['su', '-', 'root', ';', 'ls', ';' ]

编辑

stdout=subprocess.PIPE, 导致程序挂起。如果您尝试输入密码,使用 process.communicate('root password') 是可行的。

您误解了 su 的作用。 su 创建一个特权子进程;它不会改变您当前进程的特权。 su 之后的命令将在 su 完成后以您的正常权限执行。

相反,您想传递一个 -c 选项来指定您想要 运行 具有更高权限的命令。 (另见 su man page。)

popen_cmd_shell('su -c ls - root')

sudo 是专门为简化这类事情而设计的,因此您可能应该改用它。

对特权命令的脚本访问是一个棘手的话题。一种常见的方法是让您的命令执行特权操作,然后放弃其特权。从安全和设计的角度来看,这种方法倾向于简化整体逻辑。您需要确保您的特权代码尽可能简单和简短——例如,不要在特权部分进行解析。

一旦特权代码经过适当的测试、审计和冻结,赋予脚本所需的特权应该是一件简单的事情(虽然很多组织都是偏执狂,并且基本上无法为这种事情建立可行的政策).

无论您采用哪种方法,您绝对应该避免在任何安全敏感的上下文中使用 shell=True,而是将任何外部命令作为列表而不是单个字符串传递。

popen_cmd_shell(['su', '-c', 'ls', '-', 'root'])

(也许还重命名函数,因为您特别不想要 shell。显然,还要更改函数以指定 shell=False。)

同样,无论您是放弃权限,还是通过 susudo.

请求权限升级,这些安全问题都存在