chroot sftp-server [PATCH]
mouring at etoh.eviladmin.org
mouring at etoh.eviladmin.org
Thu May 24 13:53:21 EST 2001
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);
>
>
More information about the openssh-unix-dev
mailing list