pavement

SSH, limiting to SCP or Rsync only

From FreeBSDwiki
Revision as of 16:59, 30 July 2005 by Jimbo (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Use this code to create a custom shell for user accounts that you want to be able to use scp, sftp, or rsync with SSH transport, but not to have an actual shell available. Remember that this limits "snoopiness" to some degree but is NOT any kind of hardcore lockout, as any files or directories that the user has read permissions on can be scp'ed or rsync'ed over to their machine for local perusal, and any which they have write permissions on can be OVERWRITTEN with versions scp'ed or rsync'ed over FROM their machine!

Once you've saved the small C program below to a work directory as scpsftprsynconly.c, you can compile it and assign it to a user like this:

ph34r# gcc scpsftprsynconly.c -o /usr/local/bin/scpsftprsynconly
ph34r# pw usermod dave -s /usr/local/bin/scpsftprsynconly

Now user dave can use scp or sftp (if sftp is set up) or rsync (if rsync is available) commands with ssh, but cannot actually log into the box - remotely OR locally I might add! Here's a test showing ssh and local logins failing, but an scp succeeding:

ph34r# ssh dave@localhost
This account is currently not available.
ph34r# su dave
This account is currently not available.
ph34r# scp dave@localhost:/usr/local/bin/scpsftprsynconly .
Password:
scpsftprsynconly                               100%  130KB 129.7KB/s   00:00

And there we have it - it works. Note that you might want to actually LOOK at the code; it's assuming that rsync and scp will be findable via the system's PATH environment variable. If that's not the case, or if you're feeling a little extra-paranoid and want to hard-code in assurance that ONLY the particular executable you want - say, /usr/local/bin/rsync - can be run, you might want to hack that in the way you want it; just keep in mind that if your custom shell is looking to allow just rsync, it WON'T allow /usr/local/bin/rsync and vice versa. So you might wind up having to mess about with flags for your scp and rsync commands from remote machines to specify paths, if you screw around with that stuff.

Enjoy!

 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
 /*
 **  Original by Patric Draper <http://www.pdrap.org/about/>
 **
 **  Changes on 13-Mar-2004 by Msquared <http://www.msquared.id.au/>
 **
 **    * fixed bug in args to realloc()
 **    * fixed bug in parameter checks (validates entire command name)
 **    * Modified to work with OpenSSH SFTP
 **    * Added rsync support
 **
 **  This code is in the public domain.  No warranty.  If it breaks,
 **  you can dispose of it as you see fit.
 **
 **  Build with DEBUG to save calling arguments to /tmp/scpshell.log
 **  This is useful to add new protocols, debug existing calls, etc.
 */
 
 char * restrictmsg = "This account is currently not available.\n";
 
 int main (int argc, char *argv []) {
         char **newargs = NULL;
         char *newbuff = NULL;
         int i;
         char *s;
 
 #ifdef DEBUG
 
         FILE * log = fopen("/tmp/scpshell.log","a+");
         if ( log ) {
                 char **par = argv;
                 while ( *par )
                         fprintf ( log, "[%s] ", *par++ );
                 fprintf ( log, "\n" );
                 fclose(log);
         }
 
 #endif
 
         if (argc < 3) {
                 printf (restrictmsg);
                 return 1;
         }
         if ((strncmp (argv [2], "scp ", 4) != 0) &&
             (strncmp (argv [2], "/usr/libexec/openssh/sftp-server", 33) != 0) &&
             (strncmp (argv [2], "rsync ", 6) != 0)) {
                 printf (restrictmsg);
                 return 2;
         }
         i = 0;
         newbuff = strdup(argv[2]);
         s = strtok (newbuff, " ");
         do {
                 newargs = (char **) realloc (newargs, ++i*sizeof(*newargs));
                 newargs [i - 1] = strdup (s);
         } while ((s = strtok (NULL, " ")) != NULL);
 
         newargs = (char **) realloc (newargs, ++i*sizeof(*newargs));
         newargs [i - 1] = NULL;
 
         execvp (newargs [0], newargs);
 
         return 0;
 }
Personal tools