我正在编写一个运行各种shell命令的PHP程序。有时它需要调用su
,并且按照设计,我希望它提示提升特权密码。在PHP中使用passthru()
可以正常工作。
我选择仅为我的程序编写功能测试,因为它依赖于ssh
,su
和其他shell命令。因此,我想在PHPUnit中运行真实的东西,看看它是否像我期望的那样工作。
由于这需要SSH服务器和用户帐户配置,我已将测试设置为在Docker中运行。这种方法看起来很好 - 图像构建,运行时调用PHPUnit,然后退出。我希望有一种方法可以通过Docker将结果返回给调用系统,例如Travis CI。
我已选择Alpine Linux作为我的基本Docker镜像,但我遇到终端分配问题。我最初认为PHPUnit正在阻碍(请参阅此问题的原始版本),但我现在已将其缩小为SSH,无论是由PHP运行还是仅在控制台运行。
这很好用:
su -c whoami
然而,这不是:
ssh localhost -t 'su -c whoami'
我明白了:
su:必须正常工作 与localhost的连接已关闭。
请注意,ssh
设置为无密码访问localhost(用于测试目的),因此我希望输入的唯一密码是su
。
ssh
的手册表明-f
对于要求密码的位置(切换“请求ssh在命令执行之前转到后台”)有帮助,所以我试试这个:
ssh localhost -t -f 'su -c whoami'
我得到了:
由于stdin不是终端,因此不会分配伪终端 4275760bde94:〜$ su:必须是suid才能正常工作
啊,另一个错误!好的,I've tried these ideas,特别是迫使终端:
ssh localhost -tt -f 'su -c whoami'
双t仍然会出现有关SUID的投诉,但仍无效。
但是,如果我在我的Ubuntu开发机器上执行此操作(也配置了PPK访问自己),它可以正常工作:
$ ssh localhost -t 'su -c whoami'
Password:
root
Connection to localhost closed.
这使它看起来像Alpine或BusyBox的OpenSSH有问题。我怎样才能进一步深入研究这个?
一种解决方案就是交换到另一个基础发行版,Ubuntu肯定能正常工作,但这会大大增加我的Docker镜像大小(目前总共68M非常漂亮)。所以,如果可以的话,我想坚持使用Alpine。
我确实想知道Docker是否可能阻止创建或附加终端,但很快就打了折扣,因为我可以使用docker exec -it container_name sh
获得交互式shell。此外,我可以在Docker shell中的两个单独命令中完成ssh
然后su
。
我注意到Bash在Alpine中可用,但这也没有帮助,这让我感到惊讶:
/ $ apk add bash
bash-4.3$ bash
bash-4.3$ su nonpriv
bash-4.3$ ssh localhost whoami
nonpriv
bash-4.3$ ssh localhost 'su -c whoami'
su: must be suid to work properly
bash-4.3$ ssh localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
bash-4.3$ ssh -t localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
Connection to localhost closed.
bash-4.3$ ssh -tt localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
Connection to localhost closed.
bash-4.3$ ssh -tf localhost 'su -s /bin/bash -c whoami'
Pseudo-terminal will not be allocated because stdin is not a terminal.
bash-4.3$ su: must be suid to work properly
bash-4.3$ ssh -ttf localhost 'su -s /bin/bash -c whoami'
bash-4.3$ su: must be suid to work properly
Connection to localhost closed.
我发现这几乎有效:
/ $ ssh -t localhost "$( su -c whoami )"
sh: Password:: not found
sh: root: not found
Connection to localhost closed.
这使用标准的Alpine sh
shell,并使用上述链接中的"$()"
构造,我并不完全理解。它输出Password:
,这是su
中的提示,然后等待密码。输入密码后,将运行whoami
,即打印root
。
所以看起来它正在运行命令,但我不确定它是否立即运行whoami
然后将其传递给ssh
(不是我想要的)或者它是否正在运行一个远程shell到localhost然后这样做(这是我想要的)。
在任何情况下,它都试图运行标准输出行,就好像它们是命令本身一样。如何才能通过SSH打印输出?
答案 0 :(得分:1)
我在我的问题中猜到这可以在Ubuntu容器中运行,这证明是正确的。有趣的是,我仍然使用此命令得到“必须从终端运行”错误:
su -c whoami
但不是这里,终端在SSH无密码命令中明确分配给self:
ssh -t localhost 'su -c whoami'
不幸的是,新操作系统将我的68M图像提升到430M,呃!因此,我应该非常乐意收到新的答案,以便在阿尔卑斯山上工作。