2023-01-24 17:46:57 +01:00
#!/bin/sh
#
# Purpose {{{
2023-01-30 17:09:49 +01:00
# This script will try to manage VPN with forticlient v7
2023-01-24 17:46:57 +01:00
# 1. Start a VPN will
# a. Ensure forticlient systemd unit is started.
# b. Try to connect to VPN with profile name.
# 2. Stop a VPN will
# a. Disconnect from the VPN.
# b. Stop and disable forticlient systemd unit.
# c. Restart systemd-resolved to ensure to have correct DNS resolvers.
#
# 2023-01-24
# }}}
# Flags {{{
2023-01-24 18:26:08 +01:00
## Exit on error {{{
2023-01-24 17:46:57 +01:00
set -o errexit
2023-01-24 18:26:08 +01:00
## }}}
## Exit on unset var {{{
### Use "${VARNAME-}" to test a var that may not have been set
set -o nounset
## }}}
## Pipeline command is treated as failed {{{
### Not available in POSIX sh − https://github.com/koalaman/shellcheck/wiki/SC3040
#set -o pipefail
## }}}
## Help with debugging {{{
### Call the script by prefixing it with "TRACE=1 ./script.sh"
if [ " ${ TRACE -0 } " -eq 1 ] ; then set -o xtrace; fi
## }}}
2023-01-24 17:46:57 +01:00
# }}}
# Vars {{{
PROGNAME = $( basename " ${ 0 } " ) ; readonly PROGNAME
2023-01-24 18:26:08 +01:00
PROGDIR = $( readlink --canonicalize-missing $( dirname " ${ 0 } " ) ) ; readonly PROGDIR
2023-01-24 17:46:57 +01:00
ARGS = " ${ * } " ; readonly ARGS
readonly NBARGS = " ${# } "
2023-01-24 18:26:08 +01:00
[ -z " ${ DEBUG - } " ] && DEBUG = 1
2023-01-24 17:46:57 +01:00
## Export DEBUG for sub-script
export DEBUG
## Default values for some vars
readonly REQUEST_STATUS_DEFAULT = "start"
readonly VPN_PROFILE_NAME_DEFAULT = "Universite Rennes 1"
VPN_USER_DEFAULT = $( whoami) ; readonly VPN_USER_DEFAULT
2023-01-30 17:09:49 +01:00
readonly FORTICLIENT_NEW_VERSION = "7.0.0.0"
2023-01-24 17:46:57 +01:00
## Colors
readonly PURPLE = '\033[1;35m'
readonly RED = '\033[0;31m'
readonly RESET = '\033[0m'
readonly COLOR_DEBUG = " ${ PURPLE } "
# }}}
usage( ) { # {{{
cat <<- HELP
usage: $PROGNAME [ -d| -h| -p| -u]
Try to easily manage VPN with forticlient.
EXAMPLES :
- Start VPN with default profife name and default user
${ PROGNAME }
- Stop the VPN
${ PROGNAME } stop
- Start VPN with specific VPN user
${ PROGNAME } --user my_lambda_username start
- Start VPN with specific VPN profile name
${ PROGNAME } --profile "My University name" start
OPTIONS :
-d,--debug
Enable debug messages.
-h,--help
Print this help message.
-p,--profile
Define VPN profile name to use.
Default : ${ VPN_PROFILE_NAME_DEFAULT }
-u,--user
Define VPN user name to use.
Default : ${ VPN_USER_DEFAULT }
2023-01-24 18:26:08 +01:00
For a first connection, try to start \` forticlient gui\` first to configure EMS
2023-01-24 17:46:57 +01:00
and to check profile name.
HELP
}
# }}}
debug_message( ) { # {{{
local_debug_message = " ${ 1 } "
## Print message if DEBUG is enable (=0)
[ " ${ DEBUG } " -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' " DEBUG − ${ PROGNAME } : ${ local_debug_message } "
unset local_debug_message
return 0
}
# }}}
error_message( ) { # {{{
local_error_message = " ${ 1 } "
local_error_code = " ${ 2 } "
## Print message
2023-01-24 18:26:08 +01:00
printf '%b\n' " ERROR − ${ PROGNAME } : ${ RED } ${ local_error_message } ${ RESET } " >& 2
2023-01-24 17:46:57 +01:00
unset local_error_message
exit " ${ local_error_code : =66 } "
}
# }}}
define_vars( ) { # {{{
## If request_status wasn't defined (argument) {{{
2023-01-24 18:26:08 +01:00
if [ -z " ${ request_status - } " ] ; then
2023-01-24 17:46:57 +01:00
## Use default value
readonly request_status = " ${ REQUEST_STATUS_DEFAULT } "
fi
## }}}
## If vpn_profile_name wasn't defined (argument) {{{
2023-01-24 18:26:08 +01:00
if [ -z " ${ vpn_profile_name - } " ] ; then
2023-01-24 17:46:57 +01:00
## Use default value
readonly vpn_profile_name = " ${ VPN_PROFILE_NAME_DEFAULT } "
fi
## }}}
## If vpn_user wasn't defined (argument) {{{
2023-01-24 18:26:08 +01:00
if [ -z " ${ vpn_user - } " ] ; then
2023-01-24 17:46:57 +01:00
## Use default value
readonly vpn_user = " ${ VPN_USER_DEFAULT } "
fi
## }}}
2023-01-30 17:09:49 +01:00
## Try to get forticlient version {{{
is_command_available "dpkg" "| " \
&& forticlient_current_version = $( dpkg --list -- forticlient | awk '/^ii *forticlient/ {print $3}' | sed 's/.:\(.*\)-.*/\1/' )
## }}}
2023-01-24 17:46:57 +01:00
}
# }}}
is_command_available( ) { # {{{
local_command_available_cmd = " ${ 1 } "
debug_prefix = " ${ 2 :- } "
## Return False by default
return_command_available = "1"
if [ " $( command -v ${ local_command_available_cmd } ) " ] ; then
debug_message " ${ debug_prefix } is_command_available − \
${ RED } ${ local_command_available_cmd } ${ COLOR_DEBUG } seems present on this host."
return_command_available = "0"
else
debug_message " ${ debug_prefix } is_command_available − \
${ RED } ${ local_command_available_cmd } ${ COLOR_DEBUG } is not available on this host."
return_command_available = "1"
fi
unset local_command_available_cmd
unset debug_prefix
return " ${ return_command_available } "
}
# }}}
2023-01-30 17:33:55 +01:00
is_version_greater_than( ) { # {{{
first_value = " ${ 1 } "
value_to_compare = " ${ 2 } "
## Return False by default
return_is_version_greater_than = "1"
debug_message " is_version_greater_than − \
Is first value ( ${ first_value } ) greater than the second value ( ${ value_to_compare } ) ."
if printf '%s\n' " ${ first_value } " " ${ value_to_compare } " | sort --check= quiet --version-sort; then
debug_message " is_version_greater_than − ${ first_value } <= ${ value_to_compare } . "
return_is_version_greater_than = "1"
else
debug_message " is_version_greater_than − ${ first_value } > ${ value_to_compare } . "
return_is_version_greater_than = "0"
fi
unset first_value
unset value_to_compare
return " ${ return_is_version_greater_than } "
}
# }}}
2023-01-24 17:46:57 +01:00
main( ) { # {{{
debug_message "--- MAIN BEGIN"
## If forticlient command is not available {{{
### Exit with error
is_command_available "forticlient" "| " \
|| error_message "forticlient is not in PATH, ensure the package is installed." 01
## }}}
## Define all vars
define_vars
debug_message "| Define vars"
2023-01-30 17:09:49 +01:00
## If forticlient version is lower than expected one (7) {{{
### Exit with error
is_version_greater_than " ${ forticlient_current_version } " " ${ FORTICLIENT_NEW_VERSION } " \
|| error_message " Forticlient installed version ( ${ forticlient_current_version } ) seems lower than expected (>= ${ FORTICLIENT_NEW_VERSION } ). Please see fortinet.vpn.v6.sh script instead. " 02
## }}}
2023-01-24 17:46:57 +01:00
## If the VPN must be stopped {{{
if [ " ${ request_status } " = "stop" ] ; then
debug_message "-- Disconnect VPN BEGIN"
### If the VPN is still connected {{{
forticlient_status = $( forticlient vpn status | head --lines= 1 | sed 's/Status: \(.*\)/\1/' || error_message "Error while requesting current VPN status." 22)
if [ " ${ forticlient_status } " = "Connected" ] ; then
debug_message " | VPN is ${ RED } ${ forticlient_status } ${ COLOR_DEBUG } , try to disconnect it… "
2023-01-30 17:09:49 +01:00
### Try to disconnect
2023-01-24 17:46:57 +01:00
forticlient vpn disconnect > /dev/null \
|| error_message "Error when disconnecting VPN." 11
fi
### }}}
### Stop the systemd service {{{
debug_message "| Try to stop and disable forticlient.service unit"
sudo systemctl stop forticlient.service \
|| error_message "Error while stopping forticlient.service unit" 12
### Ensure to disable it
sudo systemctl disable forticlient.service \
|| error_message "Error while disabling forticlient.service unit" 13
### }}}
### Ensure to restart DNS resolver {{{
debug_message "| Try to restart systemd-resolved.service unit to have correct DNS resolvers."
sudo systemctl restart systemd-resolved.service \
|| error_message "Error while restart systemd-resolved.service unit" 14
### }}}
debug_message "-- Disconnect VPN END"
fi
## }}}
## If the VPN must be started {{{
if [ " ${ request_status } " = "start" ] ; then
debug_message "-- Connect VPN BEGIN"
### If forticlient.service unit is not started {{{
2023-01-25 10:35:07 +01:00
systemd_forticlient_status = $( systemctl show --property ActiveState --value forticlient.service || error_message "Error while requesting forticlient.service unit status." 21)
2023-01-27 19:13:02 +01:00
if [ " ${ systemd_forticlient_status } " = "inactive" ] ; then
2023-01-24 17:46:57 +01:00
debug_message "| Try to start forticlient.service unit."
sudo systemctl restart forticlient.service \
|| error_message "Error while (re)starting forticlient.service unit" 22
fi
### }}}
### If forticlient.service unit is started {{{
2023-01-25 10:35:07 +01:00
systemd_forticlient_status = $( systemctl show --property ActiveState --value forticlient.service || error_message "Error while requesting forticlient.service unit status." 21)
2023-01-24 17:46:57 +01:00
if [ " ${ systemd_forticlient_status } " = "active" ] ; then
debug_message " | forticlient.service unit is ${ RED } started ${ COLOR_DEBUG } . "
fi
### }}}
### If the VPN is not connected {{{
forticlient_status = $( forticlient vpn status | head --lines= 1 | sed 's/Status: \(.*\)/\1/' || error_message "Error while requesting current VPN status." 23)
if [ " ${ forticlient_status } " = "Not Running" ] ; then
### If script was started from a launcher {{{
2023-01-24 18:26:08 +01:00
if [ -n " ${ DISPLAY - } " ] && [ " ${ TERM } " = "linux" ] ; then
2023-01-24 17:46:57 +01:00
### Try to launch a new TERM_EMULATOR to ask the password
" ${ TERM_EMULATOR } " -e forticlient vpn connect " ${ vpn_profile_name } " --password --user= " ${ vpn_user } " \
|| error_message " Error when connecting to VPN profile ( ${ vpn_profile_name } ). " 24
### }}}
### Else we consider it was started from CLI {{{
else
### Try to connect
forticlient vpn connect " ${ vpn_profile_name } " --password --user= " ${ vpn_user } " \
|| error_message " Error when connecting to VPN profile ( ${ vpn_profile_name } ). " 25
fi
### }}}
fi
### }}}
### If the VPN is connected {{{
forticlient_status = $( forticlient vpn status | head --lines= 1 | sed 's/Status: \(.*\)/\1/' || error_message "Error while requesting current VPN status." 25)
if [ " ${ forticlient_status } " = "Connected" ] ; then
debug_message " | VPN is ${ RED } ${ forticlient_status } ${ COLOR_DEBUG } . "
fi
### }}}
debug_message "-- Connect VPN END"
fi
## }}}
debug_message "--- MAIN END"
}
# }}}
# Manage arguments # {{{
# This code can't be in a function due to argument management
if [ ! " ${ NBARGS } " -eq "0" ] ; then
manage_arg = "0"
2023-01-24 18:26:08 +01:00
## If the first argument ask for help (h|help|-h|-help|-*h|-*help)
if printf -- '%s' " ${ 1 - } " | grep --quiet --extended-regexp -- " ^-*h(elp)? $" ; then
usage
exit 0
fi
2023-01-24 17:46:57 +01:00
# Parse all argument one by one
2023-01-24 18:26:08 +01:00
while printf -- '%s' " ${ 1 - } " | grep --quiet -- "." ; do
2023-01-24 17:46:57 +01:00
case " ${ 1 } " in
-d| --debug ) ## debug
DEBUG = 0
debug_message "--- Manage argument BEGIN"
; ;
--start| start ) ## Define request_status to start
## Define var
readonly request_status = "start"
; ;
--stop| stop ) ## Define request_status to stop
## Define var
readonly request_status = "stop"
; ;
-p| --profile ) ## Define vpn_profile_name with given arg
## Move to the next argument
shift
## Define var
readonly vpn_profile_name = " ${ 1 } "
; ;
-u| --user ) ## Define vpn_user with given arg
## Move to the next argument
shift
## Define var
readonly vpn_user = " ${ 1 } "
; ;
* ) ## unknow option
printf '%b\n' " ${ RED } Invalid option: ${ 1 } ${ RESET } "
printf '%b\n' "---"
usage
exit 1
; ;
esac
debug_message " | ${ RED } ${ 1 } ${ COLOR_DEBUG } option managed. "
## Move to the next argument
shift
manage_arg = $(( manage_arg+1))
done
debug_message " | ${ RED } ${ manage_arg } ${ COLOR_DEBUG } argument(s) successfully managed. "
else
debug_message "| No arguments/options to manage."
fi
debug_message "--- Manage argument END"
# }}}
main
exit 0