Bash – Trying to script rsync using pam_exec

bashpamrsync

I'm trying to write a bash script that will execute rsync when called by pam_exec. I've tried a couple different ways, and I'm not sure what I'm doing wrong.
When I try to run the script at login by adding

session     optional      pam_exec.so /usr/bin/local/sync.sh

to my sshd file, it gives me an exit code of 12.

If I log in and then manually run my script, it allows me to connect to the remote server, and it lists my files, but it doesn't actually sync anything.

I have tried the code below using buth $USER and $PAM_USER. $PAM_USER doesn't work at all.

#!/bin/sh 
rsync -azv -e ssh $USER@remote_server:/home/html/$USER/ /home/html/$USER

Best Answer

The man page for pam_exec explains that the module provides $PAM_USER, not $USER:

the following PAM items are exported as environment variables: PAM_RHOST, PAM_RUSER, PAM_SERVICE, PAM_TTY, PAM_USER and PAM_TYPE [...]

On my Debian based system I added this line just before the entry for pam_motd

# Run a script on login
session    optional     pam_exec.so /usr/local/etc/pam_exec.sh

I then created the test script, remembering to make it executable:

cat >/usr/local/etc/pam_exec.sh <<'EOF'; chmod a+rx /usr/local/etc/pam_exec.sh
#!/bin/bash
#
test open_session = "$PAM_TYPE" && {
    echo
    date
    echo "PAM_USER=$PAM_USER, USER=$USER."

} >>/tmp/pam_exec.log

exit 0
EOF

Finally, I opened a new login session to my test system, and saw that on session start I received information such as this in my log file /tmp/pam_exec.log:

Mon Nov  9 23:32:52 GMT 2015
PAM_USER=roaima, USER=.

To implement your requirement you would need to use a script something like this:

#!/bin/sh
rsync -azq -e ssh "$PAM_USER"@remote_server:/home/html/"$PAM_USER"/ /home/html/"$PAM_USER" >/dev/null 2>&1

Notice that all output from rsync is discarded. This is necessary to ensure that client/server applications using ssh as a transport do not get hit by unexpected output before they can start their negotiation. If you really want to present it to the user, I would recommend you write it to a user-specific log file such as "$HOME/.pam_exec.log" and then use a line like this in the user's .profile to output it after the login process has completed:

if test -t 1 -a -s "$HOME/.pam_exec.log"
then
    echo "Prelogin results"
    sed 's/^/| /' "$HOME/.pam_exec.log"
fi

It's not immune to a race condition, but IME most users don't login simultaneously multiple times to the same server. If you find this scenario is common there are ways to deal with it.