From 4d6fb8b1647fc7a2b873636f274f7da04e773f6a Mon Sep 17 00:00:00 2001 From: Henrik Bengtsson Date: Sat, 18 May 2024 11:30:20 -0700 Subject: [PATCH] Add 'ucsf vpn install-vpnc' --- Makefile | 2 +- NEWS.md | 5 + README.md | 2 +- bin/ucsf-vpn | 133 +++++++++++++++++-- build.sh | 6 +- src/incl/cli.sh | 2 +- src/incl/openconnect.sh | 2 +- src/ucsf-vpn.sh | 87 ++++++++++-- src/vpnc/{connect.d => }/ucsf-vpn-flavors.sh | 3 +- 9 files changed, 215 insertions(+), 27 deletions(-) rename src/vpnc/{connect.d => }/ucsf-vpn-flavors.sh (93%) diff --git a/Makefile b/Makefile index c5b7666..c5057f7 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ README.md: README.md.tmpl bin/ucsf-vpn ## Check code using static-code analysis shellcheck: echo "ShellCheck $$(shellcheck --version | grep version:)" - cd src; shellcheck -x ucsf-vpn.sh vpnc/connect.d/ucsf-vpn-flavors.sh + cd src; shellcheck -x ucsf-vpn.sh vpnc/ucsf-vpn-flavors.sh shellcheck bin/ucsf shellcheck bin/ucsf-vpn diff --git a/NEWS.md b/NEWS.md index 7fa189d..890567c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,11 @@ ucsf-vpn * OpenConnect is now the only supported method. Support for Pulse Secure GUI client has been dropped. +### New Features + + * Add `ucsf vpn install-vpnc`, which is required before using + `--flavor=`. + ### Deprecated and Defunct * The use of `--method=pulse`, which uses the Pulse Secure GUI client diff --git a/README.md b/README.md index 4b138b6..7ab3048 100644 --- a/README.md +++ b/README.md @@ -201,7 +201,7 @@ Useful resources: * UCSF Managing Your Passwords: - https://it.ucsf.edu/services/managing-your-passwords -Version: 5.8.0-9002 +Version: 5.8.0-9003 Copyright: Henrik Bengtsson (2016-2024) License: GPL (>= 2.1) [https://www.gnu.org/licenses/gpl.html] Source: https://github.com/HenrikBengtsson/ucsf-vpn diff --git a/bin/ucsf-vpn b/bin/ucsf-vpn index 9df046a..6dde4b3 100755 --- a/bin/ucsf-vpn +++ b/bin/ucsf-vpn @@ -108,7 +108,7 @@ ### * UCSF Managing Your Passwords: ### - https://it.ucsf.edu/services/managing-your-passwords ### -### Version: 5.8.0-9002 +### Version: 5.8.0-9003 ### Copyright: Henrik Bengtsson (2016-2024) ### License: GPL (>= 2.1) [https://www.gnu.org/licenses/gpl.html] ### Source: https://github.com/HenrikBengtsson/ucsf-vpn @@ -222,7 +222,7 @@ function help() { local what res what=$1 - res=$(grep "^###" "$0" | grep -vE '^(####|### whatis: )' | cut -b 5- | sed "s/{{pulsesvc_version}}/$(pulsesvc_version)/" | sed "s/{{openconnect_version}}/$(openconnect_version)/") + res=$(grep "^###" "$0" | grep -vE '^(####|### whatis: )' | cut -b 5- | sed "s/{{openconnect_version}}/$(openconnect_version)/") if [[ $what == "full" ]]; then res=$(echo "$res" | sed '/^---/d') @@ -851,7 +851,7 @@ function openconnect_start() { ## Assert that --flavor= exists, if specified flavor_home > /dev/null - + assert_sudo "start" ## Load user credentials from file? @@ -1241,6 +1241,112 @@ function flavor_home() { } +function find_vpnc-script() { + local file + file=$(openconnect --help | grep -E "vpnc-script" | sed 's/[^"]*"//' | sed 's/".*//') + if [[ -z "${file}" ]]; then + merror "Failed to locate the default 'vpnc-script' script. It appears that openconnect --help does not specify it" + fi + echo "${file}" +} + +function find_hooks_dir() { + local file dir + find_vpnc-script > /dev/null + file=$(find_vpnc-script) + dir=$(grep -E "^HOOKS_DIR=" "${file}" | sed 's/[^=]*=//' | sed 's/[[:blank:]]$//') + echo "${dir}" +} + + +function ucsf-vpn-flavors_code() { +cat << HOOK_SCRIPT_EOF +#!/bin/sh +#################################################################### +# Use user-specific UCSF VPN configurations +# +# Install: +# ucsf vpn install-vpnc +# +# Requires: +# https://github.com/HenrikBengtsson/ucsf-vpn +#################################################################### + +## Called via 'ucsf-vpn'? +if [ -n "\${UCSF_VPN_VERSION}" ]; then + ucsf_vpn_log() { + echo "[\$(date --iso-8601=seconds)] \$*" >> "\${UCSF_VPN_LOGFILE}" + } + + ucsf_vpn_log "\$* ..." + ucsf_vpn_log "UCSF_VPN_VERSION=\${UCSF_VPN_VERSION}" + ucsf_vpn_log "UCSF_VPN_FLAVOR=\${UCSF_VPN_FLAVOR}" + + if [ "\$1" = "connect" ]; then + _hook_="pre-connect" + else + _hook_="\$1" + fi + ucsf_vpn_log "hook=\${_hook_}" + + _hook_file_="\${UCSF_VPN_FLAVOR}/\${_hook_}.sh" + ucsf_vpn_log "\${_hook_file_} ..." + if [ -f "\${_hook_file_}" ]; then + _hook_status_="done" + + # shellcheck disable=SC1090 + . "\${_hook_file_}" || _hook_status_="error" + + ucsf_vpn_log "\${_hook_file_} ... \${_hook_status_}" + else + ucsf_vpn_log "\${_hook_file_} ... non-existing" + fi + + ucsf_vpn_log "\$* ... done" +fi +HOOK_SCRIPT_EOF +} + +function install_vpnc() { + local file filename dest hooks_dir dir path + + file="$(mktemp -d)/ucsf-vpn-flavors.sh" + ucsf-vpn-flavors_code > "${file}" + + find_vpnc-script > /dev/null + hooks_dir=$(find_hooks_dir) + + mdebug "install_vpnc() ..." + mdebug " - hooks folder: ${hooks_dir}" + mdebug " - template: ${file}" + + assert_sudo "install-vpnc" + + sudo mkdir -p "${hooks_dir}" + [[ -d "${hooks_dir}" ]] || merror "Failed to create directory: ${hooks_dir}" + + filename=$(basename "${file}") + dest="${hooks_dir}/${filename}" + sudo cp "${file}" "${dest}" + sudo chmod ugo+r "${dest}" + [[ -f "${dest}" ]] || merror "Failed to create file: ${dest}" + mdebug " - copied generic hook script: ${dest}" + + for dir in pre-init connect post-connect disconnect post-disconnect attempt-reconnect post-attempt-reconnect reconnect; do + path=${hooks_dir}/${dir} + sudo mkdir -p "${path}" + [[ -d "${path}" ]] || merror "Failed to create directory: ${path}" + dest="${path}/${filename}" + sudo ln -fs "${hooks_dir}/${filename}" "${dest}" + [[ -L "${dest}" ]] || merror "Failed to create symbol link: ${dest} -> ${hooks_dir}/${filename}" + mdebug " - added symbolic link: ${dest} -> ${hooks_dir}/${filename}" + done + + rm "${file}" + mdebug "install_vpnc() ... done" +} + + function logfile() { local path file @@ -1309,23 +1415,25 @@ while [[ $# -gt 0 ]]; do ## Commands: if [[ "$1" == "start" ]]; then - action=start + action=$1 elif [[ "$1" == "stop" ]]; then - action=stop + action=$1 elif [[ "$1" == "toggle" ]]; then - action=toggle + action=$1 force=true elif [[ "$1" == "restart" ]]; then - action=restart + action=$1 force=true elif [[ "$1" == "status" ]]; then - action=status + action=$1 elif [[ "$1" == "details" ]]; then - action=details + action=$1 elif [[ "$1" == "routing" ]]; then - action=routing + action=$1 + elif [[ "$1" == "install-vpnc" ]]; then + action=$1 elif [[ "$1" == "log" ]]; then - action=log + action=$1 elif [[ "$1" == "troubleshoot" ]]; then pulse_is_defunct elif [[ "$1" == "open-gui" ]]; then @@ -1559,6 +1667,9 @@ elif [[ $action == "details" ]]; then elif [[ $action == "routing" ]]; then routing_details _exit $? +elif [[ $action == "install-vpnc" ]]; then + install_vpnc + _exit $? elif [[ $action == "start" ]]; then openconnect_start res=$? diff --git a/build.sh b/build.sh index df9cdc3..498b91b 100755 --- a/build.sh +++ b/build.sh @@ -12,7 +12,11 @@ grep -q -F 'source "${incl}/' "${tmpl}" file=$(sed -E 's/source "[$][{](incl)[}][/]([^.]+[.]sh)"/\1\/\2/' <<< "${line}") cat "src/${file}" echo - elif ! grep -q -E "^(# shellcheck source=|this=|incl=)" <<< "${line}"; then + elif [[ "${line}" == *'cat "${vpnc}/ucsf-vpn-flavors.sh"'* ]]; then + echo 'cat << HOOK_SCRIPT_EOF' + sed -E 's/[$]/\\$/g' src/vpnc/ucsf-vpn-flavors.sh + echo 'HOOK_SCRIPT_EOF' + elif ! grep -q -E "^(# shellcheck source=|this=|vpnc=|incl=)" <<< "${line}"; then echo "${line}" if [[ "${line}" == "#! /usr/bin/env bash" ]]; then echo "###################################################################" diff --git a/src/incl/cli.sh b/src/incl/cli.sh index 2de73be..0b5d2b9 100755 --- a/src/incl/cli.sh +++ b/src/incl/cli.sh @@ -9,7 +9,7 @@ function help() { local what res what=$1 - res=$(grep "^###" "$0" | grep -vE '^(####|### whatis: )' | cut -b 5- | sed "s/{{pulsesvc_version}}/$(pulsesvc_version)/" | sed "s/{{openconnect_version}}/$(openconnect_version)/") + res=$(grep "^###" "$0" | grep -vE '^(####|### whatis: )' | cut -b 5- | sed "s/{{openconnect_version}}/$(openconnect_version)/") if [[ $what == "full" ]]; then res=$(echo "$res" | sed '/^---/d') diff --git a/src/incl/openconnect.sh b/src/incl/openconnect.sh index dcce858..ea0248e 100755 --- a/src/incl/openconnect.sh +++ b/src/incl/openconnect.sh @@ -77,7 +77,7 @@ function openconnect_start() { ## Assert that --flavor= exists, if specified flavor_home > /dev/null - + assert_sudo "start" ## Load user credentials from file? diff --git a/src/ucsf-vpn.sh b/src/ucsf-vpn.sh index a082bef..3f73b3e 100755 --- a/src/ucsf-vpn.sh +++ b/src/ucsf-vpn.sh @@ -12,6 +12,7 @@ ### status Display VPN connection status ### details Display connection details in JSON format ### routing Display IP routing details +### install-vpnc Install 'ucsf-vpn' hook scripts ### log Display log file ### ### Options: @@ -105,7 +106,7 @@ ### * UCSF Managing Your Passwords: ### - https://it.ucsf.edu/services/managing-your-passwords ### -### Version: 5.8.0-9002 +### Version: 5.8.0-9004 ### Copyright: Henrik Bengtsson (2016-2024) ### License: GPL (>= 2.1) [https://www.gnu.org/licenses/gpl.html] ### Source: https://github.com/HenrikBengtsson/ucsf-vpn @@ -113,6 +114,7 @@ call="$0 $*" this="${BASH_SOURCE%/}"; [[ -L "${this}" ]] && this=$(readlink "${this}") incl="$(dirname "${this}")/incl" +vpnc="$(dirname "${this}")/vpnc" # shellcheck source=incl/output.sh source "${incl}/output.sh" @@ -349,6 +351,68 @@ function flavor_home() { } +function find_vpnc-script() { + local file + file=$(openconnect --help | grep -E "vpnc-script" | sed 's/[^"]*"//' | sed 's/".*//') + if [[ -z "${file}" ]]; then + merror "Failed to locate the default 'vpnc-script' script. It appears that openconnect --help does not specify it" + fi + echo "${file}" +} + +function find_hooks_dir() { + local file dir + find_vpnc-script > /dev/null + file=$(find_vpnc-script) + dir=$(grep -E "^HOOKS_DIR=" "${file}" | sed 's/[^=]*=//' | sed 's/[[:blank:]]$//') + echo "${dir}" +} + + +function ucsf-vpn-flavors_code() { + cat "${vpnc}/ucsf-vpn-flavors.sh" +} + +function install_vpnc() { + local file filename dest hooks_dir dir path + + file="$(mktemp -d)/ucsf-vpn-flavors.sh" + ucsf-vpn-flavors_code > "${file}" + + find_vpnc-script > /dev/null + hooks_dir=$(find_hooks_dir) + + mdebug "install_vpnc() ..." + mdebug " - hooks folder: ${hooks_dir}" + mdebug " - template: ${file}" + + assert_sudo "install-vpnc" + + sudo mkdir -p "${hooks_dir}" + [[ -d "${hooks_dir}" ]] || merror "Failed to create directory: ${hooks_dir}" + + filename=$(basename "${file}") + dest="${hooks_dir}/${filename}" + sudo cp "${file}" "${dest}" + sudo chmod ugo+r "${dest}" + [[ -f "${dest}" ]] || merror "Failed to create file: ${dest}" + mdebug " - copied generic hook script: ${dest}" + + for dir in pre-init connect post-connect disconnect post-disconnect attempt-reconnect post-attempt-reconnect reconnect; do + path=${hooks_dir}/${dir} + sudo mkdir -p "${path}" + [[ -d "${path}" ]] || merror "Failed to create directory: ${path}" + dest="${path}/${filename}" + sudo ln -fs "${hooks_dir}/${filename}" "${dest}" + [[ -L "${dest}" ]] || merror "Failed to create symbol link: ${dest} -> ${hooks_dir}/${filename}" + mdebug " - added symbolic link: ${dest} -> ${hooks_dir}/${filename}" + done + + rm "${file}" + mdebug "install_vpnc() ... done" +} + + function logfile() { local path file @@ -417,23 +481,25 @@ while [[ $# -gt 0 ]]; do ## Commands: if [[ "$1" == "start" ]]; then - action=start + action=$1 elif [[ "$1" == "stop" ]]; then - action=stop + action=$1 elif [[ "$1" == "toggle" ]]; then - action=toggle + action=$1 force=true elif [[ "$1" == "restart" ]]; then - action=restart + action=$1 force=true elif [[ "$1" == "status" ]]; then - action=status + action=$1 elif [[ "$1" == "details" ]]; then - action=details + action=$1 elif [[ "$1" == "routing" ]]; then - action=routing + action=$1 + elif [[ "$1" == "install-vpnc" ]]; then + action=$1 elif [[ "$1" == "log" ]]; then - action=log + action=$1 elif [[ "$1" == "troubleshoot" ]]; then pulse_is_defunct elif [[ "$1" == "open-gui" ]]; then @@ -667,6 +733,9 @@ elif [[ $action == "details" ]]; then elif [[ $action == "routing" ]]; then routing_details _exit $? +elif [[ $action == "install-vpnc" ]]; then + install_vpnc + _exit $? elif [[ $action == "start" ]]; then openconnect_start res=$? diff --git a/src/vpnc/connect.d/ucsf-vpn-flavors.sh b/src/vpnc/ucsf-vpn-flavors.sh similarity index 93% rename from src/vpnc/connect.d/ucsf-vpn-flavors.sh rename to src/vpnc/ucsf-vpn-flavors.sh index 7f72729..91d3d27 100644 --- a/src/vpnc/connect.d/ucsf-vpn-flavors.sh +++ b/src/vpnc/ucsf-vpn-flavors.sh @@ -3,8 +3,7 @@ # Use user-specific UCSF VPN configurations # # Install: -# mkdir -p /etc/vpnc/connect.d/ -# cp ucsf-vpn-flavors.sh /etc/vpnc/connect.d/ +# ucsf vpn install-vpnc # # Requires: # https://github.com/HenrikBengtsson/ucsf-vpn