#!/bin/bash

set -x
###########################################################################
# Cumulus Factory reset script                                            #
# /usr/bin/factory-reset                                                  #
# This script is used to reset the system to factory settings.            #
###########################################################################

# Initialize constants
FACTORY_RESET_LOG_FILE=/var/log/factory-reset.log
log_msg () {
    DATE=$(date "+%Y/%m/%d %H:%M:%S")
    echo "$DATE factory-reset.service: $1" >> $FACTORY_RESET_LOG_FILE
}
CONFIG_BACKUP_DIR=/var/lib/config-backup/backups/
NVUE_STARTUP_CONFIG_FILE=/etc/nvue.d/startup.yaml
NVUE_BACKUP_CONFIG_FILE=/tmp/startup-backup.yaml
NVUE_NEW_CONFIG_FILE=/tmp/startup-new.yaml
FIRSTBOOT_DONE_FILE=/etc/cumulus-firstboot-done
FIRSTBOOT_AFTER_NETWORKING_DONE_FILE=/etc/cumulus-firstboot-after-networking-done
NVUE_DIR=/etc/nvue
NVUE_CERT_GEN_SCRIPT=$NVUE_DIR/certificates/entity_server_cert_generate.sh
NGINX_DIR=/etc/nginx


trap "error_cleanup" HUP INT QUIT PIPE TERM

# Command usage and help
usage()
{
    cat << EOF
 Usage:  factory-reset < keep-basic | keep-all-config | keep-only-files >

        Default          - Reset configurations to factory reset. Logs and files will be deleted.
        keep-basic       - Preserves basic configurations only after boot. Logs and files will be deleted.
        keep-all-config  - Preserves all configurations after boot. Logs and files will be deleted.
        keep-only-files   - Reset configurations to factory default. Logs and files will be preserved.
EOF
}

run_reboot()
{
    reboot
    # If for any reason we reach this code, then force reboot
    rc=$?
    if [ $rc -ne 0 ]; then
        # Force reboot
        reboot -f
    fi
}

error_cleanup()
{
    if [ -f "$NVUE_BACKUP_CONFIG_FILE" ]; then
        mv $NVUE_BACKUP_CONFIG_FILE $NVUE_STARTUP_CONFIG_FILE
    fi

    log_msg "ERROR: Error seen, rebooting now"
    run_reboot
}

create_cumulus()
{
    # variables for recreating cumulus user
    user_name="cumulus"
    user_id="cumulus"
    user_hashed_passwd="\$y\$j9T\$isY/MpDAcSdgMppnXeMtf0\$Pml/AJYHmBADK0pgpYmi6pbv46jnndLBCym7QDoDYU1"
    passwd_change="usermod -p ${user_hashed_passwd} ${user_id}"

    # create user
    # TO DO: Remove --debug --verbose in final commit
    adduser --disabled-password --gecos "$user_name" "$user_id" \
      --home /home/$user_name

    # set password
    ${passwd_change}

    # force password change on first login
    passwd --expire ${user_id}

    # add user to various groups
    for g in nvapply sudo ${USER_GADD_EXTRA}; do
        adduser $user_id $g
    done
}

# Delete all the home directories having .local/share/nvue
# Use getent to get the list of all user entries
clear_nvue_cache()
{
    while IFS=: read -r _ _ uid _ _ homedir _; do
        # Only proceed for regular users (typically UID >= 1000) and root user (UID is 0)
        if [ "$uid" -eq 0 ] || [ "$uid" -ge 1000 ]; then
            # Construct the path to the .local/share/nvue directory
            target="$homedir/.local/share/nvue"
            # If the directory exists remove it
            if [ -d "$target" ]; then
                log_msg "Removing the directory $target even if it is not empty"
                rm -rf "$target"
            fi
        fi
    done < <(getent passwd)
}

# Delete all users with UID>=1000 and <=60000.
# Recreate "cumulus" user. Expire its password.
# Delete "root" user password.
reset_users()
{
    # Get non-default user accounts
    users_to_del=$(getent passwd | awk -F:  '($3>=1000 && $3<=60000) {print $1}')
    log_msg "Deleting non-default users"
    for user in ${users_to_del[@]}
    do
       # -r flag deletes the user's home directory and mail spool
       # avoid printing home directory and mail spool errors
       userdel -rf $user 2> /dev/null
       # Remove cron jobs from /var/spool/cron/*
       crontab -r -u $user
    done

    log_msg "Recreating 'cumulus' user. Expiring its password to be set on next login."
    create_cumulus

    log_msg "Disabling password for 'root' user."
    passwd --delete root
    passwd --lock root
}

delete_certificates()
{
    # Certificates and conf files present in /etc/ which are not there in backup
    # will be deleted by config-restore script.

    # Remove nvue CA certificates
    sudo find /usr/local/share/ca-certificates/nvue/ -type f -delete
    sudo find /usr/local/share/ext/ca-certificates/nvue/ -type f -delete

    # Update CA certificates in Linux
    sudo update-ca-certificates

    # Remove certificate storage file for both CA and common certificates
    sudo rm /var/lib/nvue/config/certs-oper-store.nvue
}

# Only root can run reset factory
if [ $UID != 0 ]; then
    echo "You must be root to reset system to factory settings"
    exit 1
fi

/bin/chmod 640 $FACTORY_RESET_LOG_FILE

CMD=$1
FACTORY_TYPE=
if [ -z "$CMD" ]; then
    FACTORY_TYPE="default" 
elif [ "$CMD" = "keep-all-config" ] || [ "$CMD" = "keep-only-files" ] || \
   [ "$CMD" = "keep-basic" ]; then
    FACTORY_TYPE=$CMD
else
    usage
    exit 1
fi

rc=$?
if [ $rc -ne 0 ]; then
    error_cleanup
fi

log_msg "Resetting system to factory configuration of type $FACTORY_TYPE"

log_msg "Stop SSH service and close SSH sessions"
ssh_services=$(systemctl list-units ssh* --no-pager --state=active | \
               grep -o '\b\w*\.service\b')
for service in ${ssh_services[@]}; do
    log_msg "Stopping SSH service $service"
    sudo systemctl stop $service
done
users_pids=$(who -u | awk '{print $6}')
for pid in ${users_pids[@]}; do
    log_msg "Closing active SSH session with PID $pid"
    sudo kill -HUP $pid
done

if [ "$FACTORY_TYPE" != "keep-all-config" ]; then
    if [ "$FACTORY_TYPE" == "keep-basic" ]; then
        clear_nvue_cache
    else
        reset_users
    fi

    if [ -d "$CONFIG_BACKUP_DIR" ] && [ "$(ls $CONFIG_BACKUP_DIR)" ]; then
        log_msg "Restoring /etc from the first backup configuration"

        # '-n' is the number of the backup configuration. So we are reverting to the 1st one.
        # '-B' does not create a current backup before restore
        # '-f' forcibly does the restore without asking for confirmation
        # '-X' exclude this file from restoring
        /usr/lib/cumulus/config-restore -n 1 -B -f -X etc/shadow -X etc/passwd -X etc/group

        # Delete the new files and dirs from current configuration
        /usr/lib/cumulus/config-restore -D -n 1 | grep "Only in current file-system" | awk -F ": " '{ print $2 }' | xargs rm -r
    fi

    ls -al $NVUE_NEW_CONFIG_FILE >> $FACTORY_RESET_LOG_FILE
    ls -al $NVUE_STARTUP_CONFIG_FILE >> $FACTORY_RESET_LOG_FILE
    ls -al /usr/lib/python3/dist-packages/cue_config_v1/initial.yaml >> $FACTORY_RESET_LOG_FILE

    if [ -f "$NVUE_NEW_CONFIG_FILE" ]; then
        log_msg "Copying new startup.yaml to /etc/nvue.d/startup.yaml"
        cp $NVUE_NEW_CONFIG_FILE $NVUE_STARTUP_CONFIG_FILE
    fi

    log_msg "Enabling ZTP"
    ztp --disable
    ztp --full-reset
    # RM ticket 4101112: Need to delete this file to prevent ZTP getting
    # disabled due to manual configuration detection.
    rm /var/lib/cumulus/ztp/ztp_state.sha

    log_msg "Enabling Firstboot mode"
    rm $FIRSTBOOT_DONE_FILE
    systemctl enable cumulus-firstboot.service
    rm $FIRSTBOOT_AFTER_NETWORKING_DONE_FILE
    systemctl enable cumulus-firstboot-after-networking.service

    log_msg "Uninstalling TACACS, RADIUS packages and dependencies"
    if dpkg-query -W tacplus-client ; then
        apt-get autoremove --purge -y tacplus-client
    fi
    if dpkg-query -W libpam-radius-auth ; then
        apt-get autoremove --purge -y libnss-mapuser libpam-radius-auth radius-cmd-acct
        pam-auth-update --force --package
    fi

    log_msg "Stopping nginx and nvued services"
    systemctl stop nginx-authenticator
    systemctl stop nginx
    systemctl stop nvued

    log_msg "Deleting NVUE DB and root user NVUE files"
    rm -rf /var/lib/nvue/*
    rm -rf /root/.local/share/nvue

    log_msg "Deleting NVUE and Nginx certificates"
    delete_certificates
fi

if [ "$FACTORY_TYPE" != "keep-only-files" ]; then
    log_msg "Cleaning up reset reason history"
    find /var/reset-reason/ -type l,f -delete

    log_msg "Deleting cl-support logs"
    rm -rf /var/support/*
    mkdir /var/support/core/
    rm -rf /var/images/*

    # Clearing the login logging files below instead of deleting them, as it 
    # may lead to system crash
    log_msg "Deleting log files"
    sleep 2
    find /var/log/ -type f ! -iname "wtmp" ! -iname "btmp" ! -iname "lastlog" ! -iname "factory-reset.log" -delete

    # Clear wtmp, btmp and lastlog files
    rm -rf /var/log/wtmp.*
    cat /dev/null > /var/log/wtmp
    rm -rf /var/log/btmp.*
    cat /dev/null > /var/log/btmp
    rm -rf /var/log/lastlog.*
    cat /dev/null > /var/log/lastlog

    ## Flush few more dirs
    # Temporary files that  persist between reboots
    rm -rf /var/tmp/*

    # Site-specific data such as web or FTP files
    rm -rf /srv/*

fi

log_msg "Factory reset complete. Rebooting now !"
run_reboot
