From 93224e376888b7f535e639ac018ba4b85fed974b Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Tue, 8 Aug 2023 10:50:08 +0900 Subject: [PATCH] Update create/delete scripts, add rename script rename user script added: renames user, home dir and connected files. delete script fix with remove of not needed options (-g) Update all scripts to exit only after all errors are shown, unless it is a critical run error. --- Readme.md | 19 ++++ bin/create_user.sh | 25 ++++-- bin/delete_user.sh | 21 ++--- bin/rename_user.sh | 215 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 251 insertions(+), 29 deletions(-) diff --git a/Readme.md b/Readme.md index bf2fd09..5983160 100644 --- a/Readme.md +++ b/Readme.md @@ -256,3 +256,22 @@ The script can be put into the crontab and run once a month, it prints to STDOUT ```crontab 0 2 1 * * root /root/users/bin/check_last_login.sh | mail -s "User Account check: $(hostname)" ``` + +## Delete users + +`bin/delete_user.sh -t -b ...` + +Deletes one or more users + +- `-t` test, no action done +- `-b` do not create a backup + +Unless `-b` is set the home folder and public key in /etc/ssh will be backed up. +Flags user with #DELETED-YYYYMMDD_HHmmss:id;... in the user_list.txt file + +## Rename user + +`bin/rename_user.sh -t -o -n ` + +Renames a user including the home directory, public key files and any other connected data. +Also updates the user_list.txt diff --git a/bin/create_user.sh b/bin/create_user.sh index 46acf93..4fc6ed1 100755 --- a/bin/create_user.sh +++ b/bin/create_user.sh @@ -28,7 +28,7 @@ TEST=0; # no actions will be run INFO=0; # no creation of anything, just print info strings GO=1; # without this flag the script will exit with an info box -while getopts ":tih:" opt; do +while getopts ":gtih:" opt; do case "${opt}" in g|go) GO=1; @@ -50,6 +50,7 @@ while getopts ":tih:" opt; do ;; esac; done; +error=0; # hostname for output file only host=$(hostname); timestamp=$(date +%Y%m%d-%H%M%S) @@ -71,18 +72,22 @@ if [ ! -z "${HOME_LOCATION}" ]; then # must start with / as it has to be from root if [ "${HOME_LOCATION##/*}" ]; then echo "Home location folder must start with a slash (/): ${HOME_LOCATION}"; - exit; + error=1; fi; # must be valid folder if [ ! -d "${HOME_LOCATION}" ]; then echo "Folder for home location does not exists: ${HOME_LOCATION}"; - exit; + error=1; fi; fi; # the new location for home, if override is set will be created in this folder HOME_FOLDER="${HOME_LOCATION}${HOME_BASE}" if [ ! -d "${HOME_FOLDER}" ]; then echo "Home folder location not found: ${HOME_FOLDER}"; + error=1; +fi; +# home dir error abort +if [ $error -eq 1 ]; then exit; fi; ROOT_FOLDER="${BASE_FOLDER}../"; @@ -123,18 +128,18 @@ fi; # if [ ! command -v pwgen &> /dev/null ]; then if [ -z $(command -v pwgen) ]; then echo "Missing pwgen application, aborting"; - exit; + error=1; fi; # check for zip # if [ ! command -v zip &> /dev/null ]; then if [ -z $(command -v zip) ]; then echo "Missing zip application, aborting"; - exit; + error=1; fi; # check if sshallow or sshfoward group exists if [ -z $(cat /etc/group | grep "sshallow:") ]; then echo "Missing ssh access group: sshallow"; - exit; + error=1; fi; # flag if we can set ssh forward if [ ! -z $(cat /etc/group | grep "sshforward:") ]; then @@ -143,7 +148,7 @@ fi; # check if user list file exists if [ ! -f "${ROOT_FOLDER}${input_file}" ]; then echo "Missing ${ROOT_FOLDER}${input_file}"; - exit; + error=1; fi; # make sure my own folder is owned by root and 600 (except for testing) if [ $(stat -c %a .) != "600" ]; then @@ -152,7 +157,7 @@ fi; if [ $(whoami) != "root" ]; then if [ ${TEST} -eq 0 ] && [ ${INFO} -eq 0 ]; then echo "Script must be run as root user"; - exit; + error=1; else echo "!!!! Script must be run as root user !!!!"; fi; @@ -162,6 +167,10 @@ fi; if [ $GO -eq 0 ]; then echo "Script has to be run with -g option for actual user creation."; echo "It is recommended to run -t for testing prior to user creation."; + error=1; +fi; + +if [ $error -eq 1 ]; then exit; fi; diff --git a/bin/delete_user.sh b/bin/delete_user.sh index be9d9e0..300bc26 100755 --- a/bin/delete_user.sh +++ b/bin/delete_user.sh @@ -12,13 +12,9 @@ # This will permaently remove the user TEST=0; # do not run any actions -GO=1; # without this flag the script will exit with an info box BACKUP=1; -while getopts ":tih:" opt; do +while getopts ":tb" opt; do case "${opt}" in - g|go) - GO=1; - ;; t|test) TEST=1; ;; @@ -53,7 +49,7 @@ fi; # check tar, bzip2 is installed if backup = 1 host=$(hostname); -timestamp=$(date +%Y%m%d-%H%M%S) +timestamp=$(date +%Y%m%d-%H%M%S); # character to set getween info blocks separator="#"; # base folder for all data @@ -92,6 +88,7 @@ fi; # $1 ... $n for username in "$@"; do + error=0; # skip if there is an option hidden if [[ ${_arg:0:1} = "-" ]]; then continue; @@ -108,18 +105,18 @@ for username in "$@"; do if ! id "${username}" &>/dev/null; then # not in passwd echo "[!!!] User ${username} does not exist in /etc/passwd"; - if [ ${TEST} -eq 0 ]; then - break; - fi; + error=1; fi; user_list_entry=$(grep "${username}" "${user_list_file}"); if [ -z "${user_list_entry}" ]; then echo "[!!!] User ${username} does not exist in user_list.txt file"; - if [ ${TEST} -eq 0 ]; then - break; - fi; + error=1; elif [[ "${user_list_entry}" =~ ^#DELETED ]]; then echo "[!!!] User ${username} is flagged as deleted in user_list.txt file"; + error=1; + fi; + + if [ $error -eq 1 ]; then if [ ${TEST} -eq 0 ]; then break; fi; diff --git a/bin/rename_user.sh b/bin/rename_user.sh index ead971f..c053f39 100644 --- a/bin/rename_user.sh +++ b/bin/rename_user.sh @@ -4,22 +4,32 @@ # - rename user name # - rename home folder + owner # - rename public key file in /etc/ssh/ +# - rename in user_list.txt +# - rename created public key file TEST=0; # do not run any actions -GO=1; # without this flag the script will exit with an info box -BACKUP=1; -while getopts ":tih:" opt; do +OLD_USERNAME=""; +NEW_USERNAME=""; +while getopts ":to:n:" opt; do case "${opt}" in - g|go) - GO=1; - ;; t|test) TEST=1; ;; + o|old-user) + if [ -z "${OLD_USERNAME}" ]; then + OLD_USERNAME="${OPTARG}"; + fi; + ;; + n|new-user) + if [ -z "${NEW_USERNAME}" ]; then + NEW_USERNAME="${OPTARG}"; + fi; + ;; \?) echo -e "\n Option does not exist: ${OPTARG}\n"; echo "Use -t for test"; - echo "Use -g for actually creation run"; + echo "-o: Current user"; + echo "-n: New username"; exit 1; ;; esac; @@ -35,9 +45,196 @@ if [ $(whoami) != "root" ]; then fi; fi; -if [ $# -eq 0 ]; then - echo "Must give at least one user name"; +error=0; +host=$(hostname); +timestamp=$(date +%Y%m%d-%H%M%S); +# character to set getween info blocks +separator="#"; +# base folder for all data +BASE_FOLDER=$(dirname $(readlink -f $0))"/"; +root_folder="${BASE_FOLDER}../"; +SSH_KEYGEN_FOLDER_CREATED_PUB='ssh-keygen-created-pub/'; +input_file='user_list.txt'; +user_list_file="${root_folder}${input_file}"; +default_ssh_keytype='ed25519'; +ssh_keytype=''; +# log file +LOG="${BASE_FOLDER}/../log/rename_user."$(date +"%F_%H%m%S"); +if [ ${TEST} -eq 0 ]; then + LOG="${LOG}.log"; +else + LOG="${LOG}.test.log"; +fi; +# ignore users (root and admin users) +ignore_users=('root' 'ec2-user' 'ubuntu' 'admin'); +# detect ssh authorized_keys setting +SSH_CENTRAL_AUTHORIZED_FILE_FOLDER=''; +SSH_AUTHORIZED_FILE=''; +for cf in $(grep "^AuthorizedKeysFile" /etc/ssh/sshd_config | grep "%u"); do + if [ ! -z $(echo "${cf}" | grep "%u") ]; then + SSH_CENTRAL_AUTHORIZED_FILE_FOLDER=$(echo "${cf}" | sed -e 's/%u//'); + if [ ! -d "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}" ]; then + echo "ssh central authorized_file folder could not be found: ${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}"; + error=1; + fi; + fi; +done; +if [ ! -f "${user_list_file}" ]; then + echo "${input_file} is missing"; + error=1; +fi; + +if [ -z "${OLD_USERNAME}" ] || [ -z "${NEW_USERNAME}" ]; then + echo "[!!!] Current and new username must be provided"; + error=1; +fi; + +if [ "${OLD_USERNAME}" = "${NEW_USERNAME}" ]; then + echo "[!!!] Current and new username cannot be the same"; + error=1; +fi; + +if ! [[ "${NEW_USERNAME}" =~ ^[a-z0-9]+([.a-z0-9_-]+[a-z0-9])?$ ]]; then + echo "User name can only be a-z 0-9 - _ . and cannot start or end with - . or _: ${NEW_USERNAME}"; + error=1; +fi; + +# skip ignore users, note that if a user is not in the sshallow list anyway +# we skip them too, this is just in case check +if [[ " ${ignore_users[*]} " =~ " ${OLD_USERNAME} " ]]; then + echo "[!] User ${OLD_USERNAME} is in the ignore user list"; + error=1; +fi; +if [[ " ${ignore_users[*]} " =~ " ${NEW_USERNAME} " ]]; then + echo "[!] User ${NEW_USERNAME} is in the ignore user list"; + error=1; +fi; +# user must exist in user_list.txt and /etc/passwd +# if missing in or another do not continue +if ! id "${OLD_USERNAME}" &>/dev/null; then + # not in passwd + echo "[!!!] User ${OLD_USERNAME} does not exist in /etc/passwd"; + error=1; +fi; +if id "${NEW_USERNAME}" &>/dev/null; then + # not in passwd + echo "[!!!] User ${NEW_USERNAME} exists in /etc/passwd"; + error=1; +fi; +if [ -f "${user_list_file}" ]; then + user_list_entry=$(grep "${OLD_USERNAME}" "${user_list_file}"); + if [ -z "${user_list_entry}" ]; then + echo "[!!!] User ${OLD_USERNAME} does not exist in user_list.txt file"; + error=1; + fi; + # if the old user exists but as DELETED -> no go + if [ ! -z $(echo "${user_list_entry}" | grep "#DELETED-") ]; then + echo "[!!!] User ${OLD_USERNAME} has been flagged as deleted"; + error=1; + fi; + # if new user name already exists in user list file for whatever reason + if [ $(grep "${NEW_USERNAME}" "${user_list_file}") ]; then + echo "[!!!] User ${NEW_USERNAME} exists in user_list.txt file"; + error=1; + fi; +fi; +# exit on any error +if [ $error -eq 1 ]; then exit; fi; +# parse user list entry for group/hostname/ssh type key to build ssh key list + +# POS 3: groups +_group=$(echo "${user_list_entry}" | cut -d ";" -f 3 | tr A-Z a-z | tr -d ' '); +group=$(echo "${_group}" | cut -d "," -f 1); +# POS 6: override host name, lowercase and spaces removed +_hostname=$(echo "${user_list_entry}" | cut -d ";" -f 6 | tr A-Z a-z | tr -d ' '); +if [ -z "${_hostname}" ]; then + hostname=${host}; +else + hostname=${_hostname}; +fi; +# POS 7: ssh keytype override +_ssh_keytype=$(echo "${user_list_entry}" | cut -d ";" -f 7 | tr A-Z a-z | tr -d ' '); +if [ "${_ssh_keytype}" = "rsa" ]; then + ssh_keytype="${_ssh_keytype}"; +else + ssh_keytype=${default_ssh_keytype}; +fi; + +echo "* Rename ${OLD_USERNAME} to ${NEW_USERNAME}"; + +old_home_dir=$(getent passwd "${OLD_USERNAME}" | cut -d: -f6); +new_home_dir=$(echo "${old_home_dir}" | sed -e "s/\/${OLD_USERNAME}$/\/${NEW_USERNAME}/"); +# rename user +if [ $TEST -eq 0 ]; then + echo "usermod with ${new_home_dir}"; + usermod -l ${NEW_USERNAME} -m -d "${new_home_dir}" ${OLD_USERNAME}; +else + echo "$> usermod -l ${NEW_USERNAME} -m -d \"${new_home_dir}\" ${OLD_USERNAME};"; +fi +# check that home folder is renamed and owned by new user + +# check if spool exists +if [ -f "/var/spool/mail/${OLD_USERNAME}" ]; then + if [ $TEST -eq 0 ]; then + echo "rename to /var/spool/mail/${NEW_USERNAME}"; + mv "/var/spool/mail/${OLD_USERNAME}" "/var/spool/mail/${NEW_USERNAME}"; + else + echo "$> mv \"/var/spool/mail/${OLD_USERNAME}\" \"/var/spool/mail/${NEW_USERNAME}\";"; + fi +fi; +# check if crontab exists +if [ -f "/var/spool/cron/crontabs/${OLD_USERNAME}" ]; then + if [ $TEST -eq 0 ]; then + echo "rename to /var/spool/cron/crontabs/${NEW_USERNAME}"; + mv "/var/spool/cron/crontabs/${OLD_USERNAME}" "/var/spool/cron/crontabs/${NEW_USERNAME}"; + else + echo "$> mv \"/var/spool/cron/crontabs/${OLD_USERNAME}\" \"/var/spool/cron/crontabs/${NEW_USERNAME}\";"; + fi +fi; + +# public key files user must be renamed +OLD_SSH_AUTHORIZED_FILE="${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}${OLD_USERNAME}"; +NEW_SSH_AUTHORIZED_FILE="${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}${NEW_USERNAME}"; + +if [ -f "${OLD_SSH_AUTHORIZED_FILE}" ]; then + if [ $TEST -eq 0 ]; then + echo "rename to ${NEW_SSH_AUTHORIZED_FILE}"; + chattr -i "${OLD_SSH_AUTHORIZED_FILE}"; + mv "${OLD_SSH_AUTHORIZED_FILE}" "${NEW_SSH_AUTHORIZED_FILE}"; + chattr +i "${NEW_SSH_AUTHORIZED_FILE}"; + else + echo "$> chattr -i \"${OLD_SSH_AUTHORIZED_FILE}\";"; + echo "$> mv \"${OLD_SSH_AUTHORIZED_FILE}\" \"${NEW_SSH_AUTHORIZED_FILE}\";"; + echo "$> chattr +i \"${NEW_SSH_AUTHORIZED_FILE}\";"; + fi; +else + echo "[?] ${OLD_SSH_AUTHORIZED_FILE} is missing"; +fi; + +# rename keygen public file +OLD_ssh_keygen_pub="${ROOT_FOLDER}${SSH_KEYGEN_FOLDER_CREATED_PUB}${hostname}${separator}${group}${separator}${OLD_USERNAME}${separator}${ssh_keytype}.pem.pub"; +NEW_ssh_keygen_pub="${ROOT_FOLDER}${SSH_KEYGEN_FOLDER_CREATED_PUB}${hostname}${separator}${group}${separator}${NEW_USERNAME}${separator}${ssh_keytype}.pem.pub"; + +if [ -f "${OLD_ssh_keygen_pub}" ]; then + if [ $TEST -eq 0 ]; then + echo "rename to ${NEW_ssh_keygen_pub}"; + mv "${OLD_ssh_keygen_pub}" "${NEW_ssh_keygen_pub}"; + else + echo "$> mv \"${OLD_ssh_keygen_pub}\" \"${NEW_ssh_keygen_pub}\";"; + fi; +else + echo "[?] ${OLD_ssh_keygen_pub} is missing"; +fi; + +# rename entry in user list txt file +if [ $TEST -eq 0 ]; then + echo "update ${user_list_file}"; + sed -i -e "s/^\([A-Za-z0-9]\{1,\}\);${OLD_USERNAME};/\1;${NEW_USERNAME};/" "${user_list_file}"; +else + echo "$> sed -i -e \"s/^\([A-Za-z0-9]\{1,\}\);${OLD_USERNAME};/\1;${NEW_USERNAME};/\" \"${user_list_file}\";"; +fi; + # __END__