this post was submitted on 15 Aug 2025
14 points (100.0% liked)

Linux Questions

3045 readers
1 users here now

Linux questions Rules (in addition of the Lemmy.zip rules)

Tips for giving and receiving help

Any rule violations will result in disciplinary actions

founded 2 years ago
MODERATORS
 

Hello everyone!

As the title says, I am trying to set up email alerts on my server whenever there is a successful ssh connection (will also setup the same for failed connections with fail2ban later). I already have the email script created and it works (I use it to monitor the directories containing all of these security scripts for changes so that I also get notified if anything critical is modified or deleted in those directories).

I also created a very basic user called test for - you guessed it - testing purposes. This user doesn't have a home directory or anything like that.

Here are the relevant scripts:

$ cat /usr/local/bin/login-alert.sh
#!/bin/bash

# Sends alerts only for real terminals not cron jobs
if [[ -n "$SSH_CONNECTION" ]]; then
	USERNAME=$(whoami)
	IP=$(echo $SSH_CONNECTION | awk '{print $1}')
	HOST=$(hostname)
	DATETIME=$(date)
	/usr/local/bin/semail \
		-s "[CRITICAL] SSH Login to $HOST" \
	 	-b "Login detected:\n\nUser: $USERNAME\nIP: $IP\nTime: $DATETIME\nTTY: $SSH_TTY"
fi

$ cat /usr/local/bin/semail
#!/bin/bash

# Default values
TO="my_email@here.com"
FROM="notifications@my_server.com"
SUBJECT=""
BODY=""
BODY_FILE=""


# Help function
show_help() {
cat <<EOF
Usage: $0 [OPTIONS]

Send a test email using Postfix.

Options:
  -t, --to EMAIL            Recipient email address (default: $TO)
  -s, --subject TEXT        Subject of the email (required)
  -b, --body TEXT           Body text of the email
  -f, --body-file FILE      File to read body text from (overrides --body)
  -h, --help                Show this help message

If no body or body-file is provided, you will be prompted to enter the body interactively.

Examples:
  $0 -s "Test subject" -b "Hello\nThis is a test"
  $0 --subject "Test" --body-file message.txt
EOF
}

# Parse arguments
while [[ "$#" -gt 0 ]]; do
	case "$1" in
		-t|--to)
			TO="$2"
			shift 2
			;;
		-s|--subject)
			SUBJECT="$2"
			shift 2
			;;
		-b|--body)
			BODY="$2"
			shift 2
			;;
		-f|--body-file)
			BODY_FILE="$2"
			shift 2
			;;
		-h|--help)
			show_help
			exit 0
			;;
		*)
			echo "Unknown option: $1"
			show_help
			exit 1
			;;
	esac
done

# Validate required parameters
if [[ -z "$SUBJECT" ]]; then
	echo "Error: --subject is required."
	show_help
	exit 1
fi

# Handle body input
if [[ -n "$BODY_FILE" ]]; then
	if [[ ! -f "$BODY_FILE" ]]; then
		echo "Error: Body file '$BODY_FILE' does not exist."
		exit 1
	fi
	BODY=$(<"$BODY_FILE")
elif [[ -z "$BODY" ]]; then
	echo "Enter the body of the email (end with Ctrl-D):"
	BODY=$(</dev/stdin)
fi

# Send email
{
	echo "From: $FROM"
	echo "To: $TO"
	echo "Subject: $SUBJECT"
	echo "Content-Type: text/plain; charset=UTF-8"
	echo
	printf "%b\n" "$BODY"
} | /usr/sbin/sendmail -t -f "$FROM"

# /usr/sbin/sendmail -f "$FROM" "$TO" <<EOF
# From: $FROM
# To: $TO
# Subject: $SUBJECT

# $BODY
# EOF

echo "Email sent to $TO"

And here is the output I see when I login as the test user:

ssh test@my_server.com
test@my_server.com's password:
dir=/ failed: exit code 2
dir=/ failed: exit code 2
Linux my_server 6.1.0-37-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.140-1 (2025-05-22) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Aug 15 07:08:24 2025 from my_ip_address
Could not chdir to home directory /home/test: No such file or directory

I don't get email alerts for any user, neither the test user nor my regular admin user.

Here is my /etc/pam.d/sshd relevant lines:

# Standard Un*x session setup and teardown.
account optional pam_exec.so seteuid dir=/ /usr/local/bin/login_notify.sh
@include common-session

I also tried with session instead of account and without the dir=/ part.

Can anyone help me troubleshoot this please?

Thanks in advance. Of course if you need any more info I'll do my best to provide it :)

top 12 comments
sorted by: hot top controversial new old
[–] HelloRoot@lemy.lol 3 points 4 months ago* (last edited 4 months ago) (1 children)

Your PAM line calls /usr/local/bin/login_notify.sh but your script is named login-alert.sh. That alone makes pam_exec fail (ENOENT).

Seems like AI hallucination type of mistake.

[–] promitheas@programming.dev 2 points 4 months ago

I corrected it and restarted the ssh service and then logged in as test user but it still give the same output. Tbh I havent slept so I think I should leave it until tomorrow and look at it with fresh eyes.

[–] hendrik@palaver.p3x.de 1 points 4 months ago* (last edited 4 months ago) (1 children)

According to man on my computer, pam_exec doesn't have any "dir" parameter, so you might need to remove that.

But it has a "log" parameter, so you could add "set +eux" to your script and add a "log=/tmp/loginalert.log" to the pam_exec call and see what the error message is. Or use the "stdout" option to make it output the errors to stdout on login for debugging.

~~It seems to me you're requiring a subject and body text, but never setting any.~~

[–] promitheas@programming.dev 2 points 4 months ago (1 children)

Ill remove the dir parameter and add the stdout logging and come back with more info.

As for the subject body, I set those from the -s and -b flags respectively when calling semail

[–] hendrik@palaver.p3x.de 1 points 4 months ago

Sure, you're right, I skipped past that. Maybe you need to add a few print statements as well. For example I don't know when SSH_CONNECTION gets set. Maybe that's not yet available if you use "account" instead of "session".

[–] bjoern_tantau@swg-empire.de 1 points 4 months ago

Nice idea. Saving this thread to try that on my own server when I have the energy.

I wouldn't do that with failed logins, though. My server is hammered with myriad login attempts all the time.

[–] zero_spelled_with_an_ecks@programming.dev 1 points 4 months ago (1 children)

It looks like pam_exec has a log file option and a debug option. Those will give you some more info about what's going on.

There's also one piece that I don't think you mentioned, and that's sshd config settings for pam. See if usePAM is set there.

[–] promitheas@programming.dev 2 points 4 months ago

Ill try adding the log options, and come back with results.

As for the sshd config, UsePAM is set to yes.

[–] truthfultemporarily@feddit.org 1 points 4 months ago (1 children)

Does the shell script have execute permission?

[–] promitheas@programming.dev 1 points 4 months ago (1 children)
[–] truthfultemporarily@feddit.org 1 points 4 months ago (1 children)

You have not shown login-notify.sh

You can also always do a cronjob parsing auth.log.

[–] promitheas@programming.dev 1 points 4 months ago* (last edited 4 months ago)
$ cat /usr/local/bin/login-alert.sh
#!/bin/bash

# Sends alerts only for real terminals not cron jobs
if [[ -n "$SSH_CONNECTION" ]]; then
	USERNAME=$(whoami)
	IP=$(echo $SSH_CONNECTION | awk '{print $1}')
	HOST=$(hostname)
	DATETIME=$(date)
	/usr/local/bin/semail \
		-s "[CRITICAL] SSH Login to $HOST" \
	 	-b "Login detected:\n\nUser: $USERNAME\nIP: $IP\nTime: $DATETIME\nTTY: $SSH_TTY"
fi

I feel like since Im already using systemd to monitor the directories it would be best to have everything working with systemd, also because I will be adding several other such functionalities to monitor various things. For example something I already implemented is a systemd service + timer combination to periodically check the main branch of the git repo for changes to the servers local repo, and if there are any to pull them and restart any services necessary to reflect these changes on the web app, then once again email me that that happened. This way i dont need to actually connect to the server to update any changes, just push code to github.

This is my first time doing a project like this, so this might make you seasoned sysadmins yell out in horror, idk, but since Im the only one who can push code to the repo I feel its quite safe, and makes life a lot easier for me xD