#!/usr/bin/env bash # DESCRIPTION: # creating or deleting client config for openvpn # and # sending config and info to email/telegram # # DEPENDENCIES: # - privileged rights # - chpasswd # - openvpn # - easy-rsa # - tar # - Python 3 # - existing /usr/local/bin/sendmail.py # # PARAMETERS: # 1: "add|del" - add or delete client config # 2: username - client username # 3: password - client password # 4: additional - client description # -f|--force - service will restart after username delete # # FUNCTIONS: # ####################################### # Print message and add to log. # Globals: # logs # Arguments: # 1: message to print and logging ####################################### addtologs() { printf "%s\n" "$(date +'%Y.%m.%d-%H:%M:%S') $1" | tee -a "${logs}" } ####################################### # Exit procedure. # Globals: # show # Arguments: # None ####################################### execquite() { addtologs "execution time is $(($(date +%s)-time)) seconds, exit" exit "${1}" } ####################################### # Error exit procedure. # Globals: # None # Arguments: # 1: message to print and logging ####################################### execerror() { addtologs "error: $1" execquite 1 } ####################################### # Parsing config file and creating global vars. # Globals: # None # Arguments: # None ####################################### getconfig() { logs=/var/log/openvpn/$(basename -s .sh "$(realpath "$0")").log conf="$(dirname "$(realpath "$0")")/$(basename -s .sh "$(realpath "$0")").conf" # easyrsa configuration easyrsadir="/etc/openvpn/easy-rsa" easyrsaidx="${easyrsadir}/pki/index.txt" easyrsaexe="${easyrsadir}/easyrsa" easyrsavar="${easyrsadir}/vars" easyrsacap="openvpnca" ovpncfgdir="/etc/openvpn/client" ovpncfgdef="${ovpncfgdir}/client.conf.default" # mail configuration from="$(grep "from=" "${conf}" | cut -d= -f2)" pass="$(grep "pass=" "${conf}" | cut -d= -f2)" dest="$(grep "dest=" "${conf}" | cut -d= -f2)" smtp="$(grep "smtp=" "${conf}" | cut -d= -f2)" port="$(grep "port=" "${conf}" | cut -d= -f2)" # telegram configuration API_KEY=$(grep "API_KEY=" "${conf}" | cut -d= -f2) CHAT_ID=$(grep "CHAT_ID=" "${conf}" | cut -d= -f2) THRD_ID=$(grep "THRD_ID=" "${conf}" | cut -d= -f2) } ####################################### # Checking user rights. # Globals: # None # Arguments: # None # return: # 0 - if privileged rights, 1 - if not privileged rights ####################################### checkroot() { if [ "${EUID}" -ne 0 ]; then return 1 # false else return 0 # true fi } ####################################### # Creating linux user. # Globals: # clientname # clientpass # Arguments: # None ####################################### createuser() { if ! id -u "${clientname}" >/dev/null 2>&1; then useradd "${clientname}" --shell /sbin/nologin addtologs "created Linux user '${clientname}'" else addtologs "${clientname} Linux user exists, create skipped" fi printf "%s\n" "${clientname}:${clientpass}" | chpasswd addtologs "changed '${clientname}' user password" } ####################################### # Creating Easy-RSA user certificate. # Globals: # easyrsadir # easyrsavar # easyrsaexe # easyrsacap # clientname # clientpass # Arguments: # None ####################################### # shellcheck disable=SC2016 createcert() { if ! grep -w "${clientname}" ${easyrsaidx} | grep "^V" > /dev/null 2>&1; then ( cd "${easyrsadir}" || execerror "" sed -i -e '$aset_var EASYRSA_REQ_CN '"${clientname}"'' "${easyrsavar}" # ${easyrsaexe} --passout=pass:"${clientpass}" --passin=pass:${easyrsacap} build-client-full "${clientname}" ${easyrsaexe} --passin=pass:"${easyrsacap}" build-client-full "${clientname}" nopass sed -i '/EASYRSA_REQ_CN/d' "${easyrsavar}" ) > /dev/null 2>&1 addtologs "created ${clientname} easyrsa certificate" else addtologs "${clientname} certificate exists, create skipped" fi } ####################################### # Creating ovpn config file. # Globals: # easyrsadir # ovpncfgdef # clientname # ovpncfgdir # Arguments: # None ####################################### createovpn() { cd "${easyrsadir}" || execerror "" { cat "${ovpncfgdef}" printf "%s\n" "" "$(cat "${easyrsadir}/pki/ca.crt")" "" printf "%s\n" "" "$(cat "${easyrsadir}/pki/issued/${clientname}.crt")" "" printf "%s\n" "" "$(cat "${easyrsadir}/pki/private/${clientname}.key")" "" printf "%s\n" "" "$(cat "${easyrsadir}/pki/private/ta.key")" "" } >> "${ovpncfgdir}/${clientname}.ovpn" addtologs "created ${clientname} ovpn config file" } ####################################### # Creating tar with config file. # Globals: # easyrsadir # clientname # ovpncfgdir # Arguments: # None ####################################### createtars() { cp "${ovpncfgdir}/${clientname}.ovpn" "${ovpncfgdir}/vpn.cnf" sed -i "s#auth-user-pass#auth-user-pass /config/openvpn/vpn.txt#g" "${ovpncfgdir}/vpn.cnf" { printf "%s\n" "${clientname}" printf "%s\n" "${clientpass}" } >> "${ovpncfgdir}/vpn.txt" cd "${ovpncfgdir}" || execerror "" tar cf "${clientname}.tar" --remove-files vpn.cnf vpn.txt addtologs "created ${clientname} tar with config file" } ####################################### # Creating info file. # Globals: # easyrsadir # easyrsaexe # clientname # ovpncfgdir # Arguments: # None ####################################### createinfo() { cd "${easyrsadir}" || execerror "" validuntil=$(${easyrsaexe} show-cert "${clientname}" | grep "Not After" | cut -d: -f2-) faqprofile=$(printf "%s\n" \ "OpenVPN Connect client:" \ "https://openvpn.net/client/" \ "OpenVPN GUI client:" \ "https://openvpn.net/community-downloads/" \ "" \ "${additional}" \ "" \ "User Login: \`${clientname}\`" \ "User Password: \`${clientpass}\`" \ "Time Expired: ${validuntil}" ) printf "%s\n" "${faqprofile}" > "${ovpncfgdir}/${clientname}.info" addtologs "created ${clientname} info file" } ####################################### # Send email notification about client config. # Globals: # clientname # faqprofile # ovpncfgdir # from # pass # dest # smtp # port # Arguments: # None ####################################### startsendmail() { subj="[OVPN Settings] $(cat /etc/hostname): ${clientname}.ovpn client profile" ( python3 /usr/local/bin/sendmail.py \ -u "${from}" \ -p "${pass}" \ -d "${dest}" \ --smtp "${smtp}" \ --port "${port}" \ --stls "True" \ --subj "${subj}" \ --text "$(printf "%s\n" "${faqprofile}" | sed 's|`||g')" \ --file "${ovpncfgdir}/${clientname}.ovpn,${ovpncfgdir}/${clientname}.tar" ) > /dev/null 2>&1 addtologs "sent mail with subject '${subj}' to ${dest}" } ####################################### # Send telegram notification about client config. # Globals: # clientname # faqprofile # ovpncfgdir # API_KEY # CHAT_ID # THRD_ID # Arguments: # None ####################################### # shellcheck disable=SC2030,2031 startsendtlgm() { ( API_URL="https://api.telegram.org/bot${API_KEY}/sendMediaGroup?chat_id=${CHAT_ID}" if grep -q "_" <<< "${CHAT_ID}"; then THRD_ID=$(printf "%s\n" "${CHAT_ID}" | cut -d_ -f2) CHAT_ID=$(printf "%s\n" "${CHAT_ID}" | cut -d_ -f1) fi if [ -n "${THRD_ID}" ]; then API_URL="${API_URL}&message_thread_id=${THRD_ID}" fi curl "${API_URL}" \ -F "media=[{\"type\": \"document\", \"media\": \"attach://ovpn\", \"caption\": \"${faqprofile}\", \"parse_mode\": \"Markdown\"}, {\"type\": \"document\", \"media\": \"attach://tars\" }]" \ -F "ovpn=@${ovpncfgdir}/${clientname}.ovpn" \ -F "tars=@${ovpncfgdir}/${clientname}.tar" ) > /dev/null 2>&1 addtologs "sent telegram media with ${clientname}.ovpn client profile to ${CHAT_ID}" } ####################################### # Deleting linux user. # Globals: # clientname # Arguments: # None ####################################### deleteuser() { if id -u "${clientname}" > /dev/null 2>&1; then ( userdel -f -r "${clientname}" ) > /dev/null 2>&1 addtologs "deleted Linux user '${clientname}'" else addtologs "${clientname} Linux user does not exist, delete skipped" fi } ####################################### # Deleting Easy-RSA user certificate. # Globals: # easyrsadir # easyrsavar # easyrsaexe # easyrsacap # clientname # Arguments: # None ####################################### deletecert() { if grep -w "${clientname}" ${easyrsaidx} > /dev/null 2>&1; then ( cd "${easyrsadir}" || execerror ${easyrsaexe} --batch --passin=pass:"${easyrsacap}" revoke "${clientname}" ${easyrsaexe} --batch --passin=pass:"${easyrsacap}" gen-crl ) > /dev/null 2>&1 addtologs "revoked ${clientname} easyrsa certificate" else addtologs "${clientname} certificate does not exist, revoke skipped" fi } ####################################### # Deleting ovpn config file. # Globals: # clientname # ovpncfgdir # Arguments: # None ####################################### deleteovpn() { if [ -e "${ovpncfgdir}/${clientname}.ovpn" ]; then rm -f "${ovpncfgdir}/${clientname}.ovpn" addtologs "deleted ${clientname} ovpn config file" else addtologs "${clientname} ovpn config does not exist, delete skipped" fi } ####################################### # Deleting tar with config file. # Globals: # clientname # ovpncfgdir # Arguments: # None ####################################### deletetars() { if [ -e "${ovpncfgdir}/${clientname}.tar" ]; then rm -f "${ovpncfgdir}/${clientname}.tar" addtologs "deleted ${clientname} tar with config" else addtologs "${clientname} tar does not exist, delete skipped" fi } ####################################### # Deleting info file. # Globals: # clientname # ovpncfgdir # Arguments: # None ####################################### deleteinfo() { if [ -e "${ovpncfgdir}/${clientname}.info" ]; then rm -f "${ovpncfgdir}/${clientname}.info" addtologs "deleted ${clientname} info file" else addtologs "${clientname} info file does not exist, delete skipped" fi } # # VARIABLES: # clienttodo=$1 clientname=$2 clientpass=$3 additional=$4 resetforce=0 for argument in "${@}"; do case $argument in -f | --force ) resetforce=1 ;; -* ) ;; esac done time=$(date +%s) logs=/dev/null # # MAIN: # if checkroot; then getconfig if [ "${clienttodo}" == "add" ] && \ [ -n "${clientname}" ] && \ [ "${#clientpass}" -ge 8 ]; then createuser createcert createovpn createtars createinfo startsendmail startsendtlgm elif [ "${clienttodo}" == "del" ] && \ [ -n "${clientname}" ]; then deleteuser deletecert deleteovpn deletetars deleteinfo if [ "${resetforce}" -eq 1 ];then addtologs "restarting openvpn@server..." systemctl restart openvpn@server fi else printf "%s\n" "Usage example: $0 'add' 'username(surname)' 'password(not less 8 symbols)'" printf "%s\n" "Usage example: $0 'add' 'username(surname)' 'password(not less 8 symbols)' 'additional client description'" printf "%s\n" "Usage example: $0 'del' 'username(surname)'" printf "%s\n" "Usage example: $0 'del' 'username(surname)' -f" fi else execerror "Restart this as root!" fi execquite 0