Skip site navigation (1)Skip section navigation (2)
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>