Hello, I know this chroot issue has been brought up many times before on this list. I saw that the contribibuted chroot-patch was removed from the contrib directory because it always was out of date. The main reason was of course was that sftp-server has to be run as root to be able to do the chroot() call? Most of you are against chroot (since it isnt in the src) but I believe a lot of users have use for it. I dont think the solution is to use SSH Corps version. There are several chroot-patches available, like the chrootssh project and rssh (restricted shell sftp) and scponly. To make a long story short, none of these provide the ability to chroot sftp users in their homedir. That is, in these projects you are able to wonder around the chroot-tree /dev /bin /usr etc. I have found rssh to be usable because it ables you to restrict the user to sftp or scp, and shutdown ssh-access, however the user still can wonder around the chroot-tree. I did a bit of research and came to the conclusion that the chroot-call needed to be done in the src of sftp-server.c I found three patches that does it: http://www.alt219.com/software/sftp-server-chroot/ http://www.coding-zone.com/chroot+sftp-server.patch http://groups.google.com/groups?hl=sv&lr=&ie=UTF-8&oe=UTF-8&frame=right&th=45c783aa0a25801a&seekm=arc304%241v5l%241%40FreeBSD.csie.NCTU.edu.tw#link1 Problem one seems to be that setuid(getuid()); is reversable. Also better sanity checking before chroot is required. I have written a patch that (probably) is more secure than the ones I found. It uses uidswap functions to change uid & gid. Someone said the point behind subsystems was all the configuration for that subsystem are contained in the subsystem proper and not in sshd_config. Thats why I didnt add any config-changes to this patch. So if someone feels like it, maybe /etc/ssh/sftp-server.conf is a good place to config chroot. Since I don't have much C-knowledge, there might be errors in this patch (it works for me though). Please reply with the correct code. Thanks to Ben Lindstrom for helping me with this... I use this patch together with rssh, and I put the sftp-binary in the rssh chroot /ftproot/usr/local/libexec and its called by rssh-chroot-helper. When a user logins with sftp he will get chrooted to /ftproot/home/user. I shutdown access to scp and ssh, only sftp is allowed, so the user will never see the files in /ftproot To apply this patch on OpenSSH 3.6.1p2: - patch -p0 < sftp-server.patch - edit Makefile and include uidswap.o in sftp-server - make sftp-server - copy sftp-server into your chroot and set +s Regards Magnus "sftp-server.patch" 103 lines, 2521 characters --- openssh-3.6.1p2/sftp-server.c.org 2003-08-11 22:07:47.098650000 +0200 +++ openssh-3.6.1p2/sftp-server.c 2003-08-16 16:43:11.884356000 +0200 @@ -24,15 +24,24 @@ #include "includes.h" RCSID("$OpenBSD: sftp-server.c,v 1.41 2003/03/26 04:02:51 deraadt Exp $"); +#define CHROOT #include "buffer.h" #include "bufaux.h" #include "getput.h" #include "log.h" #include "xmalloc.h" - #include "sftp.h" #include "sftp-common.h" +#ifdef CHROOT +#include "uidswap.h" +#include <pwd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> +#include <unistd.h> +#endif /* CHROOT */ + /* helper */ #define get_int64() buffer_get_int64(&iqueue); #define get_int() buffer_get_int(&iqueue); @@ -62,6 +71,51 @@ Attrib attrib; }; +#ifdef CHROOT +static void +chroot_init(void) +{ + gid_t gidset[1]; + struct passwd *pw; + struct stat st; + + /* Sanity checking before chroot */ + if ((pw = getpwuid(getuid())) == NULL) + fatal("getpwuid failed for %u", (u_int)pw->pw_uid ); + + /* Sets passwd pointer to null */ + memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); + endpwent(); + + if (geteuid() != 0) + fatal("must be SUID root to use chroot feature"); + + if ((stat(pw->pw_dir, &st)) == -1) + fatal("cannot stat chroot directory %s: %s", pw->pw_dir, strerror(errno)); + + if (!S_ISDIR(st.st_mode)) + fatal("%s is not a directory: %s", pw->pw_dir, strerror(errno)); + + /* Drop our privileges */ + debug3("chroot user:group %u:%u", (u_int)pw->pw_uid, (u_int)pw->pw_gid); + + /* Change our root directory */ + if (chroot(pw->pw_dir) == -1) + fatal("chroot(\"%s\"): %s", pw->pw_dir, strerror(errno)); + + /* Change dir to prevent chroot break */ + if (chdir("/") == -1) + fatal("chdir(\"/\"): %s", strerror(errno)); + + gidset[0] = pw->pw_gid; + if (setgid(pw->pw_gid) < 0) + fatal("setgid failed for %u", (u_int)pw->pw_gid ); + if (setgroups(1, gidset) < 0) + fatal("setgroups: %.100s", strerror(errno)); + permanently_set_uid(pw); +} +#endif /* CHROOT */ + static int errno_to_portable(int unixerrno) { @@ -1028,15 +1082,17 @@ int in, out, max; ssize_t len, olen, set_size; - /* XXX should use getopt */ +#ifdef DEBUG_SFTP-SERVER + log_init("sftp-server", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0); +#endif + +#ifdef CHROOT + chroot_init(); +#endif __progname = get_progname(av[0]); handle_init(); -#ifdef DEBUG_SFTP_SERVER - log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); -#endif - in = dup(STDIN_FILENO); out = dup(STDOUT_FILENO);