chroot sftp-server [PATCH]

mouring at etoh.eviladmin.org mouring at etoh.eviladmin.org
Thu May 24 11:01:24 EST 2001



On 23 May 2001, Patrick Higgins wrote:

> I'm working on setting up a semi-trusted sftp service, and to get it
> working, I need chroot capability.
>
Actually I was looking at it from a different point of view.

Instead of requiring setuid sftp-sever and the use of chroot().  Carefully
crafted realpath() usage and strncmp() should do the same thing.

This is a VERY VERY limited test.  (As in.. compiles.. and looks like it
works.=)

I know it can be cleaned up.. but it's where I left off in my testing.

Markus, is there anything else I should worry about using this method?

- Ben


--- ../cvs/OpenSSH/src/usr.bin/ssh/sftp-server.c	Thu Apr  5 05:42:53 2001
+++ sftp-server.c	Wed May 23 19:54:06 2001
@@ -357,6 +357,33 @@

 /* parse incoming */

+char *jailpath;
+
+char*
+getpath(u_int32_t id)
+{
+	char resolvedpath[MAXPATHLEN];
+	char *path;
+
+	path = get_string(NULL);
+
+        if (realpath(path, resolvedpath) == NULL) {
+                send_status(id, errno_to_portable(errno));
+		xfree(path);
+		return(NULL);
+        }
+        xfree(path);
+
+	if (jailpath) {
+		if (strncmp(resolvedpath, jailpath, strlen(jailpath))) {
+			send_status(id,SSH2_FX_PERMISSION_DENIED);
+			return(NULL);
+		}
+	}
+
+	return(xstrdup(resolvedpath));
+}
+
 void
 process_init(void)
 {
@@ -380,7 +407,10 @@
 	int handle, fd, flags, mode, status = SSH2_FX_FAILURE;

 	id = get_int();
-	name = get_string(NULL);
+	name = getpath(id);
+	if (name == NULL)
+		return;
+
 	pflags = get_int();		/* portable flags */
 	a = get_attrib();
 	flags = flags_from_portable(pflags);
@@ -505,7 +535,10 @@
 	int ret, status = SSH2_FX_FAILURE;

 	id = get_int();
-	name = get_string(NULL);
+	name = getpath(id);
+        if (name == NULL)
+                return;
+
 	TRACE("%sstat id %d name %s", do_lstat ? "l" : "", id, name);
 	ret = do_lstat ? lstat(name, &st) : stat(name, &st);
 	if (ret < 0) {
@@ -580,7 +613,10 @@
 	int status = SSH2_FX_OK;

 	id = get_int();
-	name = get_string(NULL);
+	name = getpath(id);
+        if (name == NULL)
+                return;
+
 	a = get_attrib();
 	TRACE("setstat id %d name %s", id, name);
 	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
@@ -646,7 +682,10 @@
 	u_int32_t id;

 	id = get_int();
-	path = get_string(NULL);
+	path = getpath(id);
+        if (path == NULL)
+                return;
+
 	TRACE("opendir id %d path %s", id, path);
 	dirp = opendir(path);
 	if (dirp == NULL) {
@@ -768,7 +807,10 @@
 	int ret;

 	id = get_int();
-	name = get_string(NULL);
+	name = getpath(id);
+        if (name == NULL)
+                return;
+
 	TRACE("remove id %d name %s", id, name);
 	ret = unlink(name);
 	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
@@ -785,7 +827,10 @@
 	int ret, mode, status = SSH2_FX_FAILURE;

 	id = get_int();
-	name = get_string(NULL);
+	name = getpath(id);
+        if (name == NULL)
+                return;
+
 	a = get_attrib();
 	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
 	    a->perm & 0777 : 0777;
@@ -804,7 +849,10 @@
 	int ret, status;

 	id = get_int();
-	name = get_string(NULL);
+	name = getpath(id);
+        if (name == NULL)
+                return;
+
 	TRACE("rmdir id %d name %s", id, name);
 	ret = rmdir(name);
 	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
@@ -820,7 +868,10 @@
 	char *path;

 	id = get_int();
-	path = get_string(NULL);
+	path = getpath(id);
+        if (path == NULL)
+                return;
+
 	if (path[0] == '\0') {
 		xfree(path);
 		path = xstrdup(".");
@@ -846,8 +897,14 @@
 	int ret, status = SSH2_FX_FAILURE;

 	id = get_int();
-	oldpath = get_string(NULL);
-	newpath = get_string(NULL);
+	oldpath = getpath(id);
+        if (oldpath == NULL)
+                return;
+
+	newpath = getpath(id);
+        if (newpath == NULL)
+                return;
+
 	TRACE("rename id %d old %s new %s", id, oldpath, newpath);
 	/* fail if 'newpath' exists */
 	if (stat(newpath, &st) == -1) {
@@ -867,7 +924,10 @@
 	char *path;

 	id = get_int();
-	path = get_string(NULL);
+	path = getpath(id);
+        if (path == NULL)
+                return;
+
 	TRACE("readlink id %d path %s", id, path);
 	if (readlink(path, link, sizeof(link) - 1) == -1)
 		send_status(id, errno_to_portable(errno));
@@ -891,8 +951,14 @@
 	int ret, status = SSH2_FX_FAILURE;

 	id = get_int();
-	oldpath = get_string(NULL);
-	newpath = get_string(NULL);
+	oldpath = getpath(id);
+        if (oldpath == NULL)
+                return;
+
+	newpath = getpath(id);
+        if (newpath == NULL)
+                return;
+
 	TRACE("symlink id %d old %s new %s", id, oldpath, newpath);
 	/* fail if 'newpath' exists */
 	if (stat(newpath, &st) == -1) {
@@ -1004,6 +1070,32 @@
 	}
 }

+char*
+jail_init(void)
+{
+	char *user_dir, *new_root;
+
+	user_dir = getenv("HOME");
+	if (!user_dir)
+		fatal("HOME isn't in environment");
+
+	new_root = user_dir + 1;
+
+	while ((new_root = strchr(new_root, '.')) != NULL) {
+		new_root--;
+		if (strncmp(new_root, "/./", 3) == 0) {
+			*new_root = '\0';
+			new_root += 2;
+
+			return(xstrdup(user_dir));
+			/*setenv("HOME", new_root, 1);*/
+			break;
+		}
+		new_root += 2;
+	}
+	return NULL;
+}
+
 int
 main(int ac, char **av)
 {
@@ -1018,6 +1110,8 @@
 #ifdef DEBUG_SFTP_SERVER
 	log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
 #endif
+
+	jailpath = jail_init();

 	in = dup(STDIN_FILENO);
 	out = dup(STDOUT_FILENO);




More information about the openssh-unix-dev mailing list