【问题标题】:How to fix "Pseudo-terminal will not be allocated because stdin is not a terminal" in Alpine Linux?如何修复 Alpine Linux 中的“由于 stdin 不是终端而不会分配伪终端”?
【发布时间】:2017-10-31 13:29:10
【问题描述】:

我正在编写一个运行各种 shell 命令的 PHP 程序。有时它需要调用su,并且根据设计,我希望它提示输入提升的特权密码。在 PHP 中使用 passthru() 可以很好地解决这个问题。

我选择只为我的程序编写功能测试,因为它依赖于sshsu 和其他 shell 命令。因此,我想在 PHPUnit 中运行真实的东西,看看它是否按预期工作。

由于这需要 SSH 服务器和用户帐户配置,我已将测试设置为在 Docker 中运行。这种方法看起来会很好 - 图像构建,当它运行时它调用 PHPUnit,然后退出。我希望有一种方法可以通过 Docker 将结果返回到调用系统,例如 Travis CI。

我已选择 Alpine Linux 作为我的基本 Docker 映像,但我遇到了终端分配问题。我最初认为 PHPUnit 会妨碍(请参阅此问题的原始版本),但我现在已将其范围缩小到 SSH,可以由 PHP 运行,甚至可以在控制台上运行。

这很好用:

su -c whoami

但是,这不是:

ssh localhost -t 'su -c whoami'

我明白了:

su:必须是 suid 才能正常工作
与 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'

double-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 是否会阻止创建或连接终端,但很快就打折了,因为我可以使用 docker exec -it container_name sh 获得交互式 shell。此外,我可以在 Docker shell 内的两个单独命令中执行 ssh 然后 su 就好了。

Bash 没有帮助

我注意到 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.

尝试shell插值

我发现这几乎可以工作:

/ $ 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 然后做它(这就是我的意图)。

在任何情况下,它都试图运行 stdout 行,就好像它们本身就是命令一样。我怎样才能让它打印通过 SSH 运行的输出?

【问题讨论】:

  • 我真的不知道,但很好奇完整性,你的测试是什么样的?
  • 感谢@Jeff,事实证明这实际上并不是 PHPUnit 的问题。它确实会妨碍及时触发expect 的输出,但我可以通过超时来缓解这种情况。看起来问题在于 Alpine 如何允许将命令包含在 ssh 命令中。我想知道我在 SSH 中是否缺少某些标志。
  • 当我有时间我会简化这个问题,因为 PHPUnit 的事情似乎是一个红鲱鱼。
  • 乍一看这是duplicate of this question,但那里的解决方案不起作用。我想知道我是否正在研究 Alpine 特有的问题?
  • 我已经重写了这个问题,专注于我认为问题的核心。

标签: shell docker terminal alpine


【解决方案1】:

我在我的问题中猜测这将在 Ubuntu 容器中工作,并且证明是正确的。有趣的是,我仍然使用此命令收到“必须从终端运行”错误:

su -c whoami

但不是在这里,终端在 SSH 无密码命令中显式分配给自己:

ssh -t localhost 'su -c whoami'

不幸的是,新操作系统将我的 68M 图像提升到 430M,呃!因此,我应该很高兴收到可以在 Alpine 上运行的新答案。

【讨论】:

    猜你喜欢
    • 2011-10-30
    • 1970-01-01
    • 2018-07-16
    • 2014-03-10
    • 1970-01-01
    • 1970-01-01
    • 2019-08-13
    • 2011-06-07
    相关资源
    最近更新 更多