Date: Tue, 17 Oct 2000 15:59:18 -0700 (PDT) From: agifford@infowest.com To: freebsd-gnats-submit@FreeBSD.org Subject: bin/22066: Patch to add feature to FreeBSD's ftpd when used with chroot Message-ID: <20001017225918.519C737B4C5@hub.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 22066
>Category: bin
>Synopsis: Patch to add feature to FreeBSD's ftpd when used with chroot
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Tue Oct 17 16:00:00 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator: Aaron D. Gifford
>Release: FreeBSD-4.1.1-STABLE
>Organization:
>Environment:
FreeBSD my.freebsd.box 4.1.1-STABLE FreeBSD 4.1.1-STABLE #0: Thu Oct 12 11:58:29 MDT 2000 root@my.freebsd.box:/usr/src/sys/compile/LOCAL i386
>Description:
Hello,
When using the ftpd daemon with users who are chrooted (see the ftpd man page, authentication rule #5), if a user's home directory is /users/joe, ftpd behaves exactly as I expect and changes to that directory. However, in certain cases, the following feature would be preferable:
If I use a set-up like this:
/users/joe - directory in which I want user joe to be chrooted
/users/joe/bin - where chroot-accessable binaries are kept
/users/joe/etc - chroot-accesable system stuff (like group) so
that ls and other tools behave normally in the
chrooted environment
/users/joe/web - this is the ONLY subdirectory that user joe
owns (all others are root.wheel) and has write
privileges to - it is where joe can upload
web pages to
With the above setup, it would be nice to be able to automatically
AFTER the chroot to /users/joe do a cwd() to /web so that joe will
begin his FTP session within his writable subdirectory. The
wu-ftpd daemon has this ability by setting a user's home directory to:
/users/joe/./web
By adding a "/./" to the home directory, the wu-ftpd daemon knows where
the chroot portion of the home directory ends and where the cwd()
portion begins. Unfortunatly, wu-ftpd is not an option. FreeBSD's
ftpd is far superior.
The patch below adds this feature to FreeBSD's ftpd daemon. I hope that you seriously consider adding this to to FreeBSD. It is quite handy and I expect that there are many others who would enjoy this added ability.
The only drawback that I can see to adding this feature (and I must mention it to be honest) is in cases where existing installations use a "/./" in home directories for some other purpose where changing the existing chroot behavior of the FTP daemon would require them to restructure. Installations where this would be a problem are very likely extremely rare or nonexistent. So while I mention it, I don't think it would really be a problem.
I've been using these very same modifications to support this new chroot feature on a web server where users are chrooted to their own subdirectories for security purposes. It has been running without problems for months on a system with about 12,000 users.
Sincerely,
Aaron Gifford
<agifford@infowest.com>
P.S. If the patch included doesn't quite come out right (I'm pasting it using a web browser), email me and I'll email a copy to you.
>How-To-Repeat:
This is a feature request.
>Fix:
Patch to ftpd follows:
+++ libexec/ftpd/ftpd.c Tue Oct 3 10:18:24 2000
@@ -250,6 +250,63 @@
static void reapchild __P((int));
static void logxfer __P((char *, long, long));
+/*
+ * Two new subroutines to let ftpd chroot to a home directory in the
+ * format /home/dir/./here/or/there where the chroot will be done
+ * on chroot("/home/dir/") followed by a chdir ("/here/or/there")
+ * (Much like wu-ftpd's similar feature) and do it safely.
+ */
+static char *
+chrootdir(dir)
+ char *dir;
+{
+ static char cdir[MAXPATHLEN+1];
+ int len = 0;
+
+ if (!dir) {
+ cdir[0] = '/';
+ cdir[1] = '\0';
+ return cdir;
+ }
+ while(*dir && len < MAXPATHLEN) {
+ if (*dir == '/' && *(dir+1) == '.' && *(dir+2) == '/') {
+ cdir[len++] = *dir;
+ cdir[len] = '\0';
+ return cdir;
+ }
+ cdir[len++] = *dir++;
+ }
+ cdir[len] = '\0';
+ return cdir;
+}
+
+static char *
+homedir(dir)
+ char *dir;
+{
+ static char hdir[MAXPATHLEN+1];
+ int len = 0;
+
+ if (!dir) {
+ hdir[0] = '/';
+ hdir[1] = '\0';
+ return hdir;
+ }
+ while (*dir && !(*dir == '/' && *(dir+1) == '.' && *(dir+2) == '/'))
+ dir++;
+ if (!*dir) {
+ hdir[0] = '/';
+ hdir[1] = '\0';
+ return hdir;
+ }
+ dir += 2;
+ while (*dir && len < MAXPATHLEN)
+ hdir[len++] = *dir++;
+ hdir[len] = '\0';
+ return hdir;
+}
+/* End of chroot feature subroutine additions */
+
static char *
curdir()
{
@@ -260,7 +317,7 @@
if (path[1] != '\0') /* special case for root dir. */
strcat(path, "/");
/* For guest account, skip / since it's chrooted */
- return (guest ? path+1 : path);
+ return ((dochroot || guest) ? path+1 : path);
}
int
@@ -1285,12 +1342,12 @@
* the old current directory will be accessible as "."
* outside the new root!
*/
- if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
+ if (chroot(chrootdir(pw->pw_dir)) < 0 || chdir(homedir(pw->pw_dir)) < 0) {
reply(550, "Can't set guest privileges.");
goto bad;
}
} else if (dochroot) {
- if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
+ if (chroot(chrootdir(pw->pw_dir)) < 0 || chdir(homedir(pw->pw_dir)) < 0) {
reply(550, "Can't change root.");
goto bad;
}
>Release-Note:
>Audit-Trail:
>Unformatted:
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20001017225918.519C737B4C5>
