Go 的 SSH 客户端和 AIX 上的 PTY
Go's SSH client and PTY on AIX
我怀疑我会在这里得到答案,因为 AIX 是非常罕见的东西,但我至少应该尝试一下。
背景
我们有程序。该程序使用 golang.org/x/crypto/ssh
库连接到远程服务并做一些事情。该程序是大型服务的一部分,并由最终用户广泛测试。它不仅适用于所有基于 Linux 的客户端(包括相当古老的东西,如 Ubuntu 12.02),而且适用于 FreeBSD、OpenBSD、NetBSD、MacOSX 上的客户端,它可以毫无问题地工作(至少与连接有关), Solaris SPARC、HP-UX 和其他 *nixes。所以看起来它不仅仅在三星冰箱上进行过测试。昨天我确信它能够连接到冰箱并毫无问题地执行所需的操作。但那是昨天...
问题
今天我们决定将 AIX 支持添加到我们的程序中。我们部分失败了。
问题描述很简单:pty
请求后程序停止运行。我的意思是我可以 ssh.RequestPty
它执行时没有任何问题,但是当我在应用程序挂起后尝试执行命令时。没有错误,什么都没有。只是挂起。
什么时候生效?
- 它在 PuTTY/KiTTY 中工作,所以我能够连接到远程主机。
- 如果我删除
requestPty
- 一切正常。但是 sudo
我们需要 pty
。
- 如果我请求
session.Shell
,即使请求 pty
,它也可以正常工作。因此,如果我编写某种交互式 shell,它会完美运行。
到目前为止我尝试了什么
我尽可能调试。最后执行的命令是 ssh/channel.go
中的 ch.sendMessage(msg)
。我的意思是它写数据包,仅此而已。没有从远程主机返回数据。
为了测试,我使用了 3 个版本的 AIX - 5.3、6.1 和 7.1。没有区别。
OpenSSH 版本不同:
- 5.3 - OpenSSH_5.2p1,OpenSSL 0.9.8k 2009 年 3 月 25 日
- 6.1 & 7.1 - OpenSSH_6.0p1,OpenSSL 1.0.1e 2013 年 2 月 11 日
所有机器都在 运行LPAR 中,但我怀疑这与问题有关。
我不知道出了什么问题。我什至不能说这是常见的 AIX 问题还是只是我们的测试机器。这是示例程序,如果它工作
应该写 IT WORKS
package main
import (
"golang.org/x/crypto/ssh"
)
func main() {
server := "127.0.0.1:22"
user := "root"
p := "password"
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{ssh.Password(p)},
}
conn, err := ssh.Dial("tcp", server, config)
if err != nil {
panic(err.Error())
}
defer conn.Close()
session, err := conn.NewSession()
if err != nil {
panic(err.Error())
}
defer session.Close()
// Comment below and everything works
modes := ssh.TerminalModes{
ssh.ECHO: 0,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}
if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
panic(err.Error())
}
// Comment above and everything works
session.Run("echo 1")
println("IT WORKS")
}
如果您附近有 AIX,并且可以 运行 此代码反对它,我将不胜感激您的反馈。
如果您有任何想法(甚至是疯狂的想法)为什么它可能会失败以及我还可以看看其他地方,请不要害羞。
更新(2017-03-02):
根据@LorinczyZsigmond 的建议,我在调试模式下启动了 sshd
。结果有点奇怪。
这是示例程序执行后 Debian 9.0 OpenSSH_6.0p1 Debian-4+deb7u3, OpenSSL 1.0.1t 3 May 2016
日志的一部分:
debug1: session_input_channel_req: session 0 req pty-req
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/1
debug1: SELinux support disabled
debug1: server_input_channel_req: channel 0 request exec reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req exec
debug2: fd 3 setting TCP_NODELAY
debug3: packet_set_tos: set IP_TOS 0x10
debug1: Setting controlling tty using TIOCSCTTY.
debug2: channel 0: rfd 10 isatty
debug2: fd 10 setting O_NONBLOCK
debug3: fd 8 is O_NONBLOCK
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
它按预期工作。
现在来自 AIX 7.1 OpenSSH_6.0p1, OpenSSL 1.0.1e 11 Feb 2013
日志的相同块:
debug1: session_input_channel_req: session 0 req pty-req
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/42
debug1: server_input_channel_req: channel 0 request exec reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req exec
debug1: Values: options.num_allow_users: 0
debug1: RLOGIN VALUE :1
debug1: audit run command euid 0 user root command 'whoami'
setsid: Operation not permitted.
在 setsid: Operation not permitted.
之后它什么都不做,直到我用 Ctrl+C 杀死它。当我杀死它时 returns:
debug2: fd 4 setting TCP_NODELAY
debug3: packet_set_tos: set IP_TOS 0x10
debug2: channel 0: rfd 10 isatty
debug2: fd 10 setting O_NONBLOCK
debug3: fd 8 is O_NONBLOCK
debug2: notify_done: reading
Exiting on signal 2
debug1: do_cleanup
debug1: session_pty_cleanup: session 0 release /dev/pts/42
debug1: audit session close euid 0 user root tty name /dev/pts/42
debug1: audit event euid 0 user root event 12 (SSH_connabndn)
debug1: Return Val-1 for auditproc:0
并将whoami
的结果回传给客户端。这看起来像是 SSH 服务器中的错误,但这对于 2 个不同的版本是否可行?
另一个有趣的事实是,当我使用 运行 sshd
和 truss
(AIX 的 strace
类型)时,输出如下所示:
debug1: session_input_channel_req: session 0 req pty-req
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/42
debug1: server_input_channel_req: channel 0 request exec reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req exec
debug1: Values: options.num_allow_users: 0
debug1: RLOGIN VALUE :1
debug1: audit run command euid 0 user root command 'whoami'
debug2: fd 4 setting TCP_NODELAY
debug3: packet_set_tos: set IP_TOS 0x10
debug2: channel 0: rfd 10 isatty
debug2: fd 10 setting O_NONBLOCK
debug3: fd 8 is O_NONBLOCK
setsid: Operation not permitted.
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
debug2: channel 0: obuf empty
debug2: channel 0: close_write
debug2: channel 0: output drain -> closed
但是 truss
输出比 strace
有点奇怪(至少对于那些不每天使用 *nix 跟踪工具的人来说)所以我不明白什么是在日志中进行。如果有人更擅长这些东西,这里是来自 debug1: RLOGIN VALUE :1
.
的跟踪数据 http://pastebin.com/YdzQwbt2 的一部分
此外,在日志中,我发现 ssh.Shell()
有效,因为它不请求 pty
。它启动一个交互式会话(或类似的东西)。但就我而言,交互式会话不是一个选项。
我遇到了与 "Allocating pty" 类似的问题,然后退出了 ssh 会话。这是我的 sshd 调试日志:
sshd 断开连接并出现错误:3004-010 设置终端所有权和模式失败。
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/2
debug1: Ignoring unsupported tty mode opcode 13 (0xd)
debug1: Ignoring unsupported tty mode opcode 18 (0x12)
debug1: server_input_channel_req: channel 0 request env reply 0
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req env
debug2: Ignoring env request LANG: disallowed name
debug1: server_input_channel_req: channel 0 request shell reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req shell
debug1: Values: options.num_allow_users: 0
debug1: RLOGIN VALUE :1
setsid: Operation not permitted.
The OS is AIX 7.1 (7100-04-03-1642)
我的环境的目标是通过 ssh 上的远程 ldap 用户对 AIX 上的用户进行身份验证(ldap 服务器实际上是 novell eDirectory)。
所以,我在用户身份验证方面遇到了类似的问题。
我修复了在 eDirectory 模式 (rfc2703) 中通过 ssh 登录,向用户添加了以下对象扩展:
posix帐号
posix组
影子账户
uamPosixUser(因为我不确定是否需要这个对象)
我只想指出,在 OS AIX 上,以下用户不是本地用户,不存在于 /etc/passwd
和 /etc/group
.
中
V.Davidov
迟到总比不到好
IBM 说这是 openssh 中的错误 - PTY 分配时的竞争条件
https://www-01.ibm.com/support/docview.wss?uid=isg1IV82042
已在包 openssh.base.server:7.5.102.1500
中修复
奇怪的是,bug 只出现在 aix 中,从来没有出现在 linux 中。尽管如此,我的问题还是解决了
我怀疑我会在这里得到答案,因为 AIX 是非常罕见的东西,但我至少应该尝试一下。
背景
我们有程序。该程序使用 golang.org/x/crypto/ssh
库连接到远程服务并做一些事情。该程序是大型服务的一部分,并由最终用户广泛测试。它不仅适用于所有基于 Linux 的客户端(包括相当古老的东西,如 Ubuntu 12.02),而且适用于 FreeBSD、OpenBSD、NetBSD、MacOSX 上的客户端,它可以毫无问题地工作(至少与连接有关), Solaris SPARC、HP-UX 和其他 *nixes。所以看起来它不仅仅在三星冰箱上进行过测试。昨天我确信它能够连接到冰箱并毫无问题地执行所需的操作。但那是昨天...
问题
今天我们决定将 AIX 支持添加到我们的程序中。我们部分失败了。
问题描述很简单:pty
请求后程序停止运行。我的意思是我可以 ssh.RequestPty
它执行时没有任何问题,但是当我在应用程序挂起后尝试执行命令时。没有错误,什么都没有。只是挂起。
什么时候生效?
- 它在 PuTTY/KiTTY 中工作,所以我能够连接到远程主机。
- 如果我删除
requestPty
- 一切正常。但是sudo
我们需要pty
。 - 如果我请求
session.Shell
,即使请求pty
,它也可以正常工作。因此,如果我编写某种交互式 shell,它会完美运行。
到目前为止我尝试了什么
我尽可能调试。最后执行的命令是 ssh/channel.go
中的 ch.sendMessage(msg)
。我的意思是它写数据包,仅此而已。没有从远程主机返回数据。
为了测试,我使用了 3 个版本的 AIX - 5.3、6.1 和 7.1。没有区别。
OpenSSH 版本不同:
- 5.3 - OpenSSH_5.2p1,OpenSSL 0.9.8k 2009 年 3 月 25 日
- 6.1 & 7.1 - OpenSSH_6.0p1,OpenSSL 1.0.1e 2013 年 2 月 11 日
所有机器都在 运行LPAR 中,但我怀疑这与问题有关。
我不知道出了什么问题。我什至不能说这是常见的 AIX 问题还是只是我们的测试机器。这是示例程序,如果它工作
应该写IT WORKS
package main
import (
"golang.org/x/crypto/ssh"
)
func main() {
server := "127.0.0.1:22"
user := "root"
p := "password"
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{ssh.Password(p)},
}
conn, err := ssh.Dial("tcp", server, config)
if err != nil {
panic(err.Error())
}
defer conn.Close()
session, err := conn.NewSession()
if err != nil {
panic(err.Error())
}
defer session.Close()
// Comment below and everything works
modes := ssh.TerminalModes{
ssh.ECHO: 0,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}
if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
panic(err.Error())
}
// Comment above and everything works
session.Run("echo 1")
println("IT WORKS")
}
如果您附近有 AIX,并且可以 运行 此代码反对它,我将不胜感激您的反馈。
如果您有任何想法(甚至是疯狂的想法)为什么它可能会失败以及我还可以看看其他地方,请不要害羞。
更新(2017-03-02):
根据@LorinczyZsigmond 的建议,我在调试模式下启动了 sshd
。结果有点奇怪。
这是示例程序执行后 Debian 9.0 OpenSSH_6.0p1 Debian-4+deb7u3, OpenSSL 1.0.1t 3 May 2016
日志的一部分:
debug1: session_input_channel_req: session 0 req pty-req
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/1
debug1: SELinux support disabled
debug1: server_input_channel_req: channel 0 request exec reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req exec
debug2: fd 3 setting TCP_NODELAY
debug3: packet_set_tos: set IP_TOS 0x10
debug1: Setting controlling tty using TIOCSCTTY.
debug2: channel 0: rfd 10 isatty
debug2: fd 10 setting O_NONBLOCK
debug3: fd 8 is O_NONBLOCK
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
它按预期工作。
现在来自 AIX 7.1 OpenSSH_6.0p1, OpenSSL 1.0.1e 11 Feb 2013
日志的相同块:
debug1: session_input_channel_req: session 0 req pty-req
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/42
debug1: server_input_channel_req: channel 0 request exec reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req exec
debug1: Values: options.num_allow_users: 0
debug1: RLOGIN VALUE :1
debug1: audit run command euid 0 user root command 'whoami'
setsid: Operation not permitted.
在 setsid: Operation not permitted.
之后它什么都不做,直到我用 Ctrl+C 杀死它。当我杀死它时 returns:
debug2: fd 4 setting TCP_NODELAY
debug3: packet_set_tos: set IP_TOS 0x10
debug2: channel 0: rfd 10 isatty
debug2: fd 10 setting O_NONBLOCK
debug3: fd 8 is O_NONBLOCK
debug2: notify_done: reading
Exiting on signal 2
debug1: do_cleanup
debug1: session_pty_cleanup: session 0 release /dev/pts/42
debug1: audit session close euid 0 user root tty name /dev/pts/42
debug1: audit event euid 0 user root event 12 (SSH_connabndn)
debug1: Return Val-1 for auditproc:0
并将whoami
的结果回传给客户端。这看起来像是 SSH 服务器中的错误,但这对于 2 个不同的版本是否可行?
另一个有趣的事实是,当我使用 运行 sshd
和 truss
(AIX 的 strace
类型)时,输出如下所示:
debug1: session_input_channel_req: session 0 req pty-req
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/42
debug1: server_input_channel_req: channel 0 request exec reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req exec
debug1: Values: options.num_allow_users: 0
debug1: RLOGIN VALUE :1
debug1: audit run command euid 0 user root command 'whoami'
debug2: fd 4 setting TCP_NODELAY
debug3: packet_set_tos: set IP_TOS 0x10
debug2: channel 0: rfd 10 isatty
debug2: fd 10 setting O_NONBLOCK
debug3: fd 8 is O_NONBLOCK
setsid: Operation not permitted.
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
debug2: channel 0: obuf empty
debug2: channel 0: close_write
debug2: channel 0: output drain -> closed
但是 truss
输出比 strace
有点奇怪(至少对于那些不每天使用 *nix 跟踪工具的人来说)所以我不明白什么是在日志中进行。如果有人更擅长这些东西,这里是来自 debug1: RLOGIN VALUE :1
.
此外,在日志中,我发现 ssh.Shell()
有效,因为它不请求 pty
。它启动一个交互式会话(或类似的东西)。但就我而言,交互式会话不是一个选项。
我遇到了与 "Allocating pty" 类似的问题,然后退出了 ssh 会话。这是我的 sshd 调试日志:
sshd 断开连接并出现错误:3004-010 设置终端所有权和模式失败。
debug1: Allocating pty.
debug1: session_pty_req: session 0 alloc /dev/pts/2
debug1: Ignoring unsupported tty mode opcode 13 (0xd)
debug1: Ignoring unsupported tty mode opcode 18 (0x12)
debug1: server_input_channel_req: channel 0 request env reply 0
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req env
debug2: Ignoring env request LANG: disallowed name
debug1: server_input_channel_req: channel 0 request shell reply 1
debug1: session_by_channel: session 0 channel 0
debug1: session_input_channel_req: session 0 req shell
debug1: Values: options.num_allow_users: 0
debug1: RLOGIN VALUE :1setsid: Operation not permitted.
The OS is AIX 7.1 (7100-04-03-1642)
我的环境的目标是通过 ssh 上的远程 ldap 用户对 AIX 上的用户进行身份验证(ldap 服务器实际上是 novell eDirectory)。 所以,我在用户身份验证方面遇到了类似的问题。
我修复了在 eDirectory 模式 (rfc2703) 中通过 ssh 登录,向用户添加了以下对象扩展:
posix帐号
posix组
影子账户
uamPosixUser(因为我不确定是否需要这个对象)
我只想指出,在 OS AIX 上,以下用户不是本地用户,不存在于 /etc/passwd
和 /etc/group
.
V.Davidov
迟到总比不到好
IBM 说这是 openssh 中的错误 - PTY 分配时的竞争条件 https://www-01.ibm.com/support/docview.wss?uid=isg1IV82042
已在包 openssh.base.server:7.5.102.1500
中修复奇怪的是,bug 只出现在 aix 中,从来没有出现在 linux 中。尽管如此,我的问题还是解决了