chroot sftp-server [PATCH]

mouring at etoh.eviladmin.org mouring at etoh.eviladmin.org
Fri May 25 00:17:46 EST 2001


There are few issues I need to sort out.  As I said.. symlink and
rename commands break under my current patch.  And I need to find a better
way of doing error checking.  I'd like to also include the option to
'jail' someone in a subdirectory off their home directory.  Thus removing
their ability to modify dot files in their home directory.  But that may
require changes to sshd.

I'm sure it will work fine.  Just when I get done I'll need a few other
people to look over the patch to ensure I did not miss any edge cases.

I'll have a more robust patch in a day or two.

- Ben

On Fri, 25 May 2001, Andrew Bartlett wrote:

> 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