Monday, November 29, 2010

Login notifications, pam_exec scripting

If you like monitoring, you might want to receive notifications at every (or only root) login, in addition to logs.

/etc/profile, bashrc, etc.

One can first think of a script in /etc/profile - I saw that solution on many websites - but it is wrong because the user can connect with ssh /bin/sh and it will not run any login script. Also, this kind of login does not appear in last/wtmp but only in auth.log by sshd (because it's not considered as an "interactive login").

Parse logs

Second solution is to parse the auth.log - for instance with SEC, Simple Event Correlator - and use a notify script. It should work, yet I prefer the third solution.


Third solution is to use PAM (Pluggable Authentication Modules). It has a module named pam_exec to execute a script at every PAM event, such as a successfull login.

First, create a notify-login script. According to pam_exec manual, PAM items are passed to the script as environment variables, so we are able not only to restrict the script to open_session (login) event but also to get user, remote host and other information. I made the following notify script, adapt it to your needs:
[ "$PAM_TYPE" = "open_session" ] || exit 0
  echo "User: $PAM_USER"
  echo "Ruser: $PAM_RUSER"
  echo "Rhost: $PAM_RHOST"
  echo "Service: $PAM_SERVICE"
  echo "TTY: $PAM_TTY"
  echo "Date: `date`"
  echo "Server: `uname -a`"
} | mail -s "`hostname -s` $PAM_SERVICE login: $PAM_USER" root
I chose to email root but thanks to /etc/aliases it arrives directly in my inbox.

Note: you may need a recent version of PAM library to have PAM_TYPE (it was added in rev 1.8). For instance Debian lenny's pam_exec does not support it (libpam-modules 1.0) while Debian squeeze's has it (libpam-modules 1.1).

Second, we prepare a pam_exec rule:
session    optional /usr/local/bin/notify-login
We have to add this rule to every login service that uses PAM: SSH but also su, login, sudo, etc. We want to avoid logins via cron that are not interative. On Debian (and maybe other distros), PAM provides a common-session rule that is included for almost all these services:
# grep 'common-session$' /etc/pam.d/*
/etc/pam.d/chfn:@include common-session
/etc/pam.d/chsh:@include common-session
/etc/pam.d/cvs:# @include common-session
/etc/pam.d/login:@include common-session
/etc/pam.d/other:@include common-session
/etc/pam.d/sshd:@include common-session
/etc/pam.d/su:@include common-session
Note: Cron and other non interactive services are using common-session-noninteractive rule. The only missing service is sudo which does not include common-session (Debian bug #519700 still not fixed). So we add the pam_exec rule to /etc/pam.d/common-session and /etc/pam.d/sudo, and we are all set!

Inform users of logins

Another application of pam_exec could be to provide users with a history of their logins. Indeed as a regular user on a system, how can you know all logins made to your account? You cannot rely on last/wtmp because it can be avoided using ssh /bin/sh, and you cannot read auth.log. A solution could be to use a pam_exec script to write logins into a rw-r---- root:$user log file such as /var/log/logins/$user.log.


  1. Hi,

    I'm trying to implement something similar, but all my PAM environment variables are coming back empty.

    I've googled for hours and there's very little out there on PAM that I can find, have you any pointers in the right direction?

    Thanks in advance for any help!

  2. What is your PAM version?
    Have you installed PAM modules?

    Under Debian you can see both with dpkg -l |grep libpam. For instance on Debian Squeeze I have libpam0g, libpam-modules and libpam-runtime, all in version 1.1.1-6.1.

  3. Thanks for this great hint!
    We should also mention that sending mails to local mail accounts is witless if you want to monitor break-ins ;-)

  4. Is it possible to execute the script as root at each user logon ?

  5. I've no idea. What do you want to do?

  6. I ran into
    /usr/local/bin/notify-login failed: exit code 13
    which could be fixed through
    chmod 755 /usr/local/bin/notify-login
    as root.

    Thx 4 ya infos!

  7. I'm trying to create a script as to notify wenever someone fails to provide a correct password for ssh.
    the script is basically echo `date`';'$PAM_SERVICE';'$PAM_USER';'$PAM_TYPE >> $logfile

    The log looks like this (date;service;user;event):
    lun ago 5 01:52:06 ART 2013;su;root;open_session
    lun ago 5 01:52:08 ART 2013;su;root;close_session
    Mon Aug 5 01:52:17 ART 2013;sshd;alejandro;auth
    lun ago 5 01:52:17 ART 2013;sshd;alejandro;open_session
    lun ago 5 01:52:19 ART 2013;sshd;alejandro;close_session

    However I'm failing to record when someone gives an incorrect password.

    Dont know if will help but there is the /var/log/auth.log output for the incorrect attemps:

    Aug 5 01:56:07 d-U10 sshd[24161]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=d-u10.local user=alejandro
    Aug 5 01:56:07 d-U10 sshd[24161]: pam_winbind(sshd:auth): getting password (0x00000388)
    Aug 5 01:56:07 d-U10 sshd[24161]: pam_winbind(sshd:auth): pam_get_item returned a password
    Aug 5 01:56:07 d-U10 sshd[24161]: pam_winbind(sshd:auth): internal module error (retval = PAM_AUTHINFO_UNAVAIL(9), user = 'alejandro')
    Aug 5 01:56:08 d-U10 sshd[24161]: Failed password for alejandro from port 38441 ssh2

    What entry should I add (and where) besides the session    optional /usr/local/bin/notify-login.

    Thanks in advance

  8. Hello, I don't know if it's possible via PAM: it looks like the failure is logged before by PAM itself and not given to pam_exec.

    You can try a different approach by tail+grep auth.log and notifying on lines matching "Failed password".

  9. Hi,

    I'm trying to implement this, but got the message while i logged in "/usr/local/bin/notify-login failed: exit code 127"
    I've googled, but only thing i got, this is due to "command not found" and possible problem is with $PATH or a typo.

    Thanks in advance for any help!

  10. Make sure to save the script above as /usr/local/bin/notify-login and executable.
    Make sure to have mail command installed.
    If it still does not work it could be $PATH, you can set it in the script.

  11. Hello,
    Thanks for the reply, i found the exact issue.
    Mail command is missing on my server, thats why server is throwing "code 127"
    i simply installed it by "apt-get install bsd-mailx" and now script is working good for me. :-)

  12. Works great on Debian Squeeze. Thanks for sharing!

  13. Works great! Thanks for this article, helped allot. I did change a few things in the script:

    Since there aren't many system vars loaded (on my ubuntu machine anyway) i just used env to dump them all. I also added date, who (current logged on identities) and a searchable string.

    (echo "Subject: Remote login: $PAM_RHOST"; echo 'Somebody logged on from a remote terminal!'; date ; who ; env) | ssmtp | exit 0