chroot sftp-server [PATCH]

Andrew Bartlett abartlet at pcug.org.au
Fri May 25 00:17:16 EST 2001


Is there any way of making this work?  This is the method I much prefer,
and was looking at implementing a while ago.  I'm glad sombodies taken a
stab at it.

I run SFTP specificly becouse it does not require a ROOT deamon (apart
from OpenSSH, which I run already) nor does it require a set-uid
binary.  Hence my interest in this patch.

Andrew Bartlett

mouring at etoh.eviladmin.org wrote:
> 
> Outside the fact that realpath() requires the file aspect of the path to
> exist which breaks 'rename' and 'symlink' =)
> 
> - Ben
> 
> On Wed, 23 May 2001 mouring at etoh.eviladmin.org wrote:
> 
> >
> >
> > 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);
> >
> >

-- 
Andrew Bartlett
abartlet at pcug.org.au



More information about the openssh-unix-dev mailing list