Index: scp.c --- scp.c.orig 2021-03-02 11:31:47.000000000 +0100 +++ scp.c 2021-03-03 08:26:22.056945000 +0100 @@ -159,6 +159,11 @@ /* This is the program to execute for the secured connection. ("ssh" or -S) */ char *ssh_program = _PATH_SSH_PROGRAM; +/* The directory to perform a chroot(2) to before operation (intended for server-side only) */ +#ifdef USE_CHROOT +char *chrootdir = NULL; +#endif + /* This is used to store the pid of ssh_program */ pid_t do_cmd_pid = -1; @@ -432,7 +437,11 @@ fflag = Tflag = tflag = 0; while ((ch = getopt(argc, argv, +#ifdef USE_CHROOT + "12346ABCTdfpqrtvF:J:P:S:c:i:l:o:R:")) != -1) { +#else "12346ABCTdfpqrtvF:J:P:S:c:i:l:o:")) != -1) { +#endif switch (ch) { /* User-visible flags. */ case '1': @@ -516,6 +525,11 @@ case 'T': Tflag = 1; break; +#ifdef USE_CHROOT + case 'R': + chrootdir = xstrdup(optarg); + break; +#endif default: usage(); } @@ -545,6 +559,19 @@ remin = STDIN_FILENO; remout = STDOUT_FILENO; +#ifdef USE_CHROOT + if (chrootdir != NULL) { + if (geteuid() != 0) + fatal("chroot(2) not possible: euid %ld != 0", (long)geteuid()); + if (chroot(chrootdir) == -1) + fatal("couldn't chroot(2) to directory \"%s\": %s", chrootdir, strerror(errno)); + if (setuid(getuid()) == -1) + fatal("couldn't drop privileges with setuid(2): %s", strerror(errno)); + if (chdir("/") == -1) + fatal("couldn't change to root directory: %s", strerror(errno)); + } +#endif + if (fflag) { /* Follow "protocol", send data. */ (void) response(); Index: session.c --- session.c.orig 2021-03-02 11:31:47.000000000 +0100 +++ session.c 2021-03-03 08:25:31.704168000 +0100 @@ -1402,6 +1402,25 @@ options.chroot_directory = NULL; in_chroot = 1; } +# ifdef USE_CHROOT + { + char *user_dir; + char *new_root; + user_dir = xstrdup(pw->pw_dir); + 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; + safely_chroot(user_dir, pw->pw_uid); + pw->pw_dir = new_root; + break; + } + new_root += 2; + } + } +# endif /* USE_CHROOT */ #ifdef HAVE_LOGIN_CAP if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) { Index: sftp-server.c --- sftp-server.c.orig 2021-03-02 11:31:47.000000000 +0100 +++ sftp-server.c 2021-03-03 08:25:31.704450000 +0100 @@ -1717,6 +1717,38 @@ logit("session opened for local user %s from [%s]", pw->pw_name, client_addr); +#ifdef USE_CHROOT +{ + char *user_dir; + char *new_root; + user_dir = getenv("HOME"); + if (user_dir == NULL) + fatal("HOME variable not found 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; + if (geteuid() == 0) { + /* chroot to subdir and adjust HOME for remaining path */ + if (chroot(user_dir) == -1) + fatal("Couldn't chroot to user directory \"%s\": %s", user_dir, strerror(errno)); + if (setuid(getuid()) == -1) + fatal("Couldn't drop privileges: %s", strerror(errno)); + setenv("HOME", new_root, 1); + } + else { + /* ignore chroot request and adjust HOME for preceeding path */ + setenv("HOME", user_dir, 1); + } + break; + } + new_root += 2; + } +} +#endif /* USE_CHROOT */ + in = STDIN_FILENO; out = STDOUT_FILENO;