sftp-server (secure) chroot patch?
Magnus F
magnus at mandarin.nu
Sun Aug 17 01:45:10 EST 2003
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);
More information about the openssh-unix-dev
mailing list