1

Im trying to send a notification upon login via PAM, but i cant figure out how to send it to the user that is logging in.

I'm configuring my PAM to execute a script every time a user logs in. The problem is i need to send a notification if there have been any login attempts (its part of a bigger security thing im trying to add, where my laptop takes a picture with the webcam upon failed logins, and notifies me when i log in again, since my classmates like to try and guess my password for some reason). The problem is that the line in my .sh file, which sends a user notification, sends it to root since thats the 'user' that executes the script, i want my script to send the notification to my current user (called "andreas"), but im having problems figuring this out.

Here is the line i added to the end of the PAM file system-login:

auth       [default=ignore]                pam_exec.so /etc/lockCam/call.sh

And here is the call.sh file:

#!/bin/sh

/etc/lockCam/notifier.sh &

The reason im calling another file is because i want it to run in the background WHILE the login process continues, that way the process doesnt slow down logging in.

Here is the script that is then executed:

#!/bin/sh

#sleep 10s

echo -e "foo" > "/etc/lockCam/test"
#This line is simply to make sure that i know that my script was executed

newLogins=`sed -n '3 p' /etc/lockCam/lockdata`

if [ $newLogins -gt 0 ]
then
    su andreas -c ' notify-send --urgency=critical --expire-time=6000 "Someone tried to log in!" "$newLogins new lockCam images!" && exit'
    callsInRow=`sed -n '2 p' /etc/lockCam/lockdata`
    crntS=$(date "+%S")
    crntS=${crntS#0}
    crntM=$(date "+%M")
    crntM=${crntM#0}
    crntH=$(date "+%H")
    crntH=${crntH#0}
    ((crntTime = $crntH \* 60 \* 60 + $crntM \* 60 + $crntS ))
    #This whole process is absolutely stupid but i cant figure out a better way to make sure none of the integers are called "01" or something like that, which would trigger an error
    echo -e "$crntTime\n$callsInRow\n0" > "/etc/lockCam/lockdata"
fi

exit 0

And this is where i THINK my error is, the line "su andreas -c...." is most likely formatted wrong or im doing something else wrong, everythin is executed upon login EXCEPT the notification doesnt show up. If i execute the script from a terminal when im already logged in there is no notification either, unless i remove the "su andreas -c" part and simply do "notify-send...", but that doesnt send out a notification when i log in, and i think thats because the notification is sent to the root user, and not "andreas".

andr813c
  • 45
  • 7

1 Answers1

1

I think your su needs to be passed the desktop users DBUS session bus address. The bus address can be easily obtained and used for X11 user sessions, but Wayland has tighter security, for Wayland the user session actually has to run up proxy to receive the messages. (Had you considered it might be easier to send an email?)

I have notify-desktop gist on github that works for X11 and should also work on Wayland (provided the proxy is running). For completeness I've appended the source code of the script to this post, it's extensively commented, I think it contains the pieces necessary to get you own code working.

#!/bin/bash
# Provides a way for a root process to perform a notify send for each
# of the local desktop users on this machine.
#
# Intended for use by cron and timer jobs. Arguments are passed straight
# to notify send.  Falls back to using wall.  Care must be taken to
# avoid using this script in any potential fast loops.
#
# X11 users should already have a dbus address socket at /run/user/<userid>/bus
# and this script should work without requiring any initialisation. Should
# this not be the case, X11 users could initilise a proxy as per the wayland
# instructions below.
#
# Due to stricter security requirments Wayland lacks an dbus socket 
# accessable to root.   Wayland users will need to run a proxy to 
# provide root with the necessary socket.  Each user can must add
# the following to a Wayland session startup script:
#
#      notify-desktop --create-dbus-proxy
#
# That will start xdg-dbus-proxy process and make a socket available under:
#      /run/user/<userid>/proxy_dbus_<desktop_sessionid>
#
# Once there is a listening socket, any root script or job can pass
# messages using the syntax of notify-send (man notify-send).
#
# Example messages
#      notify-desktop -a Daily-backup -t 0 -i dialog-information.png "Backup completed without error"
#      notify-desktop -a Remote-rsync -t 6000 -i dialog-warning.png "Remote host not currently on the network"
#      notify-desktop -a Daily-backup -t 0 -i dialog-error.png "Error running backup, please consult journalctl"
#      notify-desktop -a OS-Upgrade -t 0 -i dialog-warning.png "Update in progress, do not shutdown until further completion notice."
#
# Warnings:
#      1) There has only been limited testing on wayland
#      2) There has only been no testing for multiple GUI sessions on one desktop
#

if [ $1 == "--create-dbus-proxy" ]
then
    if [ -n "$DBUS_SESSION_BUS_ADDRESS" ]
    then
        sessionid=$(cat /proc/self/sessionid)
        xdg-dbus-proxy $DBUS_SESSION_BUS_ADDRESS /run/user/$(id -u)/proxy_dbus_$sessionid &
        exit 0
    else
        echo "ERROR: no value for DBUS_SESSION_BUS_ADDRESS environment variable - not a wayland/X11 session?"
        exit 1
    fi
fi


function find_desktop_session {
    for sessionid in $(loginctl list-sessions --no-legend | awk '{ print $1 }')
    do 
        loginctl show-session -p Id -p Name -p User -p State -p Type -p Remote -p Display $sessionid | 
            awk -F= '
                /[A-Za-z]+/ { val[$1] = $2; } 
                END { 
                    if (val["Remote"] == "no" && 
                    val["State"] == "active" && 
                    (val["Type"] == "x11" || val["Type"] == "wayland")) {
                        print val["Name"], val["User"], val["Id"];
                    } 
                }'
    done
}

count=0
while read -r -a desktop_info
do
    if [ ${#desktop_info[@]} -eq 3 ]
    then
        desktop_user=${desktop_info[0]}
        desktop_id=${desktop_info[1]}
        desktop_sessionid=${desktop_info[2]}
        proxy_bus_socket="/run/user/$desktop_id/proxy_dbus_$desktop_sessionid"
        if [ -S $proxy_bus_socket ]
        then
            bus_address="$proxy_bus_socket"
        else
            bus_address="/run/user/$desktop_id/bus"
        fi
        sudo -u $desktop_user DBUS_SESSION_BUS_ADDRESS="unix:path=$bus_address" notify-send "$@" 
        count=$[count + 1]
    fi
done <<<$(find_desktop_session)

# If no one has been notified fall back to wall
if [ $count -eq 0 ]
then
    echo "$@" | wall
fi

# Don't want this to cause a job to stop
exit 0