2003-12-20sftp doing chroot

To increase security on a public sftp-server, the sftp-server itself can be modified to perform a chroot when a random, not-root user starts a session.
First, you need the sources. Just get them.
In the sources, in file sftp-server.c, just above the main function, you put these lines.
// ----------------------------------------------------------------------- // by e-circ // ----------------------------------------------------------------------- //static const char * chroot_user_file = SSHDIR "/chroot-users"; #define syslog_raw(p0, p1, p2, args ...) \ { \ syslog(LOG_INFO, "(" p0 ", " p1 ") {errno %d=%s} " p2 \ , errno, strerror(errno) \ , ## args \ );\ } #define syslog_info(p1, p2, args ...) \ { \ syslog_raw("info", p1, p2, ## args); \ } #define syslog_fatal(p1, p2, args ...) \ { \ syslog_raw("fatal", p1, p2, ## args); \ closelog(); \ exit (errno); \ } static void chroot_init(int argc, const char * const argv []) { struct passwd * pwd; int do_chroot; const char * new_home = 0; { int j; for (j = 0; j < argc; ++j) { if (!strcmp(argv[j], "--chroot")) { if ((j+1) < argc) { ++j; new_home = argv[j]; } } } } openlog("sftp-server/e-circ", LOG_PID | LOG_CONS, LOG_AUTH); if (!(pwd = getpwuid(getuid()) )) syslog_fatal("getpwuid", ""); do_chroot = (0 != pwd->pw_uid); syslog_info("session", "user=%s, home_dir=%s, chroot=%d" , pwd->pw_name, pwd->pw_dir, do_chroot); if (do_chroot) { if (0 != chroot(pwd->pw_dir)) syslog_fatal("chroot", "userdir=%s, uid=%d", pwd->pw_dir, pwd->pw_uid); if (0 != setenv("HOME", "/samba", 1)) syslog_info("setenv", "HOME=/samba"); if (0 != new_home) { if (0 != chdir(new_home)) syslog_info("chdir", "dst=%s", new_home); } } if (setuid(getuid()) != 0) syslog_fatal("setuid", "Couldn't drop user privileges" ); if (setgid(getgid()) != 0) syslog_fatal("setgid", "Couldn't drop group privileges"); closelog(); } // ----------------------------------------------------------------------- // ~by e-circ // -----------------------------------------------------------------------
A little lower, in the main function, turn this
if (setuid(getuid()) != 0) fatal("Couldn't drop privileges: %s", strerror(errno)); in = dup(STDIN_FILENO); out = dup(STDOUT_FILENO);
into this.
// by e-circ chroot_init(ac, (const char **)av); // The privileges drop is done in chroot_init() //if (setuid(getuid()) != 0) // fatal("Couldn't drop privileges: %s", strerror(errno)); in = dup(STDIN_FILENO); out = dup(STDOUT_FILENO);
You should build and install. As you may have noticed, the chroot function only gets activated when sftp-server is executed with parameters. Unfortunately, those parameters cannot be passed from within /etc/ssh/sshd_config, so we use an in-between script that exec's the real sftp-server with the appropriate parameters.
Additionally, sftp-server needs root permissions to do it's chroot job, so make it setuid root as in
chmod +s sftp-server
This causes sftp-server always to execute as user root (if root is owner). This is not a giant problem, as privileges are dropped immediately after startup.
So modify /etc/ssh/sshd_config. The last line, which specifes the sftp-server, must be modified to point to the in-between script. So, insert this line
Subsystem sftp /usr/libexec/sftp-server-script
and add the file /usr/libexec/sftp-server-script
exec /usr/libexec/sftp-server --chroot /homedir
The --chroot enables chrooting, and the /homedir changes dir to /homedir (within the chroot).