Archive for August, 2023

How to set up Notify by email expiring local UNIX user accounts on Linux / BSD with a bash script

Thursday, August 24th, 2023


If you have already configured Linux Local User Accounts Password Security policies Hardening – Set Password expiry, password quality, limit repatead access attempts, add directionary check, increase logged history command size and you want your configured local user accounts on a Linux / UNIX / BSD system to not expire before the user is reminded that it will be of his benefit to change his password on time, not to completely loose account to his account, then you might use a small script that is just checking the upcoming expiry for a predefined users and emails in an array with lslogins command like you will learn in this article.

The script below is written by a colleague Lachezar Pramatarov (Credit for the script goes to him) in order to solve this annoying expire problem, that we had all the time as me and colleagues often ended up with expired accounts and had to bother to ask for the password reset and even sometimes clearance of account locks. Hopefully this little script will help some other unix legacy admin systems to get rid of the account expire problem.

For the script to work you will need to have a properly configured SMTP (Mail server) with or without a relay to be able to send to the script predefined email addresses that will get notified. 

Here is example of a user whose account is about to expire in a couple of days and who will benefit of getting the Alert that he should hurry up to change his password until it is too late 🙂

[root@linux ~]# date
Thu Aug 24 17:28:18 CEST 2023

[root@server~]# chage -l lachezar
Last password change                                    : May 30, 2023
Password expires                                        : Aug 28, 2023
Password inactive                                       : never
Account expires                                         : never
Minimum number of days between password change          : 0
Maximum number of days between password change          : 90
Number of days of warning before password expires       : 14

Here is the that will report the user

# vim  /usr/local/bin/


# This script will send warning emails for password expiration 
# on the participants in the following list:
# 20, 15, 10 and 0-7 days before expiration
# ! Script sends expiry Alert only if day is Wednesday – if (( $(date +%u)==3 )); !

# email to send if expiring
# the users that are admins added to belong to this group
notify_email_header_customer_name='Customer Name';

declare -A mails=(
# list below accounts which will receive account expiry emails

# syntax to define uid / email
# [“account_name_from_etc_passwd”]="real_email_addr@fqdn";

#    [“abc”]=""
#    [“cba”]=""
#    [“acct7”]=""
#    [“acct8”]=""
#    [“acct9”]=""

declare -A days

while IFS="=" read -r person day ; do
done < <(lslogins –noheadings -o USER,GROUP,PWD-CHANGE,PWD-WARN,PWD-MIN,PWD-MAX,PWD-EXPIR,LAST-LOGIN,FAILED-LOGIN  –time-format=iso | awk '{print "echo "$1" "$2" "$3" $(((($(date +%s -d \""$3"+90 days\")-$(date +%s)))/86400)) "$5}' | /bin/bash | grep -E " $admin_group " | awk '{print $1 "=" $4}')

#echo ${days[laprext]}
for person in "${!mails[@]}"; do
     echo "$person ${days[$person]}";

#     echo $tmp
# each person will receive mails only if 20th days / 15th days / 10th days remaining till expiry or if less than 7 days receive alert mail every day

     if  (( (${tmp}==20) || (${tmp}==15) || (${tmp}==10) || ((${tmp}>=0) && (${tmp}<=7)) )); 
         echo "Hello, your password for $(hostname -s) will expire after ${days[$person]} days.” | mail -s “$notify_email_header_customer_name $(hostname -s) server password expiration”  -r passwd_expire ${mails[$person]};
     elif ((${tmp}<0));
#          echo "The password for $person on $(hostname -s) has EXPIRED before{days[$person]} days. Please take an action ASAP.” | mail -s “EXPIRED password of  $person on $(hostname -s)”  -r EXPIRED ${mails[$person]};

# ==3 meaning day is Wednesday the day on which OnCall Person changes

        if (( $(date +%u)==3 ));
             echo "The password for $person on $(hostname -s) has EXPIRED. Please take an action." | mail -s "EXPIRED password of  $person on $(hostname -s)"  -r EXPIRED $alert_email;


To make the script notify about expiring user accounts, place the script under some directory lets say /usr/local/bin/ and make it executable and configure a cron job that will schedule it to run every now and then.

# cat /etc/cron.d/passwd_expire_cron

# /etc/cron.d/pwd_expire
# Check password expiration for users
# 2023-01-16 LPR
02 06 * * * root /usr/local/bin/ >/dev/null

Script will execute every day morning 06:02 by the cron job and if the day is wednesday (3rd day of week) it will send warning emails for password expiration if 20, 15, 10 days are left before account expires if only 7 days are left until the password of user acct expires, the script will start sending the Alarm every single day for 7th, 6th … 0 day until pwd expires.

If you don't have an expiring accounts and you want to force a specific account to have a expire date you can do it with:

# chage -E 2023-08-30 someuser

Or set it for new created system users with:

# useradd -e 2023-08-30 username

That's it the script will notify you on User PWD expiry.

If you need to for example set a single account to expire 90 days from now (3 months) that is a kind of standard password expiry policy admins use, do it with:

# date -d "90 days" +"%Y-%m-%d"

Ideas for script improvement

The downside of the script if you have too many local user accounts is you have to hardcode into it the username and user email_address attached to and that would be tedios task if you have 100+ accounts. 

However it is pretty easy if you already have a multitude of accounts in /etc/passwd that are from UID range to loop over them in a small shell loop and build new array from it. Of course for a solution like this to work you will have to have defined as user data as GECOS with command like chfn.

[georgi@server ~]$ chfn
Changing finger information for test.
Name [test]: 
Office []:
Office Phone []: 
Home Phone []: 


[root@server test]# finger georgi
Login: georgi                       Name: georgi
Directory: /home/georgi                   Shell: /bin/bash
On since чт авг 24 17:41 (EEST) on :0 from :0 (messages off)
On since чт авг 24 17:43 (EEST) on pts/0 from :0
   2 seconds idle
On since чт авг 24 17:44 (EEST) on pts/1 from :0
   49 minutes 30 seconds idle
On since чт авг 24 18:04 (EEST) on pts/2 from :0
   32 minutes 42 seconds idle
New mail received пт окт 30 17:24 2020 (EET)
     Unread since пт окт 30 17:13 2020 (EET)
No Plan.

Then it should be relatively easy to add the GECOS for multilpe accounts if you have them predefined in a text file for each existing local user account.

Hope this script will help some sysadmin out there, many thanks to Lachezar for allowing me to share the script here.
Enjoy ! 🙂

Fix ruby: /usr/lib/ version `XCRYPT_2.0′ not found in apt upgrade on Debian Linux 10

Saturday, August 5th, 2023

I've an old legacy Thinkpad Laptop that is for simplicty running Window Maker Wmaker which was laying on my home desk for almost an year and I remembered since i'm for few days in my parents home in Dobrich that it will be a good idea to update its software to the latest Debian packages to patch security issues with it. Thus if you're like me and  you tried to update your Debian 10 Linux to the latest Stable release debian packages  and you end up into a critical error that is preventing apt to to resolve conflicts (fix it with) cmds like:

# apt-get update –fix-missing

# apt –fix-broken install

As usual I looked into Google to see about solution and found few articles, claiming to have scripts that fix it but at the end nothing worked.
And the shitty error occured during the standard:

# apt-get update && apt-get upgrade

ruby: /usr/lib/ version `XCRYPT_2.0' not found

Hence the cause and work around seemed to be very unexpected.
For some reason debian makes a link

root@noah:/lib# ls -al /lib/
lrwxrwxrwx 1 root root 19 Aug  3 16:53 /lib/ ->

root@noah:/lib# ls -al /lib/
lrwxrwxrwx 1 root root 16 Jun 15  2017 /lib/ ->

Thus to resolve it and force the .deb upgrade package to continue it is up to simply deleting the strange simlink and re-run the

# apt-get update && apt-get upgrade

Setting up libc6:i386 (2.31-13+deb11u6) …
/usr/bin/perl: /lib/ version `XCRYPT_2.0' not found (required by /usr/bin/perl)
dpkg: error processing package libc6:i386 (–configure):
 installed libc6:i386 package post-installation script subprocess returned error exit status 1
Errors were encountered while processing:

Few more times. If you get some critical apt failures still, each time make sure to rerun the command after doing a simple removal of the strange simbolic link with cmd:

# rm -f /lib/

That's all folks after a short while your Debian will be updated to latest Enoy folks ! 🙂

Saint Emilianos (Emilian) of Dorostorum (Silistra) ancient saint venerated in Bulgarian Orthodox Church

Saturday, August 5th, 2023


Saint Emilian / Emilianos Dorostolski is a martyr revered with a feast day by the Bulgarian Orthodox Church.

According to his biography, he was born in Durostorum (now Silistra Bulgaria), where he spent his life as a servant (or slave) to the mayor.
He lived in the time of Emperor Julian (the apostate).

Emperor Julian sent a new governor to Dorostol charged with the task of eradicating Christianity from the city.

Frightened by his fame as a very cruel ruler, the local inhabitants hide from him that there are Christians among them and declare that they all worship the pagan gods.
Satisfied, he gives a feast to the citizens, but for the zealous Christian Aemilianus (Emilianos), the boasting of the pagan governor is unbearable, and during the feast he smashes the statues of the pagan gods in the sanctuary with a hammer.

An innocent person is accused of the crime, but knowing this, Emilian appears before the governor and confesses his guilt.

The city was fined for harboring Christians, and Aemilianus himself, after torture, was burned at the stake by the Danube[1] (river) on July 18, 362; this date is today the day of his veneration by the church[2].

It is assumed that the life of Saint Emilian was written immediately after the saint's death – the end of the 4th and the beginning of the 5th century. Its earliest variants are generally two.

The first is based on the so-called Codex Vaticanus 866 (published by Boschius in 1868), and the second is based on the so-called Codex Parisiensis of the 9th century (published by François Halkin). Although the Codex Parisiensis largely repeats the Codex Vaticanus, there is a difference between the two lives in both the date of Aemilian's martyrdom and the location of his obituary. According to the first, Emilian was burned at the stake on September 3 in Gedina (localized near the present-day village of Golesh), and according to the second, it happened on July 18 in Gezedina, right next to Durostorum (fortress).

Information about Saint Emilian can also be found in blessed Jerome, and saint Ambrose (Ambrosius) of Milan, Theophanes the Confessor and Nicephorus Callistus.
In the Church-Slavic hagiography, the life enters mainly from its later copies in the Paschal Chronicle (Chronicon Paschalae), the Synaxarium (Church book with the service text dedicated to the sant) of the Constantinople Patriarchate (Synaxarium Constantinopolitanum) and the Monthly Message of Emperor Basil II (Menologium Basilii (Basilius) II).

A major difference between the early lives and their later editions is Aemilian's social status.

According to the late Church Slavonic redactions, he was a slave / servant of the mayor of Durostorum (today city of Silistra Bulgaria), while according to the earlier ones he himself was of noble birth – his father Sevastian was the governor of the city – and was a soldier (presumably from the XI Claudius Legion)[3].



 1. Georgi Atanasov, 345 early Christian saints-martyrs from the Bulgarian lands I – IV centuries / Publisher: Unicart ISBN: 9789542953012 / page 11
  2. Lives of the Saints. Synodal publishing house. Sofia, 1991. pp. 337-338.
  3. St. Emilian Dorostolski: My name is Christian

Other Research sources

  • Constantinesco, R. Les martyrs de Durostorum. – Revue des Etudes Sud-Est Europeennes, 5, 1967, No. 1 – 2, 14 – 19.
  • G. Atanasov. St. Emilian Dorostolsky († 362) – the last early Christian martyr in Mysia. – In: Civitas divino-humana in honor of Professor Georgi Bakalov. S. 2004, 203 – 218.
  • Ivanova, R., G. Atanasov, P. Donevski. History of Silistra. T. 1. The ancient Durostorum. Silistra-S., 2006.
  • Atanasov, G. The Christian Durostorum-Druster. Varna, 2007.

Generate and Add UUID for every existing Redhat / CentOS / RHEL network interface to configuration if missing howto

Saturday, August 5th, 2023


If you manage old Linux machines it might be after the update either due to update mess or because of old system administrators which manually included the UUID to the config forgot to include it in the present network configuration in /etc/sysconfig/networking-scripts/ifcfg-* Universally Unique IDentifier (UUID)128-bit label I used a small one liner after listing all the existing configured LAN interfaces reported from iproute2 network stack with ip command. As this might be useful to someone out there here is the simple command that returns a number of commands to later just copy paste to console once verified there are no duplicates of the UUID already in the present server configuration with grep.

In overall to correct the configs and reload the network with the proper UUIDs here is what I had to do:

# grep -rli UUID /etc/sysconfig/network-scripts/ifcfg-*

No output from the recursive grep means UUIDs are not present on any existing interface, so we can step further check all the existing machines network ifaces and generate the missing UUIDs with uuidgen command

# ip a s |grep -Ei ': <'|sed -e 's#:##g' |grep -v '\.' |awk '{ print $2 }'


I've stumbled on that case on some legacy Linux inherited from other people sysadmins and in order to place the correct 

# for i in $(ip a s |grep -Ei ': <'|sed -e 's#:##g' |grep -v '\.' |awk '{ print $2 }'); do echo "echo UUID=$(uuidgen $i)"" >> ifcfg-$i"; done|grep -v '\-lo' 
echo UUID=26819d24-9452-4431-a9ca-176d87492b75 >> ifcfg-venet0
echo UUID=3c7e8848-0232-436f-a52a-46db9a03eb33 >> ifcfg-eth0
echo UUID=1fc0454d-bf23-417d-b960-571fc04754d2 >> ifcfg-eth1
echo UUID=5793c1e5-4481-4f09-967e-2cceda85c35f >> ifcfg-eth2
echo UUID=65fdcaf6-d271-4845-a8f1-0ec478c375d1 >> ifcfg-eth3

As you can see I exclude the loopback interface -lo from the ouput as it is not necessery to have UUID for it.
That's all folks problem solved. Enjoy