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).