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