[Archlinux 4.18.9]
我已经建立了一个简单的别名来通过 vpn 连接到集群:
alias clusvpn='sudo /usr/bin/openvpn --config client.ovpn'
这包括一个特定的/etc/sudoers
条目,因此在发出 cmd 时不需要向授权用户请求 sudo 密码。
这会导致 2 个输入请求:一个用于远程 vpn 服务器上的注册用户姓名,一个用于用户密码。手动从 cli 执行操作,一切正常。没有问题。
然而一旦通道打开,即用户输入了他们的姓名和密码后,我想自动将我的 vpn 会话置于后台。理想情况下,我想在使用别名发出 cmd 的同时表明这一事实。但发出命令sudo /usr/bin/openvpn --config client.ovpn &
并不允许用户输入用户名和密码。
有没有办法做到这一点,而不必借助包含密码和用户名的文件?
答案1
我了解,您谈论的凭证可以通过 传递--auth-user-pass
,但不能通过 传递--askpass
,因此--daemon
没有用。
我认为你可以使用expect
. 可能的解决方案的草图:
spawn sudo /usr/bin/openvpn --config client.ovpn
运行该程序。expect "Username: "
或类似(取决于openvpn
打印的内容,我现在无法检查)等待提示。使用如下代码:
send_user "Username: " expect_user -re "(.*)\n"
从用户处获取用户名。
send "$expect_out(1,string)\n"
将其传递给程序。- 重复密码,
stty -echo
可能会有用。 - 最后使用
fork
并将disconnect
程序置于后台。
手册中有一些示例可能会对您有所帮助。我认为您甚至可以实现一些逻辑来涵盖诸如“密码无效,请重试”等响应。
这是我的尚未完全测试代码片段:
#!/usr/bin/expect
log_user 0
set timeout -1
spawn sudo /usr/bin/openvpn --config client.ovpn
expect "*sername*"
send_user "Username: "
expect_user -re "(.*)\n"
send "$expect_out(1,string)\n"
expect "*assword*"
stty -echo
send_user "Password: "
expect_user -re "(.*)\n"
send "$expect_out(1,string)\n"
stty echo
send_user "\n"
if {[fork]!=0} exit
disconnect
expect eof
唯一的测试是在 Debian 上进行的,spawn nc …
它连接到另一个nc
在单独的控制台中监听的控制台。我成功发送了提示和答案,然后原来的控制台expect
终止了。我处于 shell 提示符下,但两个nc
-s 仍然连接着,生成的那个在后台运行。应该也会发生同样的情况openvpn
,但我从未用它测试过openvpn
。
请从这里开始(提示:注释掉该行log_user 0
对于测试很有用)。