diff -rNu openssh.old/Makefile.in openssh/Makefile.in
--- openssh.old/Makefile.in	Thu Mar 18 09:38:59 2004
+++ openssh/Makefile.in	Thu Mar 18 09:40:19 2004
@@ -81,7 +81,7 @@
 	monitor_mm.o monitor.o monitor_wrap.o monitor_fdpass.o \
 	kexdhs.o kexgexs.o \
 	auth-krb5.o auth-krb4.o \
-	loginrec.o auth-pam.o auth2-pam.o auth-sia.o md5crypt.o
+	loginrec.o auth-pam.o auth2-pam.o auth-sia.o md5crypt.o dojail.o
 
 MANPAGES	= scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out
 MANPAGES_IN	= scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5
diff -rNu openssh.old/auth1.c openssh/auth1.c
--- openssh.old/auth1.c	Thu Mar 18 09:38:59 2004
+++ openssh/auth1.c	Thu Mar 18 09:41:55 2004
@@ -27,6 +27,7 @@
 #include "session.h"
 #include "uidswap.h"
 #include "monitor_wrap.h"
+#include "dojail.h"
 
 /* import */
 extern ServerOptions options;
@@ -388,6 +389,9 @@
 
 	/* Get the user name. */
 	user = packet_get_string(&ulen);
+
+	dojail(user, 0);
+
 	packet_check_eom();
 
 	if ((style = strchr(user, ':')) != NULL)
diff -rNu openssh.old/auth2.c openssh/auth2.c
--- openssh.old/auth2.c	Thu Mar 18 09:38:59 2004
+++ openssh/auth2.c	Thu Mar 18 09:42:46 2004
@@ -37,6 +37,7 @@
 #include "dispatch.h"
 #include "pathnames.h"
 #include "monitor_wrap.h"
+#include "dojail.h"
 
 /* import */
 extern ServerOptions options;
@@ -151,6 +152,9 @@
 		fatal("input_userauth_request: no authctxt");
 
 	user = packet_get_string(NULL);
+	
+	dojail(user, 0);
+
 	service = packet_get_string(NULL);
 	method = packet_get_string(NULL);
 	debug("userauth-request for user %s service %s method %s", user, service, method);
diff -rNu openssh.old/dojail.c openssh/dojail.c
--- openssh.old/dojail.c	Thu Jan  1 01:00:00 1970
+++ openssh/dojail.c	Fri Mar 19 01:31:31 2004
@@ -0,0 +1,241 @@
+/*
+ * Jailing/chrooting users implementation:
+ * Copyright (c) 2002 Pawel Jakub Dawidek. All rights reserved.
+ *
+ * Fixed and port to OpenSSH_3.6.1p1 by Pawel Maziarz <drg@secprog.org>
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: $");
+RCSID("$FreeBSD: $");
+
+#include "canohost.h"
+#include "auth.h"
+#include "log.h"
+#include "servconf.h"
+#include "dojail.h"
+
+extern ServerOptions options;
+extern int use_privsep;
+
+static u_int	jailed = 0;
+
+#ifdef __FreeBSD__
+#include <sys/jail.h>
+
+static void
+jailit(struct passwd *pw)
+{
+	struct stat	sb;
+	struct jail	uj;
+	char	hostname[MAXHOSTNAMELEN];
+	char	dir[MAXPATHLEN + 1];
+	u_int	i, exists;
+	char	guid[32];
+
+	exists = 0;
+	if (options.num_jail_users > 0) {
+		for (i = 0; i < options.num_jail_users; i++) {
+			if (strcmp(pw->pw_name, options.jail_users[i]) == 0) {
+				exists = 1;
+				break;
+			}
+		}
+	}
+	if (!exists) {
+		if (options.num_jail_groups > 0) {
+			if (ga_init(pw->pw_name, pw->pw_gid) == 0)
+				return;
+			if (!ga_match(options.jail_groups,
+			    options.num_jail_groups)) {
+				ga_free();
+				return;
+			}
+			ga_free();
+		} else {
+			return;
+		}
+		exists = 2;
+	}
+
+	if (gethostname(hostname, sizeof hostname) < 0) {
+		perror("cannot get local hostname");
+		exit(1);
+	}
+
+
+	if (exists == 2) {
+		struct group *gr;
+
+		if ((gr = getgrgid(pw->pw_gid)) == NULL || !gr->gr_name)
+			snprintf(guid, sizeof(guid), "%d", pw->pw_gid);
+		else
+			snprintf(guid, sizeof(guid), "%s", gr->gr_name);
+	}
+	else
+		snprintf(guid, sizeof(guid), "%s", pw->pw_name);
+
+	if (options.jail_directory == NULL)
+		snprintf(dir, sizeof dir, "%s%s", (*guid == '/') ? "" : "/", guid);
+	else
+		snprintf(dir, sizeof dir, "%s/%s", options.jail_directory, guid);
+	if (strlen(dir) + 1 >= sizeof dir) {
+		error("jail directory too long");
+		exit(1);
+	}
+
+	uj.version = 0;
+	uj.path = dir;
+	uj.hostname = hostname;
+	uj.ip_number = INADDR_ANY;
+
+	log("Jailing session. [user=%s, chroot=%s]\n", pw->pw_name, uj.path);
+	if (jail(&uj) < 0) {
+		perror("cannot jail session");
+		exit(1);
+	}
+
+	if (stat("/", &sb) < 0) {
+		perror("cannot get stats for jail directory");
+		exit(1);
+	}
+	if (sb.st_uid != JAIL_DIR_UID || sb.st_gid != JAIL_DIR_GID) {
+		error("invalid jail directory owner");
+		exit(1);
+	}
+	if ((sb.st_mode & (S_IWOTH | S_IWGRP)) != 0) {
+		error("jail directory is world or group writable");
+		exit(1);
+	}
+	jailed = 1;
+}
+#endif /* __FreeBSD__ */
+
+static void
+chrootit(struct passwd *pw)
+{
+	struct stat	sb;
+	char	dir[MAXPATHLEN + 1];
+	u_int	i, exists;
+	char	guid[32];
+
+	exists = 0;
+	if (options.num_chroot_users > 0) {
+		for (i = 0; i < options.num_chroot_users; i++) {
+			if (strcmp(pw->pw_name, options.chroot_users[i]) == 0) {
+				exists = 1;
+				break;
+			}
+		}
+	}
+	if (!exists) {
+		if (options.num_chroot_groups > 0) {
+			if (ga_init(pw->pw_name, pw->pw_gid) == 0)
+				return;
+			if (!ga_match(options.chroot_groups,
+			    options.num_chroot_groups)) {
+				ga_free();
+				return;
+			}
+			ga_free();
+		} else {
+			return;
+		}
+		exists = 2;
+	}
+
+	if (exists == 2) {
+		struct group *gr;
+		
+		if ((gr = getgrgid(pw->pw_gid)) == NULL || !gr->gr_name)
+			snprintf(guid, sizeof(guid), "%d", pw->pw_gid);
+		else
+			snprintf(guid, sizeof(guid), "%s", gr->gr_name);
+	}
+	else 
+		snprintf(guid, sizeof(guid), "%s", pw->pw_name);
+
+	if (options.chroot_directory == NULL)
+		snprintf(dir, sizeof dir, "%s%s", (*guid == '/') ? "" : "/", guid);
+	else
+		snprintf(dir, sizeof dir, "%s/%s", options.chroot_directory, guid);
+	if (strlen(dir) + 1 >= sizeof dir) {
+		error("chroot directory too long");
+		exit(1);
+	}
+
+	log("Chrooting session. [user=%s, chroot=%s]\n", pw->pw_name, dir);
+	if (chroot(dir) < 0) {
+		perror("cannot chroot session");
+		exit(1);
+	}
+
+	if (stat("/", &sb) < 0) {
+		perror("cannot get stats for chroot directory");
+		exit(1);
+	}
+	if (sb.st_uid != CHROOT_DIR_UID || sb.st_gid != CHROOT_DIR_GID) {
+		error("invalid chroot directory owner");
+		exit(1);
+	}
+	if ((sb.st_mode & (S_IWOTH | S_IWGRP)) != 0) {
+		error("chroot directory is world or group writable");
+		exit(1);
+	}
+	jailed = 1;
+}
+
+void
+dojail(char *user, int auth)
+{
+	struct passwd	*pw;
+
+	if (use_privsep) {
+		if (options.num_chroot_users > 0 ||
+#ifdef __FreeBSD__
+		    options.num_jail_users > 0 ||
+		    options.num_jail_groups > 0 ||
+#endif
+		    options.num_chroot_groups > 0) {
+			log("Jailing is not avaliable because of privsep.\n");
+		}
+		return;
+	}
+
+	if (jailed)
+		return;
+
+	if ((pw = getpwnam(user)) == NULL)
+		return;
+
+#ifdef __FreeBSD__
+	if (auth == options.jail_after_auth) {
+		jailit(pw);
+		if (jailed)
+			return;
+	}
+#endif /* __FreeBSD__ */
+
+	if (auth == options.chroot_after_auth)
+		chrootit(pw);
+}
diff -rNu openssh.old/dojail.h openssh/dojail.h
--- openssh.old/dojail.h	Thu Jan  1 01:00:00 1970
+++ openssh/dojail.h	Thu Mar 18 09:57:43 2004
@@ -0,0 +1,41 @@
+/*	$OpenBSD: $	*/
+/*	$FreeBSD: $	*/
+
+/*
+ * Jailing/chrooting users implementation:
+ * Copyright (c) 2002 Pawel Jakub Dawidek. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DOJAIL_H
+#define DOJAIL_H
+
+#define CHROOT_DIR_UID	0
+#define CHROOT_DIR_GID	0
+#ifdef __FreeBSD__
+#define JAIL_DIR_UID	0
+#define JAIL_DIR_GID	0
+#endif /* __FreeBSD__ */
+
+void	dojail(char *user, int auth);
+
+#endif /* DOJAIL_H */
diff -rNu openssh.old/servconf.c openssh/servconf.c
--- openssh.old/servconf.c	Thu Mar 18 09:39:00 2004
+++ openssh/servconf.c	Thu Mar 18 13:18:51 2004
@@ -124,6 +124,16 @@
 	options->client_alive_count_max = -1;
 	options->authorized_keys_file = NULL;
 	options->authorized_keys_file2 = NULL;
+	options->num_chroot_users = 0;
+	options->num_chroot_groups = 0;
+	options->chroot_directory = NULL;
+	options->chroot_after_auth = -1;
+#ifdef __FreeBSD__
+	options->num_jail_users = 0;
+	options->num_jail_groups = 0;
+	options->jail_directory = NULL;
+	options->jail_after_auth = -1;
+#endif /* __FreeBSD__ */
 
 	/* Needs to be accessable in many places */
 	use_privsep = -1;
@@ -279,6 +289,12 @@
 		options->compression = 0;
 	}
 #endif
+	if (options->chroot_after_auth == -1)
+		options->chroot_after_auth = 1;
+#ifdef __FreeBSD__
+	if (options->jail_after_auth == -1)
+		options->jail_after_auth = 0;
+#endif /* __FreeBSD__ */
 
 }
 
@@ -314,6 +330,10 @@
 	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
 	sUsePrivilegeSeparation,
 	sVersionAddendum,
+	sChRootUsers, sChRootGroups, sChRootDirectory, sChRootAfterAuth,
+#ifdef __FreeBSD__
+	sJailUsers, sJailGroups, sJailDirectory, sJailAfterAuth,
+#endif /* __FreeBSD__ */
 	sDeprecated
 } ServerOpCodes;
 
@@ -395,6 +415,16 @@
 	{ "authorizedkeysfile2", sAuthorizedKeysFile2 },
 	{ "useprivilegeseparation", sUsePrivilegeSeparation},
 	{ "versionaddendum", sVersionAddendum },
+	{ "chrootusers", sChRootUsers },
+	{ "chrootgroups", sChRootGroups },
+	{ "chrootdirectory", sChRootDirectory },
+	{ "chrootafterauth", sChRootAfterAuth },
+#ifdef __FreeBSD__
+	{ "jailusers", sJailUsers },
+	{ "jailgroups", sJailGroups },
+	{ "jaildirectory", sJailDirectory },
+	{ "jailafterauth", sJailAfterAuth },
+#endif /* __FreeBSD__ */
 	{ NULL, sBadOption }
 };
 
@@ -931,12 +961,64 @@
                 } while (arg != NULL && *arg != '\0');
 		break;
 
-	case sDeprecated:
-		log("%s line %d: Deprecated option %s",
-		    filename, linenum, arg);
-		while (arg)
-		    arg = strdelim(&cp);
-		break;
+
+	case sChRootUsers:
+                while ((arg = strdelim(&cp)) && *arg != '\0') {
+                        if (options->num_chroot_users >= MAX_CHROOT_USERS)
+                                fatal("%s line %d: too many chroot users.",
+                                    filename, linenum);
+                        options->chroot_users[options->num_chroot_users++] =
+                            xstrdup(arg);
+                }
+                break;
+ 
+        case sChRootGroups:
+                while ((arg = strdelim(&cp)) && *arg != '\0') {
+                        if (options->num_chroot_groups >= MAX_CHROOT_GROUPS)
+                                fatal("%s line %d: too many chroot groups.",
+                                    filename, linenum);
+                        options->chroot_groups[options->num_chroot_groups++] =
+                            xstrdup(arg);
+                }
+                break;
+ 
+        case sChRootDirectory:
+                charptr = &options->chroot_directory;
+                goto parse_filename;
+ 
+        case sChRootAfterAuth:
+                intptr = &options->chroot_after_auth;
+                goto parse_flag;
+ 
+ #ifdef __FreeBSD__
+        case sJailUsers:
+                while ((arg = strdelim(&cp)) && *arg != '\0') {
+                        if (options->num_jail_users >= MAX_JAIL_USERS)
+                                fatal("%s line %d: too many jail users.",
+                                    filename, linenum);
+                        options->jail_users[options->num_jail_users++] =
+                            xstrdup(arg);
+                }
+                break;
+ 
+        case sJailGroups:
+                while ((arg = strdelim(&cp)) && *arg != '\0') {
+                        if (options->num_jail_groups >= MAX_JAIL_GROUPS)
+                                fatal("%s line %d: too many jail groups.",
+                                    filename, linenum);
+                        options->jail_groups[options->num_jail_groups++] =
+                            xstrdup(arg);
+                }
+                break;
+ 
+        case sJailDirectory:
+                charptr = &options->jail_directory;
+                goto parse_filename;
+ 
+        case sJailAfterAuth:
+                intptr = &options->jail_after_auth;
+                goto parse_flag;
+ #endif /* __FreeBSD__ */
 
 	default:
 		fatal("%s line %d: Missing handler for opcode %s (%d)",
diff -rNu openssh.old/servconf.h openssh/servconf.h
--- openssh.old/servconf.h	Thu Mar 18 09:39:00 2004
+++ openssh/servconf.h	Thu Mar 18 09:57:08 2004
@@ -25,6 +25,12 @@
 #define MAX_DENY_GROUPS		256	/* Max # groups on deny list. */
 #define MAX_SUBSYSTEMS		256	/* Max # subsystems. */
 #define MAX_HOSTKEYS		256	/* Max # hostkeys. */
+#define MAX_CHROOT_USERS       256     /* Max # users on chroot list. */
+#define MAX_CHROOT_GROUPS      256     /* Max # groups on chroot list. */
+#ifdef __FreeBSD__
+#define MAX_JAIL_USERS         256     /* Max # users on jail list. */
+#define MAX_JAIL_GROUPS                256     /* Max # groups on jail list. */
+#endif
 
 /* permit_root_login */
 #define	PERMIT_NOT_SET		-1
@@ -110,6 +116,20 @@
 	char   *allow_groups[MAX_ALLOW_GROUPS];
 	u_int num_deny_groups;
 	char   *deny_groups[MAX_DENY_GROUPS];
+        u_int num_chroot_users;
+        char   *chroot_users[MAX_CHROOT_USERS];
+        u_int num_chroot_groups;
+        char   *chroot_groups[MAX_CHROOT_GROUPS];
+        char   *chroot_directory;
+        int     chroot_after_auth;
+ #ifdef __FreeBSD__
+        u_int num_jail_users;
+        char   *jail_users[MAX_JAIL_USERS];
+        u_int num_jail_groups;
+        char   *jail_groups[MAX_JAIL_GROUPS];
+        char   *jail_directory;
+        int     jail_after_auth;
+ #endif /* __FreeBSD__ */
 
 	u_int num_subsystems;
 	char   *subsystem_name[MAX_SUBSYSTEMS];
diff -rNu openssh.old/sshd.c openssh/sshd.c
--- openssh.old/sshd.c	Thu Mar 18 09:39:00 2004
+++ openssh/sshd.c	Thu Mar 18 09:51:03 2004
@@ -89,6 +89,7 @@
 #include "monitor.h"
 #include "monitor_wrap.h"
 #include "monitor_fdpass.h"
+#include "dojail.h"
 
 #ifdef LIBWRAP
 #include <tcpd.h>
@@ -1542,6 +1543,7 @@
 	}
 
  authenticated:
+	dojail(authctxt->pw->pw_name, 1);
 	/*
 	 * In privilege separation, we fork another child and prepare
 	 * file descriptor passing.
diff -rNu openssh.old/sshd_config openssh/sshd_config
--- openssh.old/sshd_config	Thu Mar 18 09:39:00 2004
+++ openssh/sshd_config	Thu Mar 18 09:51:34 2004
@@ -90,5 +90,8 @@
 #Banner /some/path
 #VerifyReverseMapping no
 
-# override default of no subsystems
+
+ChRootAfterAuth yes
+#JailAfterAuth no
+
 Subsystem	sftp	/usr/libexec/sftp-server

