Pam_script :

Download location (HTTP):       http://freshmeat.net/projects/pam_script
Version used:                   0.1.5

Scripts :

Download location (HTTP):       http://linux.bononline.nl/linux/pamscript/src/scripts
                                


Installation of pam_script



tar -xzf pam-script-*.tar.gz
cd pam-script-*
make
mv pam_script.so /lib/security
chown root:root /lib/security/pam_script.so
chmod 755 /lib/security/pam_script.so
	



Adjusting PAM configuration




The module is stacked in the sessionpart:

cat /etc/pam.d/login
-- snip --

session		optional	pam_mail.so dir=/var/mail noenv close empty
session		optional	pam_motd.so
session		required	pam_script.so runas=root
session		required	pam_unix.so shadow md5
session		required	pam_ldap.so

	

Pam_script has the ability (from version 0.1.5) to get the password provided at login, and make this via an evironmentvariable PAM_AUTHTOK available to scripts.
Insert it in the authpart:

cat /etc/pam.d/login
-- snip --

auth		required	pam_shells.so
auth		sufficient	pam_unix.so shadow md5
auth		required	pam_script.so expose=1
auth		required	pam_ldap.so use_first_pass

	


Note that if the module pam_unix.so succees, pam_script.so is skipped. This no problem for me. On my desktop I only want pam_script and the scripts for my normal users, which are in the LDAP database. I had to do this, because version 0.1.5 does not ask for a password: another module has to do that. That other module is pam_ldap.so or pam_unix.so.

When using other ways for users to login than the standard, like a X-based login as kdm,
adjust them the same way. On my machine I login frequently with kdm, and that uses the
kde-service, which is a symlink to the login-service:

cd /etc/pam.d
    
ls -al
    
drwxr-xr-x   2 root root  392 2005-07-11 13:59 .
drwxr-xr-x  36 root root 3152 2005-07-19 14:09 ..
-rw-r--r--   1 root root  253 2004-05-12 16:06 chage
-rw-r--r--   1 root root   69 2005-01-12 00:20 cups
-rw-r--r--   1 root root  330 2005-01-19 10:00 fcron
-rw-r--r--   1 root root  506 2004-12-22 23:04 fcrontab
lrwxrwxrwx   1 root root    5 2005-07-11 13:59 kde -> login
lrwxrwxrwx   1 root root    5 2005-07-11 13:59 kde-np -> login
-rw-r--r--   1 root root  931 2005-07-19 13:20 login
-rw-r--r--   1 root root  305 2005-07-16 22:46 other
-rw-r--r--   1 root root  282 2003-08-13 18:22 passwd
-rw-r--r--   1 root root  411 2003-08-12 17:53 shadow
-rw-r--r--   1 root root  448 2005-07-18 10:18 su
-rw-r--r--   1 root root  666 2005-02-28 12:59 sudo
-rw-r--r--   1 root root  257 2004-05-12 16:05 useradd
-rw-r--r--   1 root root  200 2005-04-25 09:05 xscreensaver
	




Notes :



- the pam_script.so uses some parameters. All of them are described in the README in the source directory.
I use expose=1 in the authpart because I want the password to be used by fusesmb.
And in the sessionpart I use runas=root because some actions (like umount) have to be run as root.
- to make use of the module I had to reorder the auth-part. The module pam_script has to become after pam_unix or pam_ldap, but before pam_ldap.


Creating the session scripts




Pam_script.so works with three scripts, standard onsessionopen, onsessionclose and onauth in the /etc/security directory.
The onsessionopen script looks like:

cat >> /etc/security/onsessionopen << "EOF"
#!/bin/bash

userid=$1
service=$2
userproperties=$(getent passwd | grep -E "^$userid");    
    
if [ -z "$userproperties" ]; then

    #
    # userproperties not found: something wrong
    #
    
    echo "User not found."
    exit
    
fi;
    
nrusers=$(w -h  $userid | wc -l );
    
firstsession=0;

case "$service" in
    login)
	if [ $nrusers -eq 0 ]; then

	    firstsession=1;

	fi;
	;;
    kde)
	if [ $nrusers -eq 0 ]; then

	    firstsession=1;
		
	fi;
	;;
esac;

if [ $firstsession -eq 1 ]; then

    # There are no other sessions for this user: this is the first

    if [ -d /var/lib/pam/scripts/onsessionopen ]; then

	for script in /var/lib/pam/scripts/onsessionopen/*.sh ; do
	    
	    if [ -x $script ] ; then

		eval $script $userid $

	    fi;
	    
	done;
	
    fi;	

fi;

EOF
	


The onsessionclose script:

cat >> /etc/security/onsessionclose << "EOF"
#!/bin/bash

userid=$1
service=$2
userproperties=$(getent passwd | grep -E "^$userid");    
    
if [ -z "$userproperties" ]; then

    #
    # userproperties not found: something wrong
    #
    
    echo "User not found."
    exit
    
fi;
    

nrusers=$(w -h $userid | wc -l );

lastsession=0;

case "$service" in
    login)
	if [ $nrusers -eq 1 ]; then

	    lastsession=1;

	fi;
	;;
    kde)
	if [ $nrusers -eq 0 ]; then

	    lastsession=1;
	fi;
	;;
esac;


if [ $lastsession -eq 1 ]; then

    # This is the last session for this user

    if [ -d /var/lib/pam/scripts/onsessionclose ]; then

	for script in /var/lib/pam/scripts/onsessionclose/*.sh ; do
	    
	    if [ -x $script ] ; then
		eval $script $userid
	    fi;
	done;
	
    fi;	

fi;

EOF

	


The onauth script:

cat >> /etc/security/onauth << "EOF"
#!/bin/bash

userid=$1
service=$2
userproperties=$(getent passwd | grep -E "^$userid")

if [ -z "$userproperties" ]; then

    #
    # userproperties not found: something wrong
    #
    
    echo "User not found."
    exit
    
fi;


homedir=$(echo $userproperties | cut -d ":" -f 6);
gidnr=$(echo $userproperties | cut -d ":" -f 4);
uidnr=$(echo $userproperties | cut -d ":" -f 3);

nrusers=$(w -h $userid | wc -l);

firstsession=0;

case "$service" in

    login)
	
	if [ $nrusers -eq 0 ]; then
	    
	    firstsession=1;
	    
	fi;
	;;

    kde)
	
	if [ $nrusers -eq 0 ]; then
	    
	    firstsession=1;
	    
	fi;
	;;
esac;	    


if [ $firstsession -eq 1 ]; then
        
    if [ -d /var/lib/pam/scripts ]; then
	    
	for script in /var/lib/pam/scripts/onauth/*.sh; do
	
	    if [ -x $script ]; then
		
		eval $script $userid $service $PAM_AUTHTOK
		
	    fi;
	done;
	
    fi;

fi;

exit 0
	


Set permissions and rwx bits right:

chown root:root /etc/security/onsession*
chmod 755 /etc/security/onsession*
chown root:root /etc/security/onauth
chmod 755 /etc/security/onauth
	


These scripts can also be downloaded from:


Create the directories where the scripts will go:

mkdir -p /var/lib/pam/scripts/onsessionopen
mkdir -p /var/lib/pam/scripts/onsessionclose
mkdir -p /var/lib/pam/scripts/onauth
	


The construction is now ready to execute sessionscripts at login and logout. But this still does nothing: there are no scripts in the open and the close directory. There are some examples of scripts I'm using on my system.


Notes :



Determing how many times a user is logged in

- as you can see I use the command "w" to determine the users logged in. Other utilities as who, users and last gave not reliable information. It looks as if the utmp file is not always presenting the right values. Utilities as who,users and last show information from utmp without any check, so they inherit the faults. 'w' does some extra checking, which makes it more usable.
Other pammodules, like pam_mount, have other ways to keep track of the amount of logins per user. With pam_mount, a seperate file (/var/run/pam_mount/$userid) is created for this purpose.
Anyone knowing a better way to determine how many times a user is logged in, please let me know.

SUDO is needed

- in the examples 'sudo' is used. This is not included in the BLFS 6.1 book, so you have to install it yourself. Sources available at the homepage of sudo.
This is not difficult. Sudo does not have to support PAM. That's not neccasary. It's only needed to execute a command as normal user when the id is root.

Some remarks about "login" and the utmp database

The number of sessions is zero when logging in: the user is still not logged in. This happens with all the services I'm using: login and kde.
When logging out, something strange happens: it's one when logging out when the service is 'login', zero when service is "kde" (and this user is not logged in on any other way). I've just discovered what's causing this. The program "login" is responsible. It stores a record in the utmp-database with the pid of the login-proces (the parent), not the pid of the shell (the child). When the session is closed, the proces with the pid stored in the utmp database isn't closed at all. That's the login program itself, which is still running. So, when using "w" to check the users logged in, it finds that the proces with the pid in the utmp database for this user is still running, it concludes this user must still be logged in, which is not the case.
I've posted a message about this issue on the maillinglist op shadow.