SSH – Force Command execution on login even without Shell

The ForceCommand option runs without a PTY unless the client requests one. As a result, you don't actually have a shell to execute scripts the way you might expect. In addition, the OpenSSH SSHD_CONFIG(5) man page clearly says:

The command is invoked by using the user's login shell with the -c option.

That means that if you've disabled the user's login shell, or set it to something like /bin/false, then ForceCommand can't work. Assuming that:

  1. the user has a sensible shell defined,
  2. that your target script is executable, and
  3. that your script has an appropriate shebang line

then the following should work in your global sshd_config file once properly modified with the proper username and fully-qualified pathname to your custom script:

Match User foo
    ForceCommand /path/to/script.sh

I am the author of the OP; I came to the conclusion that what I need to achieve is not possible using SSH only to the date (OpenSSH_6.9p1 Ubuntu-2, OpenSSL 1.0.2d 9 Jul 2015), but I found a great piece of software that uses encrypted SPAuthentication to open SSH port and it's new version (to the date of this post, it's GitHub master branch) has a feature to execute a command always that a user authorizates successfully.

FWKNOP - Encrypted Single Packet Authorization

FWKNOP set iptables rules that allow access to given ports upon a single packet encrypted which is sent via UDP. Then after authorization it allow access for the authorized user for a given time, for example 30 seconds, closing the port after this, leaving the connection open.

1. To install on an Ubuntu linux:

The current version (2.6.0-2.1build1) on Ubuntu repositories to the date still doesn't allow command execution on successful SPA; (please use 2.6.8 from GitHub instead)

On client machine:

sudo apt-get install fwknop-client

On server side:

sudo apt-get install fwknop-server

Here is a tutorial on how to setup the client and server machines https://help.ubuntu.com/community/SinglePacketAuthorization

Then, after it is set up, on server side:

  1. Edit /etc/default/fwknop-server
  2. Change the line START_DAEMON="no" to START_DAEMON="yes"
  3. Then run:

    sudo service fwknop-server stop

    sudo service fwknop-server start

2. Warning admin on successful SPA (email, pushover script etc)

So, as stated above the current version present in Ubuntu repositories (2.6.0-2.1build1) cannot execute command on successful SPA. If you need this feature as of the OP, but it will be released at fwknop version (2.6.8), as can it is stated here:

https://github.com/mrash/fwknop/issues/172

So if you need to use it right now you can build from github branch master which have the CMD_CYCLE_OPEN option.

3. More resources on fwknop

https://help.ubuntu.com/community/SinglePacketAuthorization

https://github.com/mrash/fwknop/ (project on GitHub)

http://www.cipherdyne.org/fwknop/ (project site)

https://www.digitalocean.com/community/tutorials/how-to-use-fwknop-to-enable-single-packet-authentication-on-ubuntu-12-04 (tutorial on DO's community)


If you only need to run a script you can rely on pam_exec.

Basically you reference the script you need to run in the /etc/pam.d/sshd configuration:

session optional pam_exec.so seteuid /path/to/script.sh

After some testing you may want to change optional to required.

Please refer to this answer "bash - How do I set up an email alert when a ssh login is successful? - Ask Ubuntu" for a similar request.

Indeed in the script only a limited subset on the environment variables is available:

LANGUAGE=en_US.UTF-8
PAM_USER=bitnami
PAM_RHOST=192.168.1.17
PAM_TYPE=open_session
PAM_SERVICE=sshd
PAM_TTY=ssh
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8
PWD=/

If you want to get the user info from authorized_keys this script could be helpful:

#!/bin/bash
# Get user from authorized_keys
# pam_exec_login.sh
# * [ssh - What is the SHA256 that comes on the sshd entry in auth.log? - Server Fault](https://serverfault.com/questions/888281/what-is-the-sha256-that-comes-on-the-sshd-entry-in-auth-log)
# * [bash - How to get all fingerprints for .ssh/authorized_keys(2) file - Server Fault](https://serverfault.com/questions/413231/how-to-get-all-fingerprints-for-ssh-authorized-keys2-file)

# Setup log
b=$(basename $0| cut -d. -f1)
log="/tmp/${b}.log"

function timeStamp () {
  echo "$(date '+%b %d %H:%M:%S') ${HOSTNAME} $b[$$]:"
}

# Check if opening a remote session with sshd
if [ "${PAM_TYPE}" != "open_session" ] || [ $PAM_SERVICE != "sshd" ] || [ $PAM_RHOST == "::1" ]; then
  exit $PAM_SUCCESS
fi

# Get info from auth.log
authLogLine=$(journalctl -u ssh.service |tail -100 |grep "sshd\[${PPID}\]" |grep "${PAM_RHOST}")
echo ${authLogLine} >> ${log}

PAM_USER_PORT=$(echo ${authLogLine}| sed -r 's/.*port (.*) ssh2.*/\1/')
PAM_USER_SHA256=$(echo ${authLogLine}| sed -r 's/.*SHA256:(.*)/\1/')

# Get details from .ssh/authorized_keys
authFile="/home/${PAM_USER}/.ssh/authorized_keys"
PAM_USER_authorized_keys=""

while read l; do
  if [[ -n "$l" && "${l###}" = "$l" ]]; then
    authFileSHA256=$(ssh-keygen -l -f <(echo "$l"))
    if [[ "${authFileSHA256}" == *"${PAM_USER_SHA256}"* ]]; then
      PAM_USER_authorized_keys=$(echo ${authFileSHA256}| cut -d" " -f3)
      break
    fi
  fi
done < ${authFile}

if [[ -n ${PAM_USER_authorized_keys} ]]
then
  echo "$(timeStamp) Local user: ${PAM_USER}, authorized_keys user: ${PAM_USER_authorized_keys}" >> ${log}
else
  echo "$(timeStamp) WARNING: no matching user in authorized_keys" >> ${log}
fi

Tags:

Ssh

Sshd