【问题标题】:Automating switching from normal user to root with subproccess in python使用python中的子进程自动从普通用户切换到root
【发布时间】:2015-10-28 07:53:22
【问题描述】:

问题:

我正在尝试执行一个从 PostgreSQL 数据库读取的 cmd。我可以手动切换到 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 身份执行命令并返回并继续脚本的其余部分,而不会被锁定到新用户并需要输入“退出”。

"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 ..........])

我只需要在 -c 之后以 root 身份执行的命令。所以它现在切换到 postgres 用户,然后从 root 中找到它需要的数据返回给普通用户。

【问题讨论】:

  • 为什么不简单地创建脚本,然后使用 sudo 以 root 身份运行脚本?而且您甚至不需要 root 即可访问数据库。
  • (1) 您应该能够在不切换到 root 的情况下访问数据库。如果您不知道如何专门询问一个单独的问题 (2) 为避免被询问 root 密码,请使用 sudo,您可以配置为以 root 身份运行您的命令而无需密码:output = check_output(['sudo', 'get-db-data.sh'])。在我的系统上,如果您需要传递 root 密码但又想避免在源代码中对其进行硬编码,只需将一行文件放入 /etc/sudoers.d/ 目录 (3) 就足够了,那么您可以使用 root_password = getpass.getpass('root password:') 来询问运行时的密码。

标签: python postgresql shell python-2.7 subprocess


【解决方案1】:

您误解了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 请求提权,这些安全问题都存在。

【讨论】:

    【解决方案2】:

    你的命令是这样的

    su - root; ls;
    

    shell 将其解释为 this

    "su -root; ls;"
    

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

    尝试将其拆分为列表

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

    编辑

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

    【讨论】:

    • 不,您不应该在 POSIX 上使用带有 shell=True 的列表参数。不,除非stdin=PIPE,否则.communicate(input) 将不起作用。此外,如果su 直接从终端(而不是标准输入)接受密码,它将不起作用。
    【解决方案3】:

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

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

    不过我推荐使用 SQLAlchemy 之类的 ORM,它们使与数据库的通信成为一项微不足道的任务。

    【讨论】:

      猜你喜欢
      • 2019-03-19
      • 2021-11-21
      • 2014-04-01
      • 2019-07-07
      • 1970-01-01
      • 1970-01-01
      • 2018-10-22
      • 1970-01-01
      • 2023-03-03
      相关资源
      最近更新 更多