*** crypto/openssh/sftp-server.c.orig	Thu Dec 18 22:58:39 2014
--- crypto/openssh/sftp-server.c	Fri Dec 19 12:40:30 2014
***************
*** 38,43 ****
--- 38,44 ----
  #include <stdio.h>
  #include <string.h>
  #include <pwd.h>
+ #include <grp.h>
  #include <time.h>
  #include <unistd.h>
  #include <stdarg.h>
***************
*** 48,53 ****
--- 49,57 ----
  #include "misc.h"
  #include "match.h"
  #include "uidswap.h"
+ #ifdef SFTPCHROOT
+ #include "pathnames.h"
+ #endif
  
  #include "sftp.h"
  #include "sftp-common.h"
***************
*** 499,504 ****
--- 503,595 ----
  	buffer_consume(m, mlen);
  }
  
+ /*
+  * Check if a user is in the file "fname",
+  * return a pointer to a malloc'd string with the rest
+  * of the matching line in "residue" if not NULL.
+  */
+ #ifdef SFTPCHROOT
+ static int
+ checkuser(char *fname, char *name, gid_t pw_gid, char **residue)
+ {
+  FILE *fd;
+  int found = 0;
+  size_t len;
+  char *line, *mp, *p;
+ 
+  if ((fd = fopen(fname, "r")) != NULL) {
+     while (!found && (line = fgetln(fd, &len)) != NULL) {
+         /* skip comments */
+         if (line[0] == '#')
+            continue;
+         if (line[len - 1] == '\n') {
+            line[len - 1] = '\0';
+            mp = NULL;
+         } else {
+            if ((mp = malloc(len + 1)) == NULL)
+               fatal("Ran out of memory.");
+            memcpy(mp, line, len);
+            mp[len] = '\0';
+            line = mp;
+         }
+         /* avoid possible leading and trailing whitespace */
+         p = strtok(line, " \t");
+         /* skip empty lines */
+         if (p == NULL)
+            goto nextline;
+         /*
+          * if first chr is '@', check group membership
+          */
+         if (p[0] == '@') {
+            int i = 0;
+            struct group *grp;
+ 
+            if (p[1] == '\0') /* single @ matches anyone */
+               found = 1;
+            else {
+               if ((grp = getgrnam(p+1)) == NULL)
+                  goto nextline;
+               /*
+                * Check user's default group
+                */
+               if (grp->gr_gid == pw_gid)
+                  found = 1;
+               /*
+                * Check supplementary groups
+                */
+               while (!found && grp->gr_mem[i])
+                  found = strcmp(name,
+                     grp->gr_mem[i++])
+                     == 0;
+            }
+         }
+         /*
+          * Otherwise, just check for username match
+          */
+         else
+            found = strcmp(p, name) == 0;
+         /*
+          * Save the rest of line to "residue" if matched
+          */
+         if (found && residue) {
+            if ((p = strtok(NULL, "")) != NULL)
+               p += strspn(p, " \t");
+            if (p && *p) {
+               if ((*residue = strdup(p)) == NULL)
+                  fatal("Ran out of memory.");
+            } else
+               *residue = NULL;
+         }
+  nextline:
+         if (mp)
+            free(mp);
+      }
+      (void) fclose(fd);
+   }
+   return (found);
+ }
+ #endif /* SFTPCHROOT */
+ 
  static const char *
  status_to_message(u_int32_t status)
  {
***************
*** 1445,1450 ****
--- 1536,1548 ----
  	SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
  	char *cp, *homedir = NULL, buf[4*4096];
  	long mask;
+ #ifdef SFTPCHROOT
+ 	int dochroot;
+ 	char *chrootdir, *residue;
+ 	uid_t uid;
+ 	struct passwd *pw;
+ #endif
+ 
  
  	extern char *optarg;
  	extern char *__progname;
***************
*** 1558,1569 ****
--- 1656,1744 ----
  	rset = (fd_set *)xmalloc(set_size);
  	wset = (fd_set *)xmalloc(set_size);
  
+ #ifndef	SFTPCHROOT
  	if (homedir != NULL) {
  		if (chdir(homedir) != 0) {
  			error("chdir to \"%s\" failed: %s", homedir,
  			    strerror(errno));
  		}
  	}
+ #else
+ 	uid = getuid();
+ 	if ((pw = getpwuid(uid)) == NULL)
+ 		fatal("Cannot get user info");
+ 	residue = NULL;
+ 	dochroot =
+ 		checkuser(_PATH_SFTPCHROOT_FILE, pw->pw_name, pw->pw_gid, &residue);
+ 	chrootdir = NULL;
+ 	homedir = NULL;
+ 	/*
+ 	 * For a chrooted local user,
+ 	 * a) see whether ftpchroot(5) specifies a chroot directory,
+ 	 * b) extract the directory pathname from the line,
+ 	 * c) expand it to the absolute pathname if necessary.
+ 	 */
+ 	if (dochroot && residue &&
+ 	    (chrootdir = strtok(residue, " \t")) != NULL) {
+ 		if (chrootdir[0] != '/')
+ 			asprintf(&chrootdir, "%s/%s", pw->pw_dir, chrootdir);
+ 		else
+ 			chrootdir = strdup(chrootdir); /* make it permanent */
+ 		if (chrootdir == NULL)
+ 			fatal("Ran out of memory.");
+ 	}
+ 	if (dochroot) {
+ 		/*
+ 		 * If no chroot directory set yet, use the login directory.
+ 		 * Copy it so it can be modified while pw->pw_dir stays intact.
+ 		 */
+ 		if (chrootdir == NULL &&
+ 		    (chrootdir = strdup(pw->pw_dir)) == NULL)
+ 			fatal("Ran out of memory.");
+ 		/*
+ 		 * Check for the "/chroot/./home" syntax,
+ 		 * separate the chroot and home directory pathnames.
+ 		 */
+ 		if ((homedir = strstr(chrootdir, "/./")) != NULL) {
+ 			*(homedir++) = '\0';    /* wipe '/' */
+ 			homedir++;	      /* skip '.' */
+ 		} else {
+ 			/*
+ 			 * We MUST do a chdir() after the chroot. Otherwise
+ 			 * the old current directory will be accessible as "."
+ 			 * outside the new root!
+ 			 */
+ 			homedir = "/";
+ 		}
+ 		/*
+ 		 * Finally, do chroot()
+ 		 */
+ 		if (chroot(chrootdir) < 0) {
+ 			fatal("Can't change root.");
+ 		}
+ 	} else  /* real user w/o chroot */
+ 		homedir = pw->pw_dir;
+ 	/*
+ 	 * Set euid *before* doing chdir() so
+ 	 * a) the user won't be carried to a directory that he couldn't reach
+ 	 *    on his own due to no permission to upper path components,
+ 	 * b) NFS mounted homedirs w/restrictive permissions will be accessible
+ 	 *    (uid 0 has no root power over NFS if not mapped explicitly.)
+ 	 */
+ 	if (seteuid(pw->pw_uid) < 0) {
+ 		fatal("Can't set uid.");
+ 	}
+ 	if (chdir(homedir) < 0) {
+ 		if (dochroot) {
+ 			fatal("Can't change to base directory.");
+ 		} else {
+ 			if (chdir("/") < 0) {
+ 				fatal("Root is inaccessible.");
+ 			}
+ 			fatal("No directory! Logging in with home=/.");
+ 		}
+ 	}
+ #endif	/* SFTPCHROOT */
  
  	for (;;) {
  		memset(rset, 0, set_size);
*** secure/libexec/sftp-server/Makefile.orig	Thu Dec 18 22:59:09 2014
--- secure/libexec/sftp-server/Makefile	Fri Dec 19 11:54:23 2014
***************
*** 19,24 ****
--- 19,30 ----
  DPADD+=	${LIBCRYPT} ${LIBCRYPTO} ${LIBZ}
  LDADD+=	-lcrypt -lcrypto -lz
  
+ .if defined(SFTP_CHROOT)
+ CFLAGS+=-DSFTPCHROOT
+ BINOWN= root
+ BINMODE=4555
+ .endif
+ 
  .include <bsd.prog.mk>
  
  .PATH:	${SSHDIR}
*** crypto/openssh/pathnames.h.orig	Thu Dec 18 22:58:37 2014
--- crypto/openssh/pathnames.h	Fri Dec 19 11:54:30 2014
***************
*** 46,51 ****
--- 46,53 ----
  /* Backwards compatibility */
  #define _PATH_DH_PRIMES			SSHDIR "/primes"
  
+ #define _PATH_SFTPCHROOT_FILE		SSHDIR "/sftpchroot"
+ 
  #ifndef _PATH_SSH_PROGRAM
  #define _PATH_SSH_PROGRAM		"/usr/bin/ssh"
  #endif
