В альмаматер сисадминам надоело возиться с firewall'ом и открывать пользователям порты вручную на каждый хост по их неисчислимым требованиям, поэтому запилили VPN. Ну, пока не пережили массовой эпидемии червей, как это произошло в CERN в силу того что у нас всего лишь несколько сотен пользователей нуждаются в удалённом доступе, и секьюрность сети в целом это, видимо, не слишком уменьшает.
VPN предлагается использовать через Cisco Any Connect VPN Client. Ясное дело, под Linux клиент, если даже и есть, то не той он сложности, чтобы вот так, с порога, его вкатывать, когда есть openconnect с ебилдом в официальном дереве портажей.
Одна беда. Реквизиты SSO‐учётки хранить в конфигах я не хочу, как не хочу использовать истекающие куки и добывать сертификат тоже не хочу. А хочу вводить пароль каждый раз, когда нужно подключиться.
Я сделал себе небольшой скрипт на gtkdialog (есть почти везде), который спрашивает у меня иксовым диалогом пароль для соединения. Всё остальное вбито в шелл‐скрипт гвоздями. Меня интересовала главным образом возможность сделать лишь средствами shell‐only диалог для ввода некоторой критической информации.
У gtkdialog непростая судьба, и он несколько рудиментарен в функциях. Его модификация XML (который на самом деле не XML) не описана в больших книжках, а постигается листанием примеров в SVN‐репозитории. Может быть на него и есть какой‐то официальный референс, но я за весь вечер ничего так и не нашёл. Правда архивы форума некоторых коммьюнити оказались весьма информативны. Во всём прочем, у gtkdialog большой бардак с документацией, хотя позапускав примерчики из транка всякий может убедиться, что маленький диалект gtkdialog не такой уж и маленький.
Прежде всего, вот такой небольшой пара‐XML файл сделает вам диалог с полем для вводом пароля и двумя кнопочками:
<window title="TPU VPN"
modal="True"
resizable="False"
type="popup"
type_hint="dialog">
<vbox>
<entry visibility="false"
invisible-char="42">
<variable>PASSWD</variable>
</entry>
<hbox>
<button cancel></button>
<button can-default="true" has-default="true">
<label>OK</label>
<input file stock="gtk-ok"></input>
</button>
</hbox>
</vbox>
</window>
Кнопочки не так нужны такому диалогу как реакция на клавиши: <esc> — для отмены,
<return> — для ввода. Наибеолее прямолинейное решение состояло бы в одновременном
использовании атрибутов signal
и condition
тэга <action>
, вроде вот такого:
<action signal="key-press-event"
condition="command_is_true([ $KEY_RAW = 0x9 ] && echo false)">
echo "$KEY_RAW -- exit"</action>
Однако gtkdialog версии 0.8.2 отчего‐то игнорирует condition
, кажется, в пользу signal
.
Пришлось размаскировать ~amd64
‐ебилд 0.8.3 и кончить вот таким вот шелл‐скриптом (выкладываю целиком):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | #!/bin/sh
# Requires:
# - >=gtkdialog-0.8.3
# - gksudo
# - awk
# - sed
#
# Please, note this openconnect parameters:
VPN_AUTH_SERVER="https://ssl.yourserver.com"
VPN_CFG_FILE="/root/access/only/vpn.conf"
#
# Utils
[ -z $GTKDIALOG ] && GTKDIALOG=$(whereis gtkdialog | awk '{print $2}')
[ -z $GKSUDO ] && GKSUDO=$(whereis gksudo | awk '{print $2}')
[ -z $OPENCONNECT ] && OPENCONNECT=$(whereis openconnect | awk '{print $2}')
[ -z $XTERM ] && XTERM=$(whereis xterm | awk '{print $2}')
if [ -z "$GTKDIALOG" ] \
|| [ -z "$GKSUDO" ] \
|| [ -z "$OPENCONNECT" ] \
|| [ -z "$XTERM" ]
then
echo "Couldn't find one or more of the dependencies."
exit 1
fi
#
# gtkdialog stuff:
MAIN_DIALOG='
<window title="My VPN"
modal="True"
resizable="False"
type_hint="dialog"
center="True">
<vbox>
<entry visibility="false"
invisible-char="42"
caps-lock-warning="true">
<variable>PASSWD</variable>
<action signal="key-press-event"
condition="command_is_true([ $KEY_RAW = 0x24 ] && echo true)"
type="exit">OK</action>
<action signal="key-press-event" condition="command_is_true([ $KEY_RAW = 0x9 ] && echo true)"
condition="command_is_true([ $KEY_RAW = 0x24 ] && echo true)"
type="exit">Cancel</action>
</entry>
<hbox>
<button cancel></button>
<button can-default="true" has-default="true">
<label>OK</label>
<input file stock="gtk-ok"></input>
</button>
</hbox>
</vbox>
</window>
'
export MAIN_DIALOG
#
# Running util:
function open_vpn_tun() {
vpnPasswd=''
dialogEStr=''
while read line; do
key=$(echo $line | awk -F "=" '{print $1}')
val=$(echo $line | awk -F "=" '{print $2}' | sed 's/^"\(.*\)".*/\1/')
case $key in
PASSWD ) vpnPasswd=$val ;;
EXIT ) dialogEStr=$val ;;
esac
done
case $dialogEStr in
OK ) $GKSUDO "xterm -hold -e 'echo \"$vpnPasswd\" | $OPENCONNECT --config=$VPN_CFG_FILE $VPN_AUTH_SERVER'" ;;
# ... whatever dialog exit results can be treated in special manner?
* ) >&2 echo "Exit due to password dialog result (action failed or cancelled by user)."; exit 1 ;;
esac
}
#
# Entry point
case $1 in
#-d | --dump) echo "$MAIN_DIALOG" ;;
#-t | --test) open_vpn_tun one ;;
*) $GTKDIALOG --center --program=MAIN_DIALOG | open_vpn_tun ;;
esac
|
Скрипт использует с пяток утилит, которые, по идее, должны быть в каждом
современном дистрибутиве. openconnect
невозможно использовать без
root‐привелегий, так что пароля придётся вводить аж два — для учётки на VPN, и
для sudo‐сессии. Сама сессия будет инициализированна в xterm, что, вообще,
довольно опасно и нужно будет когда‐нибудь исправить.