#!/bin/bash # Name: cron_report-password-expiry.sh # Description: Meant to be executed via cron: # -Check all user accounts for an upcoming password expiration # -Auto disable accounts that have been expired for a certain amount of time # -Notify users about auto disabled account or upcoming password expiration # -Create a summary report and e-mail to the admins # Last Updated: 2018-05-31 # Recent Changes:-Initial release ############################################################################################### #==================================== ##### Customize These Variables ##### #==================================== # Admin credentials: For ipa commands admin_user="admin" admin_pass='adminpwhere' # Email password expiry summary report to email_to="systemadmins@yourdomain.org" # FreeIPA self service portal URL (included in user reminder email) self_service_portal="https://ldapserver.yourdomain.org/ipa/ui/" # Auto disable user account when password expired for many days?(negative number expected) auto_disable_days=-4 # Warn about passwords expiring in how many days or less? password_expiry_warn_days=14 # Users are sent password expiration reminder emails on these days left until expiry remind_on_days=(14 7 3 1 0) # Temp files for building e-mail messages password_report_email="/root/ldap-scripts/tmp/cron_report-password-expiry-to-admins_report" password_report_disabled_users="/root/ldap-scripts/tmp/cron_report-password-expiry-to-admins_disabled-users" password_expiry_email="/root/ldap-scripts/tmp/cron_email-users-password-expiry_email" #===================================== ##### End of Customize Variables ##### #===================================== #========================================== #### Functions Here: Main Starts After #### #========================================== # Create the initial summary report layout/header function create_report_header() { # Clear out email temp file contents cat /dev/null > ${password_report_email} cat /dev/null > ${password_report_disabled_users} # Overwrite temp file contents echo -e "---- FreeIPA User Expiration Report ----" > ${password_report_email} echo -e "\nAccounts that will expire in ${password_expiry_warn_days} days or less." >> ${password_report_email} echo -e "Accounts will be automatically disabled and users emailed notification when expired for: ${auto_disable_days} days." >> ${password_report_email} echo -e "Users are sent password expiration warning emails on days: ${remind_on_days[@]}" >> ${password_report_email} # Setup report header echo -e "\n----------------------------------------------------------------" >> ${password_report_email} echo -e "User\t\tDays Left Until Expiration" >> ${password_report_email} echo -e "----------------------------------------------------------------" >> ${password_report_email} } # Add usernames and days left until expiration to the report function add_to_report() { # Set variables passed to the function username=${1} expires_in_days=${2} expires_in_secs=${3} expires_on_epoch=${4} # Determine the friendly looking expiration date userpw_expiry_date_long=$(date --date="@${expires_on_epoch}") # Determine day_format (Day vs Days) if [[ ${expires_in_days} -eq 1 || ${expires_in_days} -eq -1 ]]; then day_format="day" else day_format="days" fi # Determine if expiring in the future or if already expired if [[ ${expires_in_days} -le 0 ]]; then if [[ ${expires_in_secs} -le 0 ]]; then # expired now dialog_expires="${expires_in_days} ${day_format} (Expired Since: ${userpw_expiry_date_long}) ----> Auto Disable Warning!" else # expiring less than a day dialog_expires="${expires_in_days} ${day_format} (Expires On: ${userpw_expiry_date_long})" fi else # expiring on a future day dialog_expires="${expires_in_days} ${day_format} (Expires On: ${userpw_expiry_date_long})" fi # Status message echo "--Adding ${username} to password report." ## Add user account and expiration line to report file if [[ $(echo ${username} | wc --max-line-length) -lt 8 ]]; then # If less than 8 character username, use two tabs echo -e "${username}\t\t${dialog_expires}" >> ${password_report_email} else # If 8 or more characters, use one tab echo -e "${username}\t${dialog_expires}" >> ${password_report_email} fi } # Add usernames that have been disabled to a disabled list function add_to_disabled_list() { # Set variables passed to the function username=${1} # Status message echo "--Adding ${username} to disabled report." ## Add user account and expiration line to report file echo -e "${username}" >> ${password_report_disabled_users} } # Add usernames that have been disabled to the end of the email report function add_disabled_list_to_report() { # Setup disabled users header echo -e "\n\n----------------------------------------------------------------" >> ${password_report_email} echo -e "Users that have been automatically disabled" >> ${password_report_email} echo -e "----------------------------------------------------------------" >> ${password_report_email} # Add Disabled Users to end of report if [[ -s ${password_report_disabled_users} ]]; then # If file size is greater than 0, add content to report cat ${password_report_disabled_users} >> ${password_report_email} else # If file size is 0, give a status message echo "No users auto disabled during this script run." >> ${password_report_email} fi } # Email user to notify them that their account was auto disabled function notify_disabled_user(){ # Set username from passed variable username=${1} # Status message echo "--Notify ${username} that their account was disabled." # Gather email address, first name for the email name_email="$(/usr/bin/ipa user-show ${username} | grep -E "(First name|Email address)" | awk '{print $3}')" first_name="$(echo $name_email | awk '{print $1}')" user_email_address="$(echo $name_email | awk '{print $2}')" # Email user notification that their account has been disabled echo -e "${first_name},\n\nYour Linux account (${username}), has been automatically disabled due to having an expired password for ${auto_disable_days} days.\nPlease contact your System Administrators if you wish to enable the account.\n\n----\nSystem Administrators\n${email_to}" | /usr/bin/mail -s "Linux Account Auto-Disabled" -r ${email_to} -b ${email_to} ${user_email_address} } # Email user a reminder of their upcoming password expiration function email_user_reminder() { # Set variables passed to the function username=${1} expires_in_days=${2} expires_in_secs=${3} expires_on_epoch=${4} # Determine day_format (Day vs Days) if [[ ${expires_in_days} -eq 1 ]]; then day_format="Day" else day_format="Days" fi # Determine if expiring in the future or if already expired if [[ ${expires_in_days} -le 0 ]]; then if [[ ${expires_in_secs} -le 0 ]]; then # expired now dialog_expires_subject="Has Expired!" dialog_expires_body="expired on" else # expiring in less than a day dialog_expires_subject="Expires in < 24 Hours!" dialog_expires_body="will expire on" fi else # expiring on a future day dialog_expires_subject="Expires in: ${expires_in_days} ${day_format}" dialog_expires_body="will expire on" fi # Gather email address, first name, and friendly date for the email name_email="$(/usr/bin/ipa user-show ${username} | grep -E "(First name|Email address)" | awk '{print $3}')" first_name="$(echo $name_email | awk '{print $1}')" user_email_address="$(echo $name_email | awk '{print $2}')" userpw_expiry_date_long=$(date --date="@${expires_on_epoch}") ## Create email message file to send user echo "${first_name}," > ${password_expiry_email} echo -e "\nYour Linux password for (${username}) ${dialog_expires_body}: ${userpw_expiry_date_long}" >> ${password_expiry_email} echo -e "\nWarning: After a password has been expired for ${auto_disable_days} days, the account is automatically disabled." >> ${password_expiry_email} echo -e "\n==== Action Required ====" >> ${password_expiry_email} echo -e "\nChange your password using either the CLI or Web Portal method below." >> ${password_expiry_email} echo -e "\n== Change Password: CLI Method ==" >> ${password_expiry_email} echo -e "\n->Login to one of the systems that you have access to and change it by executing the 'passwd' command." >> ${password_expiry_email} echo "--You will be prompted for your current password and then new password twice." >> ${password_expiry_email} echo "--Login with your new password going forward." >> ${password_expiry_email} echo -e "\n== Change Password: Web Portal Method ==" >> ${password_expiry_email} echo -e "\nAlternatively, login to the self-service portal to change it (Cancel on any browser login pop-ups, use the actual web page form): ${self_service_portal}" >> ${password_expiry_email} echo -e "\n-After logging in, in the upper right corner:" >> ${password_expiry_email} echo "--Click your name for a drop down box, then 'Change password'." >> ${password_expiry_email} echo "----Enter in your 'Current Password'." >> ${password_expiry_email} echo "----Leave the 'OTP' field blank." >> ${password_expiry_email} echo "----Enter in your 'New Password' and again in 'Verify Password'." >> ${password_expiry_email} echo "--Click the 'Reset Password' button when complete." >> ${password_expiry_email} echo -e "\n==== New Password Requirements ====" >> ${password_expiry_email} echo -e "\nYour new password requirements are:" >> ${password_expiry_email} echo "->At least 12 characters in length" >> ${password_expiry_email} echo "->At least 3 types of characters from the following categories:" >> ${password_expiry_email} echo "--Upper case letters" >> ${password_expiry_email} echo "--Lower case letters" >> ${password_expiry_email} echo "--Numbers" >> ${password_expiry_email} echo "--Special Characters" >> ${password_expiry_email} echo -e "\nIf you have any questions, please contact your System Administrators." >> ${password_expiry_email} echo -e "\n----\nSystem Administrators" >> ${password_expiry_email} echo "${email_to}" >> ${password_expiry_email} # Status message echo "--Emailing upcoming password expiry reminder to: ${username} (${user_email_address})..." ## E-mail the password expiry warning to the user /usr/bin/mail -s "Linux Password ${dialog_expires_subject}" -r ${email_to} ${user_email_address} < ${password_expiry_email} # Allow some time for the message to exit the queue sleep 5 # Clear out email contents cat /dev/null > ${password_expiry_email} } #========================= #### End of Functions #### #========================= #========================= #### Main Starts Here #### #========================= # Initialize a kerberos ticket as admin and wait a short time echo ${admin_pass} | /usr/bin/kinit ${admin_user} sleep 3 # Build a list of enabled accounts #- Find all users | grep logins and disabled status lines | #- If the current line matches "False" (/False/), print the stored username (print username), #- next, store the current line's field 3 in the variable username (username=$3) user_list=$(/usr/bin/ipa user-find --sizelimit=0 --all | grep -E "(User login|Account disabled)" | awk '/False/ { print username }; { username=$3 }') # Get today's epoch time (seconds since Jan 1st, 1970, midnight UTC) todays_epoch=$(date +%s) # Create the system admin report header create_report_header #### Main Loop #### for user in ${user_list}; do echo "Checking expiry for ${user}..." # Get user's password expiration and cut off the zulu time designator trailing at the end('Z') userpw_expiry_datetime=$(/usr/bin/ipa user-show ${user} --all | grep krbpasswordexpiration | awk '{print $2}' | cut -c 1-14) # If the user account does not have a password expiration value, skip the user if [[ -z ${userpw_expiry_datetime} ]]; then continue fi # Split up the year,month,day,hour,min, and sec from the datetime string userpw_expiry_date_year="$(echo ${userpw_expiry_datetime} | cut -c 1-4)" userpw_expiry_date_month="$(echo ${userpw_expiry_datetime} | cut -c 5-6)" userpw_expiry_date_day="$(echo ${userpw_expiry_datetime} | cut -c 7-8)" userpw_expiry_time_hour="$(echo ${userpw_expiry_datetime} | cut -c 9-10)" userpw_expiry_time_min="$(echo ${userpw_expiry_datetime} | cut -c 11-12)" userpw_expiry_time_sec="$(echo ${userpw_expiry_datetime} | cut -c 13-14)" # Caculate the user's expiry date in epoch time userpw_expiry_epoch=$(date --utc --date="${userpw_expiry_date_year}-${userpw_expiry_date_month}-${userpw_expiry_date_day} ${userpw_expiry_time_hour}:${userpw_expiry_time_min}:${userpw_expiry_time_sec}" +%s) # Calculate how many seconds and days until password expiration password_expires_seconds=$(expr ${userpw_expiry_epoch} - ${todays_epoch}) password_expires_days=$(expr ${password_expires_seconds} / 86400) # If the password expires in 'password_expiry_warn_days' days or less, determine if we should: # -Disable user if the password has been expired <= to the auto_disable_days # -Check to see if we should email the user on the remind_on_days # -Add user to the system admin report if [[ ${password_expires_days} -le ${password_expiry_warn_days} ]]; then # if password has been expired for 'auto_disable_days' or more days, disable the account/notify user if [[ ${password_expires_days} -le ${auto_disable_days} ]]; then echo "--Disabling the user account: ${user}" /usr/bin/ipa user-disable ${user} # Add disabled account to a list for inclusion at the footer of the system admin report add_to_disabled_list ${user} # Email the user and notify them that their account was auto disabled notify_disabled_user ${user} else # Not auto disabling user, add the user to the system admin report add_to_report ${user} ${password_expires_days} ${password_expires_seconds} ${userpw_expiry_epoch} # Check to see if the user should be reminded of their upcoming passowrd expiry # Loop through array of days to send the email reminder on for reminder_day in "${remind_on_days[@]}"; do # If days left before user's password expires matches a reminder day, send an email to the user if [[ ${password_expires_days} -eq ${reminder_day} ]]; then email_user_reminder ${user} ${password_expires_days} ${password_expires_seconds} ${userpw_expiry_epoch} break fi done fi fi done #### End Main Loop #### # Add disabled users list to the end of email report add_disabled_list_to_report # Status message echo ">>Emailing summary report to ${email_to}..." # Use the date-time from the beginning of the script todays_date_long=$(date --date="@${todays_epoch}") # Email Report /usr/bin/mail -s "FreeIPA User Expiration Report - ${todays_date_long}" ${email_to} < ${password_report_email} # Wait a bit for the message queue to get sent sleep 5 # Clear out email temp file contents cat /dev/null > ${password_report_email} cat /dev/null > ${password_report_disabled_users}