| Summary: | Patch to add feature to FreeBSD's ftpd when used with chroot | ||
|---|---|---|---|
| Product: | Base System | Reporter: | agifford |
| Component: | bin | Assignee: | freebsd-bugs (Nobody) <bugs> |
| Status: | Closed FIXED | ||
| Severity: | Affects Only Me | ||
| Priority: | Normal | ||
| Version: | 4.1.1-STABLE | ||
| Hardware: | Any | ||
| OS: | Any | ||
This should probably be closed in preference to bin/23944. State Changed From-To: open->closed duplicate of 23944; thanks dhagan@colltech.com |
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. 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; } How-To-Repeat: This is a feature request.