martyr-deepin / deepin-terminal-gtk

DDE terminal emulator application
GNU General Public License v3.0
263 stars 57 forks source link

当远程主机密码含特殊字符时可能导致自动登录失败 #160

Closed straicat closed 5 years ago

straicat commented 5 years ago

远程主机的密码为E4iG'W<,Cy)f9$HYV1}~

在使用远程管理的功能时,自动登录出现错误:

$ expect -f /tmp/deepin-terminal-Z47C1Z
extra characters after close-brace
    while executing
"set password {E4iG'W<,Cy)f9$HYV1}~"
    (file "/tmp/deepin-terminal-Z47C1Z" line 36)

猜测为密码中的}字符导致。在修改密码,新密码不含},再次使用远程管理功能,一切正常。

BLumia commented 5 years ago

https://github.com/linuxdeepin/internal-discussion/issues/898 关联一下。

我回头看看,目前手头事情有点多- -

以及如果乐意的话,欢迎直接通过 GitHub Pull Request 提交 Patch ~

可能相关的代码:

https://github.com/linuxdeepin/deepin-terminal/blob/d935171d67fbd3803199bd3f5ff1d73b316c605b/ssh_login.sh#L35-L61

abcfy2 commented 5 years ago

+1,我也遇到这个问题,特殊字符的密码会导致登录失败。

我个人建议使用sshpass这个工具代替expect脚本,可靠的多。而且可以让登录交互大幅简化。

比如你那一堆expect脚本,使用了了sshpass之后就简化成一行命令了:

SSHPASS=mypass sshpass -e ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@192.168.31.1

使用-o UserKnownHostsFile=/dev/null是为了规避服务器重装或者其他原因导致密钥变化之后登录失败

甚至sshpass支持使用-f FILE参数指明密码从哪个文件读取。

BLumia commented 5 years ago

+1,我也遇到这个问题,特殊字符的密码会导致登录失败。

我个人建议使用sshpass这个工具代替expect脚本,可靠的多。而且可以让登录交互大幅简化。

比如你那一堆expect脚本,使用了了sshpass之后就简化成一行命令了:

SSHPASS=mypass sshpass -e ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@192.168.31.1

我的确不太熟悉这个,可以考虑来个 PR 。顺便相关逻辑在这里(你可能已经看过了):

https://github.com/linuxdeepin/deepin-terminal/blob/f462e53c07a40843d707e1508b40773ea575aa92/ssh_login.sh#L33-L61

使用-o UserKnownHostsFile=/dev/null是为了规避服务器重装或者其他原因导致密钥变化之后登录失败

这点其实现在的版本是无论如何都发个 yes :

https://github.com/linuxdeepin/deepin-terminal/blob/f462e53c07a40843d707e1508b40773ea575aa92/ssh_login.sh#L54

值得一提的是,我维护这个项目的时候觉得之前无论如何都发 yes 的行为其实不好,因为密钥变化也有可能是中间人攻击或者其他原因导致的,用户的确需要知道这件事情发生并且自己确认到底是不是真的有问题。不过如果是和目前行为保持完全一致的话,应该也只能这样做。

abcfy2 commented 5 years ago

那这里可以考虑采用putty或者xshell之类的逻辑,交给用户判断,是否信任服务器公钥。同时,如果服务器公钥发生改变之后,也会提示用户重新信任服务器密钥

abcfy2 commented 5 years ago

原来的逻辑这里有点太繁琐了,还有点反人类。打算大改一次这里的逻辑,不太熟悉Vala,一边google查文档一边改,可能会稍微慢一点提交PR

原来的逻辑是使用模板替换ssh_login.sh中的内容,然后调用expect跑。太繁琐了,我觉得没必要,敏感信息全部注入环境变量

abcfy2 commented 5 years ago

@BLumia 大部分功能我都搞定了,但是有一处不解,就是这个vte版本究竟是怎么回事?我看使用的版本是0.52.1这个版本,按理说应该已经支持Vte.Terminal.spawn_async这个方法了: https://valadoc.org/vte-2.91/Vte.Terminal.spawn_async.html 并且Vte.Terminal.spawn_sync已经被标记废弃,编译的时候也有警告,但为什么我用term.spawn_async的时候报错spawn_asyncVte.Terminal上下文找不到?

我看vteterminal.cc这个文件中已经有vte_terminal_spawn_async这个函数定义了啊?

但是term.spawn_sync没问题,不过这玩意似乎在进程结束就把终端销毁了,不太符合期望。我尝试用term.spawn_sync(null, './ssh_login.sh',...)这个函数,可以成功调起ssh_login.sh,并且可以注入环境变量,但是退出退出ssh后终端进程就被销毁了,不知道有什么好的解决方案没?我看好像Vte.Terminal.spawn_async能解决这个问题,但是在我们目前的环境编译会找不到这个方法

BLumia commented 5 years ago

大部分功能我都搞定了,但是有一处不解,就是这个vte版本究竟是怎么回事?我看使用的版本是0.52.1这个版本,按理说应该已经支持Vte.Terminal.spawn_async这个方法了: https://valadoc.org/vte-2.91/Vte.Terminal.spawn_async.html 并且Vte.Terminal.spawn_sync已经被标记废弃,编译的时候也有警告,但为什么我用term.spawn_async的时候报错spawn_asyncVte.Terminal上下文找不到?

我不太清楚你所在使用的发行版,deepin-terminal 本身是可以选择使用附带的 vte 或者发行版提供的 vte 的,如果你使用 USE_VENDOR_LIB=off 构建的话,会使用你所用发行版附带的 vte ,否则是 repo 里附带的 vte 版本。

内附 vte 和 zssh 的原因是 vte 打过几个 patch ,而 debian stretch 附带的 zssh 本身有毛病(压根没法用)。等 debian 发 buster 的时候这些 vendor libs 我会去掉。

但是term.spawn_sync没问题,不过这玩意似乎在进程结束就把终端销毁了,不太符合期望。我尝试用term.spawn_sync(null, './ssh_login.sh',...)这个函数,可以成功调起ssh_login.sh,并且可以注入环境变量,但是退出退出ssh后终端进程就被销毁了,不知道有什么好的解决方案没?我看好像Vte.Terminal.spawn_async能解决这个问题,但是在我们目前的环境编译会找不到这个方法

我觉得不如等节后我先找产品确认一下 ssh 断开后依然回到普通的 shell 是不是原始需求,因为你传给 spawn 的程序就是作为 shell 程序运行的,它返回后终端自然就销毁了。(当然也可能我理解有误)


ps. 由于我也不甚熟悉 vala/GTK ,所以其实我有私底下在尝试做 DTK 的 terminal (我还没放出来代码),不知道有没有兴趣一起搞 😂

abcfy2 commented 5 years ago

@BLumia

我用的就是Deepin环境编译的。按照README中的描述安装依赖和编译,在编译就会报错找不到Vte.Terminal.spawn_async,不知道是怎么回事。

这里我打算先用quick dirty的方案解决了吧,先把expect脚本解决特殊字符的问题吧。其他更优的方案理论可行,但在不熟悉的vala+vte编程环境下我的好多想法暂时都没法实现。

我做过很多年的运维,根据我的经验和实际体验,我都是尽可能避免使用expect,尽可能采纳其他更好的非交互式解决方案。因为expect这玩意不可控,非常可能会出现你意想不到的输出,导致整个脚本失效。而且这玩意维护量非常大,expect脚本你必须为每一步的IO深思熟虑,考虑每一步可能产生的输出和结果,这就导致维护量一下就上去了,还会有很多潜在的BUG。比如这个ssh_login那一堆expect脚本改用bash脚本就一行。

我最早的想法是这样的:

去掉zssh相对好做,而且xshell这一类的终端本身也是没有zssh依赖的,只要把交互这里设计好就可以了。改造ssh_login.sh这里我当初已经做了一大半了,把terminal.vala中的expect -f部分也成功改用了直接调用shell执行,fork子进程查了半天vala的文档,使用term.spawn_sync可以实现,并且可以使用当前终端的STDIN和STDOUT,成功捕获键盘输入和终端输出,但是退出之后整个terminal就被销毁了,和之前行为不一致,而且那个菜单判断也不正常,右键的时候不会出现上传下载文件选项,这里也不是难事,但是积少成多,动的手术有点太大,一时半会控制不住了,怕改坏了。所以暂时先保守治疗吧。

我个人从事DevOps工作,开发强项主要是Java服务端开发,以网络编程和CLI为主,GUI不是我擅长的。平时也使用大量的Python和Bash脚本维护服务器,所以对脚本终端这些基本原理都算是熟悉。参与开源也是我的爱好,我也给多个项目提交过PR,不过没有太多时间专业做这个。如果你开放源码的话我可以帮忙做一些参考,提交一些力所能及的PR都不成问题。

abcfy2 commented 5 years ago

我本来的设想是连lrzsz都去掉,因为这玩意实在太慢了,而且不能支持文件夹。xshell不是有个打开xftp的按钮么。我本来想用那个,需要上传下载文件的时候用sshfs挂载远程目录到本地,直接图形化界面拖拽就行了,或者调起sftp协议,这个文件管理器就能直接支持。

不过这个改动更夸张,而且sftp会受到ssh权限限制,不一定所有的远程连接都可以使用sftp。相反rzsz虽然速度慢,不支持文件夹,而且有编码支持的问题,但是兼容性来说是最好的,它直接调起服务器的虚拟串口传输文件,几乎无权限问题,通用性是最好的。

abcfy2 commented 5 years ago

PR已经提交。暂时沿用以前的解决方案,修复了密码包含特殊字符的问题

我自己改了一半改不下去的部分先放到我的dev了: https://github.com/abcfy2/deepin-terminal/commit/e71b321e5ae8b254a2a9d914bf0d07e4c0eb8abb 有空看能不能改的下去吧。:unamused:

BLumia commented 5 years ago

去掉zssh依赖,改到ssh。理由: zssh长期缺乏维护,几乎停滞不更新了,最主要的是zssh没发用sshpass实现非交互式

有这个想法,不过目前我们情况一样,我也不太熟悉 Vala/GTK ,所以目前基本只处理一些 bug.. 不知道 @manateelazycat 原作者有没有兴趣讨论一下看法。

至于去掉 lrzsz 之类的,不知道有没有什么其它的 zmodem 相关库推荐?

非常感谢 PR ,今天晚些时候我就 review 。

abcfy2 commented 5 years ago

去掉zssh依赖,改到ssh。理由: zssh长期缺乏维护,几乎停滞不更新了,最主要的是zssh没发用sshpass实现非交互式

有这个想法,不过目前我们情况一样,我也不太熟悉 Vala/GTK ,所以目前基本只处理一些 bug.. 不知道 @manateelazycat 原作者有没有兴趣讨论一下看法。

至于去掉 lrzsz 之类的,不知道有没有什么其它的 zmodem 相关库推荐?

非常感谢 PR ,今天晚些时候我就 review 。

平时我很少用终端直接做rzsz,我一般都是用sftp或者用图形界面的filezilla。可以参考下xshell、securitycrt他们怎么做的。因为我发现xshell是不用zssh的