On Sun, 8 Oct 2006, Bruno Cesar Ribas wrote:
> Hi,
>
> I saw in archive that some people made a patch to sftp-server, and
> that patch sets a root path. I'd like to know if there's an ideia
to
> apply that patch in main tree of openssh?
>
> With the use of SSHFS [wich uses sftp-server], it would be interesting
> to have someting like that, because as we have netboot workstations,
> the access to devices [such as, floppy, cdrom and usb data] are
> becoming to be used by sshfs, but we don't want that users can make an
> sftp tunnell and mount others directories besides those pre-determined
> [i.e /mnt].
Here is my current sftp-server chroot diff for OpenBSD. It should
apply to portable too, but it will be up to you to make a change
that corresponds to the sftp-server/Makefile hunk.
Chroot is enabled using commandline options to sftp-server much
like the new logging options.
I think the patch is safe, but haven't run through the extra code it
exposes with root privileges or fully considered what new attacks it
might enable - so don't apply it unless you are willing to do so.
I don't know when I'll have time to come back to this, but maybe some
lurkers on this mailing list feel like analysing/auditing it.
-d
diff -urp ssh/sftp-server/Makefile ssh-x/sftp-server/Makefile
--- sftp-server/Makefile Tue Jun 13 11:22:55 2006
+++ sftp-server/Makefile Sat Apr 22 09:41:18 2006
@@ -5,7 +5,7 @@
PROG= sftp-server
BINOWN= root
-BINMODE?=555
+BINMODE?=4555
BINDIR= /usr/libexec
MAN= sftp-server.8
diff -urp ssh/sftp-server.8 ssh-x/sftp-server.8
--- sftp-server.8 Tue Jun 13 11:23:10 2006
+++ sftp-server.8 Tue Apr 25 18:16:06 2006
@@ -30,6 +30,7 @@
.Nd SFTP server subsystem
.Sh SYNOPSIS
.Nm sftp-server
+.Op Fl C Ar chroot_path
.Op Fl f Ar log_facility
.Op Fl l Ar log_level
.Sh DESCRIPTION
@@ -54,6 +55,25 @@ for more information.
.Pp
Valid options are:
.Bl -tag -width Ds
+.It Fl C Ar chroot_path
+Requests that
+.Nm
+.Xr chroot 2
+itself to the specified path prior to processing requests from the user.
+The
+.Ar chroot_path
+use the tilde syntax to refer to a user's home directory or one of the
+following
+escape characters:
+.Ql %d
+(local user's home directory) or
+.Ql %g
+(local user's primary group name).
+Note that
+.Xr chroot 2
+support requires
+.Nm
+to be installed setuid root.
.It Fl f Ar log_facility
Specifies the facility code that is used when logging messages from
.Nm .
diff -urp ssh/sftp-server.c ssh-x/sftp-server.c
--- sftp-server.c Tue Jun 13 11:23:42 2006
+++ sftp-server.c Tue Jun 13 11:24:35 2006
@@ -1154,6 +1154,35 @@ process(void)
buffer_consume(&iqueue, msg_len - consumed);
}
+static void
+do_chroot(const char *chroot_path_template)
+{
+ char *cp, *chroot_path;
+ struct group *gr;
+
+ if ((gr = getgrgid(pw->pw_gid)) == NULL)
+ fatal("No group found for gid %lu", (u_long)pw->pw_gid);
+
+ cp = percent_expand(chroot_path_template, "d", pw->pw_dir,
+ "u", pw->pw_name, "g", gr->gr_name, (char
*)NULL);
+ chroot_path = tilde_expand_filename(cp, getuid());
+ xfree(cp);
+
+ logit("chroot to %s", chroot_path);
+
+ /* Ensure the user has rights to access the chroot path first */
+ temporarily_use_uid(pw);
+ if (chdir(chroot_path) == -1)
+ fatal("chdir(\"%s\"): %s", chroot_path, strerror(errno));
+ restore_uid();
+
+ if (chroot(chroot_path) == -1)
+ fatal("chroot(\"%s\"): %s", chroot_path,
strerror(errno));
+ if (chdir("/") == -1)
+ fatal("chdir(\"/\"): %s", strerror(errno));
+ xfree(chroot_path);
+}
+
/* Cleanup handler that logs active handles upon normal exit */
void
cleanup_exit(int i)
@@ -1179,7 +1208,7 @@ main(int argc, char **argv)
int in, out, max, ch, skipargs = 0, log_stderr = 0;
ssize_t len, olen, set_size;
SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
- char *cp;
+ char *cp, *chroot_path = NULL;
extern int optind;
extern char *optarg;
@@ -1192,6 +1221,9 @@ main(int argc, char **argv)
while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che"))
!= -1) {
switch (ch) {
+ case 'C':
+ chroot_path = optarg;
+ break;
case 'c':
/*
* Ignore all arguments if we are invoked as a
@@ -1236,6 +1268,11 @@ main(int argc, char **argv)
logit("session opened for client %s local user %s",
client_addr, pw->pw_name);
+ if (chroot_path != NULL)
+ do_chroot(chroot_path);
+ if (getuid() != geteuid())
+ permanently_set_uid(pw);
+
handle_init();
in = dup(STDIN_FILENO);