Sometimes one need to create a special SSH accounts that do only one thing: starts a program or a shell script. In that case one might need to prevent possibility to download or upload files to server. Due to my research it was not so trivial task as it might be looking.
Lets start with a description of how SCP and SFTP works.
SFTP works as subprocess of shell. So basically when user logs in via sftp client shell starts subprocess which in case of CentOS is /usr/libexec/openssh/sftp-server(One can find that info in /etc/ssh/sshd_config).
Meanwhile SCP talks directly with a shell. So it actually needs /bin/bash set as user shell.
Commonly described solution such as:
Match Group nosft Subsystem sftp /bin/false
actually doesn’t work on CentOS(At least version 6). Maybe because SSHD is too old or something like that. If one tries to restart SSHD with above code in the config file he will get following error:
# service sshd restart Stopping sshd: [ OK ] Starting sshd: /etc/ssh/sshd_config line 141: Directive 'Subsystem' is not allowed within a Match block [FAILED]
I’ve found small trick how to solve this problem.
First thing is to disable SFTP. Since it’s using another process withing shell let’s find it and deny it. For that I’m going to use small shell script that is wrapper around /bin/bash. So one needs to set following script as login shell of user account:
#!/bin/bash # disable sftp if [ "$2" == "/usr/libexec/openssh/sftp-server" ]; then exit 1 fi /bin/bash
What it does? It’s actually looking for second argument of the starting command and if it matches sftp-server it exits with status code 1. And when user tries to initiate SFTP session it immediately drops a session.
But in case of SCP client will think a little longer but it will login and allow download and upload files. What to do? Since SCP talks directly to the shell we need to get rid of shell. Replace last scring (/bin/bash) in above script with a program that you want user to interact (example: telnet to another device) and SCP will fail to connect due to timeout since it cannot talk directly to shell.
I hope I didn’t miss anything important. 😉