Date: Thu, 4 Jan 2001 11:05:58 -0500 (EST) From: Daniel Hagan <dhagan@colltech.com> To: freebsd-audit@freebsd.org Cc: freebsd-gnats-submit@freebsd.org, fschapachnik@vianetworks.com.ar, greid@dogma.freebsd-uk.eu.org Subject: Re: bin/23944: Proposed modification to ftpd Message-ID: <200101041605.f04G5wM74909@athena.cs.vt.edu>
next in thread | raw e-mail | index | archive | help
I've rewritten some of your patch to not use dangling pointers. I also added the cd_dir functionality to the ftp guest account, not because I think it's a great idea, but because it will be consistent behavior. (If someone had specified /info/ftp/./pub as HOME for ftp, your patch would have chroot'd ftp into /info/ftp/pub, instead of /info/ftp. And this 'bug' would only appear for the ftp account. ;-)) In the event that this mail doesn't get munged the way I'd like, please respond to dhagan@colltech.com Thanks, Daniel Index: ftpcmd.y =================================================================== RCS file: /raid/ncvs/src/libexec/ftpd/ftpcmd.y,v retrieving revision 1.19 diff -u -r1.19 ftpcmd.y --- ftpcmd.y 2000/12/16 19:19:19 1.19 +++ ftpcmd.y 2001/01/04 15:55:42 @@ -92,6 +92,8 @@ extern char tmpline[]; extern int readonly; extern int noepsv; +extern int dochroot; +extern char *cd_dir, *chroot_dir; off_t restart_point; @@ -505,8 +507,11 @@ | CWD check_login CRLF { if ($2) { - if (guest) - cwd("/"); + if (guest || dochroot) + if (cd_dir != NULL) + cwd(cd_dir); + else + cwd("/"); else cwd(pw->pw_dir); } Index: ftpd.8 =================================================================== RCS file: /raid/ncvs/src/libexec/ftpd/ftpd.8,v retrieving revision 1.36 diff -u -r1.36 ftpd.8 --- ftpd.8 2000/12/18 08:33:25 1.36 +++ ftpd.8 2001/01/04 15:46:24 @@ -311,13 +311,14 @@ or the user is a member of a group with a group entry in this file, i.e. one prefixed with .Ql \&@ , -the session's root will be changed to the user's login directory by +the session's root will be changed to the user's login directory (up to the first /./) by .Xr chroot 2 as for an .Dq anonymous or .Dq ftp account (see next item). +The user is placed into the directory that remainds after stripping the former from the user's login directory. This facility may also be triggered by enabling the boolean "ftp-chroot" capability in .Xr login.conf 5 . Index: ftpd.c =================================================================== RCS file: /raid/ncvs/src/libexec/ftpd/ftpd.c,v retrieving revision 1.72 diff -u -r1.72 ftpd.c --- ftpd.c 2000/12/20 03:34:54 1.72 +++ ftpd.c 2001/01/04 15:56:59 @@ -140,6 +140,7 @@ int anon_only = 0; /* Only anonymous ftp allowed */ int guest; int dochroot; +char *cd_dir = NULL, *chroot_dir = NULL; int stats; int statfd = -1; int type; @@ -188,6 +189,9 @@ char *pid_file = NULL; +/* WARNING: FTP_CHROOT_SEPARATOR *MUST* end in / */ +#define FTP_CHROOT_SEPARATOR "/./" + /* * Timeout intervals for retrying connections * to hosts that don't accept PORT cmds. This @@ -251,6 +255,7 @@ static char *sgetsave __P((char *)); static void reapchild __P((int)); static void logxfer __P((char *, long, long)); +static void get_chroot_and_cd_dirs __P((char *, char **, char **)); static char * curdir() @@ -1038,6 +1043,8 @@ logged_in = 0; guest = 0; dochroot = 0; + free(chroot_dir); + free(cd_dir); } #if !defined(NOPAM) @@ -1291,19 +1298,20 @@ login_getcapbool(lc, "ftp-chroot", 0) || #endif checkuser(_PATH_FTPCHROOT, pw->pw_name, 1); - if (guest) { + if (guest || dochroot) { /* * We MUST do a chdir() after the chroot. Otherwise * the old current directory will be accessible as "." * outside the new root! */ - if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { - reply(550, "Can't set guest privileges."); - goto bad; - } - } else if (dochroot) { - if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { - reply(550, "Can't change root."); + get_chroot_and_cd_dirs(pw->pw_dir, &chroot_dir, &cd_dir); + /* + * Do not free chroot_dir & cd_dir b/c they are used in + * processing CWD commands from client. They should be + * free'd during a user logout. + */ + if (chroot(chroot_dir) < 0 || chdir(cd_dir) < 0) { + reply(550, guest ? "Can't set guest privileges." : "Can't change root."); goto bad; } } else if (chdir(pw->pw_dir) < 0) { @@ -2802,5 +2810,50 @@ ctime(&now)+4, ident, remotehost, path, name, size, now - start + (now == start)); write(statfd, buf, strlen(buf)); + } +} + +/* + * Make a pointer to the chroot dir and another to the cd dir. + * The first is all the path up to the first FTP_CHROOT_SEPARATOR. + * The later is the remaining chars, not including the FTP_CHROOT_SEPARATOR, + * but prepending a '/', if FTP_CHROOT_SEPARATOR is found. + * Otherwise, return user_home_dir as chroot_dir and "/" as cd_dir. + */ +static void +get_chroot_and_cd_dirs(user_home_dir, chroot_dir, cd_dir) + char *user_home_dir; + char **chroot_dir; + char **cd_dir; +{ + char *p; + + /* Make a pointer to first character of string FTP_CHROOT_SEPARATOR + inside user_home_dir. */ + p = (char *) strstr(user_home_dir, FTP_CHROOT_SEPARATOR); + if (p == NULL) { + /* + * There is not FTP_CHROOT_SEPARATOR string inside + * user_home_dir. Return user_home_dir as chroot_dir, + * and "/" as cd_dir. + */ + if ((*chroot_dir = (char *) strdup(user_home_dir)) == NULL) + fatal("Ran out of memory."); + if ((*cd_dir = (char *) strdup("/")) == NULL) + fatal("Ran out of memory."); + } else { + /* + * Use strlen(user_home_dir) as maximun length for + * both cd_dir and chroot_dir, as both are substrings of + * user_home_dir. + */ + if ((*chroot_dir = malloc(strlen(user_home_dir))) == NULL) + fatal("Ran out of memory."); + if ((*cd_dir = malloc(strlen(user_home_dir))) == NULL) + fatal("Ran out of memory."); + (void) strncpy(*chroot_dir, user_home_dir, p-user_home_dir); + /* Skip FTP_CHROOT_SEPARATOR (except the last /). */ + p += strlen(FTP_CHROOT_SEPARATOR)-1; + (void) strncpy(*cd_dir, p, strlen(p)); } } To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-audit" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200101041605.f04G5wM74909>