У меня проблемы с отправкой системного уведомления при входе пользователя (KDE Plasma) (Arch Linux)

Я пытаюсь отправить уведомление при входе в систему через PAM, но я не могу понять, как отправить его пользователю, который входит в систему.

Я настраиваю свой PAM для выполнения сценария каждый раз, когда пользователь входит в систему. Проблема в том, что мне нужно отправить уведомление, если были какие-либо попытки входа в систему (это часть более крупной меры безопасности, которую я пытаюсь добавить, где мой ноутбук принимает изображение с веб-камеры при неудачном входе в систему и уведомляет меня, когда я снова вхожу в систему, так как мои одноклассники почему-то любят пытаться угадать мой пароль). Проблема в том, что строка в моем файле .sh, которая отправляет уведомление пользователя, отправляет его пользователю root, поскольку это «пользователь», который выполняет скрипт, я хочу, чтобы мой скрипт отправлял уведомление моему текущему пользователю (называется «andreas» ), но у меня проблемы с этим.

Вот строка, которую я добавил в конец файловой системы PAM:

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

А вот и файл call.sh:

#!/bin/sh

/etc/lockCam/notifier.sh &

Причина, по которой я вызываю другой файл, заключается в том, что я хочу, чтобы он работал в фоновом режиме, ПОКА процесс входа в систему продолжается, таким образом, процесс не замедляет вход в систему.

Вот скрипт, который затем выполняется:

#!/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

И здесь я ДУМАЮ, что это моя ошибка, строка «su andreas -c....», скорее всего, отформатирована неправильно или я делаю что-то еще неправильно, все выполняется при входе в систему, ЗА ИСКЛЮЧЕНИЕМ уведомления не появляется. Если я выполняю скрипт с терминала, когда я уже вошел в систему, уведомления также не будет, если только я не удалю часть «su andreas -c» и просто не сделаю «уведомление-отправить ...», но это не отправит уведомление, когда я вхожу в систему, и я думаю, что это потому, что уведомление отправляется пользователю root, а не «andreas».


person andr813c    schedule 18.01.2019    source источник


Ответы (1)


Я думаю, что вашему su нужно передать адрес шины сеанса DBUS пользователей настольных компьютеров. Адрес шины можно легко получить и использовать для пользовательских сеансов X11, но Wayland имеет более строгую безопасность, для Wayland сеанс пользователя фактически должен запускать прокси-сервер для получения сообщений. (Вы думали, что отправить электронное письмо может быть проще?)

У меня есть notify-desktop gist на github, который работает для X11 и также должен работать на Wayland (при условии прокси работает). Для полноты картины я добавил исходный код скрипта к этому сообщению, он подробно прокомментирован, я думаю, что он содержит части, необходимые для того, чтобы ваш собственный код работал.

#!/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
person Michael Hamilton    schedule 27.03.2021