From c801ef40b432cd38bd3a275ae8d2cc8a45ea78d8 Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Fri, 12 Sep 2025 10:16:05 +0900 Subject: [PATCH] Switch from lastlogin to lsogins Debian 13 dropped lastlogin, replaced with lastlogin2 which is an extra install. Switch to lslogins, which also makes parsing much easier --- Readme.md | 4 ++-- bin/check_last_login.sh | 31 +++++++++++++++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Readme.md b/Readme.md index d381f06..4ab997e 100644 --- a/Readme.md +++ b/Readme.md @@ -266,7 +266,7 @@ If not set it defaults to allow, if a user_list.txt file with this user exist it There are two scripts that can be user to check if and when the user has logged in the last time. -Because of users who do not open shells (for example sftp users) we cannot rely on lastlog, so a script called `collect_login_data.sh` exists that parses the systemd logind info or /var/log/secure for user authentication data. +Because of users who do not open shells (for example sftp users) we cannot rely on lslogins, so a script called `collect_login_data.sh` exists that parses the systemd logind info or /var/log/secure for user authentication data. Data is stored in `auth-log/user_auth.log` folder as `user;last login date` @@ -278,7 +278,7 @@ This script should be run every day via crontab as root: The script `check_last_login.sh` will go through the ssh allow groups (sshallow/sshforward) users and flag out those that have not logged in, in the last 60 days and recommend to lock them. The script will also check for user accounts that never logged in and where created in the last 30 days and recomment to lock them too. -This script will first check the `auth-log/user_auth.log` file, then lastlog output and finally check for creation time in passwd file or home director for when the user was created. +This script will first check the `auth-log/user_auth.log` file, then lslogins output and finally check for creation time in passwd file or home director for when the user was created. Currently only information is printed out and no action is done itself. diff --git a/bin/check_last_login.sh b/bin/check_last_login.sh index f1490df..70e17b3 100755 --- a/bin/check_last_login.sh +++ b/bin/check_last_login.sh @@ -44,6 +44,11 @@ if [ -z "$(command -v jq)" ]; then echo "Missing jq application, aborting"; error=1; fi; +# use lslogins instead of last log +if [ -z "$(command -v lslogins)" ]; then + echo "Missing lslogins application, aborting"; + error=1; +fi; if [ $error -eq 1 ]; then exit; fi; @@ -187,10 +192,18 @@ for ssh_group in "${ssh_groups[@]}"; do # below only works if the user logged in, a lot of them are just file upload # users. Use the collect script from systemd-logind or /var/log/secure - # Username Port From Latest - # user pts/35 10.110.160.230 Wed Nov 2 09:40:35 +0900 2022 - last_login_string=$(lastlog -u "${username}" | sed 1d); - search="Never logged in"; + # for the rest use lslogin, returns ":" separted list, not set is never logged in + # LAST LOGIN :FAILED LOGIN + # 2025-09-12T09:56:22+09:00: + last_login_string=$( + lslogins \ + -c --noheadings --notruncate \ + --time-format=iso \ + -o LAST-LOGIN,FAILED-LOGIN \ + -l "${username}" + ); + last_login_date=$(echo "${last_login_string}" | cut -d ":" -f 1); + # search="Never logged in"; never_logged_in="false"; found=""; login_source=""; @@ -227,12 +240,10 @@ for ssh_group in "${ssh_groups[@]}"; do login_source="ssh"; # rewrite to Y-M-D, aka last_login_date="${last_login_date_string}" - elif [ -n "${last_login_string##*"$search"*}" ]; then + elif [ -n "${last_login_date}" ]; then # if we have "** Never logged in**" the user never logged in - # find \w{3} \w{3} [\s\d]{2} \d{2}:\d{2}:\d{2} \+\d{4} \d{4} - # awk '{for(i=4;i<=NF;++i)printf $i FS}' - last_login_date=$(echo "${last_login_string}" | awk '{for(i=4;i<=NF;++i)printf $i FS}' | date +"%s" -f -); - # date -d "Wed Nov 2 09:40:35 +0900 2022" +%s + # we get an ISO DATE with timezone + last_login_date=$(echo "${last_login_string}" | date +"%s" -f -); last_login=$(awk '{printf("%.0f\n",($1-$2)/$3)}' <<<"${now} ${last_login_date} ${day}"); if [ "${last_login}" -gt ${max_age_login} ]; then out_string="[!] Last terminal log in ${last_login} days ago"; @@ -245,7 +256,7 @@ for ssh_group in "${ssh_groups[@]}"; do out_string="OK [lastlog, ${last_login} days ago]"; fi; login_source="lastlog"; - last_login_date=$(echo "${last_login_string}" | awk '{for(i=4;i<=NF;++i)printf $i FS}' | date +"%F %T" -f -) + last_login_date=$(echo "${last_login_string}" | date +"%F %T" -f -) elif [ -n "${user_create_date}" ]; then if [ "${account_age}" -gt ${max_age_create} ]; then out_string="[!] Never logged in: account created ${account_age} days ago";