From fpscha@ns1.via-net-works.net.ar  Fri Dec 29 08:19:51 2000
Return-Path: <fpscha@ns1.via-net-works.net.ar>
Received: from ns1.via-net-works.net.ar (ns1.via-net-works.net.ar [200.10.100.10])
	by hub.freebsd.org (Postfix) with ESMTP id 9444737B400
	for <FreeBSD-gnats-submit@freebsd.org>; Fri, 29 Dec 2000 08:19:49 -0800 (PST)
Received: (from fpscha@localhost)
	by ns1.via-net-works.net.ar (8.9.3/8.9.3) id NAA03223;
	Fri, 29 Dec 2000 13:20:46 -0300 (ART)
Message-Id: <200012291620.NAA03223@ns1.via-net-works.net.ar>
Date: Fri, 29 Dec 2000 13:20:46 -0300 (ART)
From: fschapachnik@vianetworks.com.ar
Sender: fpscha@ns1.via-net-works.net.ar
Reply-To: fpscha@ns1.via-net-works.net.ar
To: FreeBSD-gnats-submit@freebsd.org
Subject: Patch for ftpd to add a cd after the chroot.
X-Send-Pr-Version: 3.2

>Number:         23944
>Category:       bin
>Synopsis:       Patch for ftpd to add a cd after the chroot.
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    yar
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Dec 29 08:20:01 PST 2000
>Closed-Date:    Tue Feb 11 06:53:09 PST 2003
>Last-Modified:  Tue Feb 11 06:53:09 PST 2003
>Originator:     Fernando Schapachnik
>Release:        FreeBSD 4.2-RELEASE i386
>Organization:
VIA NET.WORKS ARGENTINA
>Environment:

	ftpd chroots to the user home directory if username is
	specified in /etc/ftproot.
	Other FTP daemons, like wu-ftpd, split the user's home
	dir in two parts, using '/./' as a separator.
	The first one becomes the chroot dir, and after the
	chroot the user is chdir'ed to the second part.

>Description:

	A patch is supplied to add similar functionality to
	ftpd.

>How-To-Repeat:

	See patch.

>Fix:


--- ftpd.c.orig	Mon Oct 23 17:57:54 2000
+++ ftpd.c	Fri Dec 29 12:49:09 2000
@@ -185,6 +185,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
@@ -248,6 +251,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()
@@ -1168,6 +1172,7 @@
 {
 	int rval;
 	FILE *fd;
+	char *cd_dir, *chroot_dir;
 #ifdef	LOGIN_CAP
 	login_cap_t *lc = NULL;
 #endif
@@ -1291,10 +1296,15 @@
 			goto bad;
 		}
 	} else if (dochroot) {
-		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
+		get_chroot_and_cd_dirs(pw->pw_dir, &chroot_dir, &cd_dir);
+		if (chroot(chroot_dir) < 0 || chdir(cd_dir) < 0) {
+			free(chroot_dir);
+			free(cd_dir);
 			reply(550, "Can't change root.");
 			goto bad;
 		}
+		free(chroot_dir);
+		free(cd_dir);
 	} else if (chdir(pw->pw_dir) < 0) {
 		if (chdir("/") < 0) {
 			reply(530, "User %s: can't change directory to %s.",
@@ -2789,5 +2799,47 @@
 			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 '/'.
+ */
+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.
+		  */
+		 *chroot_dir = (char *) strdup(user_home_dir);
+		 *cd_dir = (char *) strdup("/");
+	} 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));
 	}
 }
--- ftpd.8.orig	Fri Dec 29 12:53:21 2000
+++ ftpd.8	Fri Dec 29 12:55:51 2000
@@ -298,13 +298,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 .

>Release-Note:
>Audit-Trail:

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
Date: Thu, 4 Jan 2001 11:05:58 -0500 (EST)

 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));
  	}
  }
 

From: Daniel Hagan <dhagan@colltech.com>
To: freebsd-audit@FreeBSD.ORG, freebsd-gnats-submit@FreeBSD.ORG,
	fschapachnik@vianetworks.com.ar, greid@dogma.freebsd-uk.eu.org
Cc:  
Subject: Re: bin/23944: Proposed modification to ftpd
Date: Thu, 04 Jan 2001 11:13:02 -0500

 Oh, forgot to mention -- this is against -CURRENT not -STABLE.
 
 Daniel
 
 Daniel Hagan wrote:
 > 
 > I've rewritten some of your patch to not use dangling pointers.  I also
 

From: Daniel Hagan <dhagan@colltech.com>
To: freebsd-gnats-submit@FreeBSD.org, fpscha@ns1.via-net-works.net.ar
Cc:  
Subject: Re: bin/23944: [PATCH] Patch for ftpd to add a cd after the chroot.
Date: Thu, 04 Jan 2001 16:58:24 -0500

 Here's a patch that addresses several different PRs and discussions
 recently concerning ftpd.  Available at
 http://vtopus.cs.vt.edu/~dhagan/freebsd/ftpd.patch
 
 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 20:16:35
 @@ -91,7 +91,10 @@
  extern  int transflag;
  extern  char tmpline[];
  extern int readonly;
 +extern int readonly_user;
  extern int noepsv;
 +extern int dochroot;
 +extern char *cd_dir, *chroot_dir;
  
  off_t  restart_point;
  
 @@ -505,8 +508,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);
                         }
 @@ -979,6 +985,10 @@
                 {
                 if (readonly) {
                         reply(202, "Command ignored. Server is in
 readonly mode.");
 +                       $$ = 0;
 +               }
 +               else if (readonly_user) {
 +                       reply(202, "Command ignored. User is in readonly
 session.");
                         $$ = 0;
                 }
                 else
 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 20:23:27
 @@ -158,6 +158,10 @@
  .It Fl r
  Put server in read-only mode.
  All commands which may modify the local filesystem are disabled.
 +Read-only mode may be set on a per account basis in
 +.Xr login.conf 5
 +with the boolean capability
 +.Dq ftp-readonly .
  .It Fl E
  Disable the EPSV command.
  This is useful for servers behind older firewalls.
 @@ -258,8 +262,12 @@
  .Pp
  The ftp server will abort an active file transfer only when the
  ABOR
 -command is preceded by a Telnet "Interrupt Process" (IP)
 -signal and a Telnet "Synch" signal in the command Telnet stream,
 +command is preceded by a Telnet
 +.Dq "Interrupt Process"
 +.Pq IP
 +signal and a Telnet
 +.Dq Synch
 +signal in the command Telnet stream,
  as described in Internet RFC 959.
  If a
  STAT
 @@ -299,7 +307,8 @@
  .It
  The login name must not be a member of a group specified in the file
  .Pa /etc/ftpusers .
 -Entries in this file interpreted as group names are prefixed by an "at"
 +Entries in this file interpreted as group names are prefixed by an
 +.Dq at
  .Ql \&@
  sign.
  .It
 @@ -311,14 +320,19 @@
  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
 +.Pq "up to the first /./"
 +by
  .Xr chroot 2
  as for an
  .Dq anonymous
  or
  .Dq ftp
  account (see next item).
 -This facility may also be triggered by enabling the boolean
 "ftp-chroot"
 +The user is placed into the directory that remains after stripping the
 +former from the user's login directory.
 +This facility may also be triggered by enabling the boolean
 +.Dq ftp-chroot
  capability in
  .Xr login.conf 5 .
  However, the user must still supply a password.
 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 20:11:48
 @@ -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;
 @@ -149,6 +150,7 @@
  int    usedefault = 1;         /* for data transfers */
  int    pdata = -1;             /* for passive mode */
  int    readonly=0;             /* Server is in readonly mode.  */
 +int    readonly_user = 0;      /* User's session is readonly. */
  int    noepsv=0;               /* EPSV command is disabled.    */
  sig_atomic_t transflag;
  off_t  file_size;
 @@ -188,6 +190,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 +256,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 +1044,10 @@
         logged_in = 0;
         guest = 0;
         dochroot = 0;
 +       readonly_user = 0;
 +       free(chroot_dir);
 +       free(cd_dir);
 +       chroot_dir = cd_dir = NULL;
  }
  
  #if !defined(NOPAM)
 @@ -1291,19 +1301,23 @@
                 login_getcapbool(lc, "ftp-chroot", 0) ||
  #endif
                 checkuser(_PATH_FTPCHROOT, pw->pw_name, 1);
 -       if (guest) {
 +#ifdef LOGIN_CAP       /* Check for ftp-readonly */
 +               readonly_user = login_getcapbool(lc, "ftp-readonly", 0);
 +#endif
 +       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 +2816,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));
         }
  }
 

From: Fernando Schapachnik <fschapachnik@vianetworks.com.ar>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: bin/23944: Patch for ftpd to add a cd after the chroot.
Date: Tue, 12 Feb 2002 17:08:05 -0300

 --0F1p//8PRICkK4MW
 Content-Type: text/plain; charset=iso-8859-1
 Content-Disposition: inline
 Content-Transfer-Encoding: 8bit
 
 Hi,
 	Here it is an updated version of the patch against
 4.5-RELEASE. I'd like to see it come into the main tree.
 
 	Regards.
 
 
 Fernando P. Schapachnik
 Gerente de tecnologa de red
 y sistemas de informacin
 VIA NET.WORKS ARGENTINA S.A.
 fschapachnik@vianetworks.com.ar
 Tel.: (54-11) 4323-3381
 
 --0F1p//8PRICkK4MW
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename="ftpd.patch-4.5"
 
 --- ftpd.c.orig	Tue Dec 18 15:35:55 2001
 +++ ftpd.c	Tue Feb 12 16:51:22 2002
 @@ -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;
 @@ -191,6 +192,9 @@
  
  char	*pid_file = NULL;
  
 +/* WARNING: FTP_CHROOT_SEPARATOR *MUST* end in / */
 +#define FTP_CHROOT_SEPARATOR	"/./"
 +
  /*
   * Limit number of pathnames that glob can return.
   * A limit of 0 indicates the number of pathnames is unlimited.
 @@ -261,6 +265,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()
 @@ -1056,6 +1061,14 @@
  	logged_in = 0;
  	guest = 0;
  	dochroot = 0;
 +	if (chroot_dir!=NULL) {
 +		free(chroot_dir);
 +		chroot_dir= NULL;
 +	}
 +	if (cd_dir!=NULL) {
 +		free(cd_dir);
 +		cd_dir= NULL;
 +	}
  }
  
  #if !defined(NOPAM)
 @@ -1320,7 +1333,8 @@
  			goto bad;
  		}
  	} else if (dochroot) {
 -		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
 +		get_chroot_and_cd_dirs(pw->pw_dir, &chroot_dir, &cd_dir);
 +		if (chroot(chroot_dir) < 0 || chdir(cd_dir) < 0) {
  			reply(550, "Can't change root.");
  			goto bad;
  		}
 @@ -2841,5 +2855,53 @@
  			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;
 +	int len= strlen(user_home_dir);
 +
 +	/* 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(len)) == NULL)
 +			fatal("Ran out of memory.");
 +		 if ((*cd_dir = malloc(len)) == NULL)
 +			fatal("Ran out of memory.");
 +		 (void) strncpy(*chroot_dir, user_home_dir, len-strlen(p));
 +		 *(*chroot_dir+(len-strlen(p)))= '\0';
 +		 /* Skip FTP_CHROOT_SEPARATOR (except the last /). */
 +		 p += strlen(FTP_CHROOT_SEPARATOR)-1;
 +		 (void) strncpy(*cd_dir, p, strlen(p));
 +		 *(*cd_dir+strlen(p))= '\0';
  	}
  }
 --- ftpd.8.orig	Tue Dec 18 15:35:55 2001
 +++ ftpd.8	Tue Feb 12 16:51:22 2002
 @@ -321,13 +321,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 .
 --- ftpcmd.y.orig	Tue Feb 12 16:59:03 2002
 +++ ftpcmd.y	Tue Feb 12 17:00:30 2002
 @@ -94,6 +94,8 @@
  extern	int noepsv;
  extern	int noretr;
  extern	int noguestretr;
 +extern	int dochroot;
 +extern	char *cd_dir, *chroot_dir;
  
  off_t	restart_point;
  
 @@ -525,7 +527,9 @@
  			if ($2) {
  				if (guest)
  					cwd("/");
 -				else
 +				else if (dochroot) {
 +					cwd(cd_dir);
 +				} else
  					cwd(pw->pw_dir);
  			}
  		}
 
 --0F1p//8PRICkK4MW--
Responsible-Changed-From-To: freebsd-bugs->yar 
Responsible-Changed-By: johan 
Responsible-Changed-When: Wed Aug 21 12:54:32 PDT 2002 
Responsible-Changed-Why:  
Another ftpd PR with alot of patches. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=23944 

From: Yar Tikhiy <yar@FreeBSD.org>
To: freebsd-gnats-submit@FreeBSD.org, fpscha@ns1.via-net-works.net.ar
Cc:  
Subject: Re: bin/23944: Patch for ftpd to add a cd after the chroot.
Date: Wed, 29 Jan 2003 12:02:07 +0300

 Hi Fernando,
 
 I'm installing a patch to FreeBSD-current that should add the feature
 you proposed 2 years ago to ftpd(8) (it's a shame it took us that
 long to deal with your proposal.)  Could you test my solution in
 -current, or shall I provide a patch against 4.7-stable for your
 convenience?
 
 -- 
 Yar
State-Changed-From-To: open->patched 
State-Changed-By: yar 
State-Changed-When: Wed Jan 29 02:10:36 PST 2003 
State-Changed-Why:  
Implemented in -current. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=23944 

From: Fernando Schapachnik <fernando@mecon.gov.ar>
To: yar@FreeBSD.org
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: bin/23944: Patch for ftpd to add a cd after the chroot. (fwd)
Date: Wed, 29 Jan 2003 10:28:01 -0300

 Hi Yar,
 	I'm relocated now. Unfortunatedly all I have are RELENG_4_7 machines.
 
 	I'd gladly test it. I can also provide my current patches, in case you
 need them.
 
 	Kind regards!
 
 
 
 Lic. Fernando Schapachnik
 Proyecto de Informtica
 Ministerio de Economa
 ----- Forwarded message from Hernan Nunez <hnunez@vianetworks.com.ar> -----
 
 X-Sieve: cmu-sieve 1.3
 From: Hernan Nunez <hnunez@vianetworks.com.ar>
 Reply-To: <hnunez@vianetworks.com.ar>
 To: "Yar Tikhiy" <yar@FreeBSD.org>
 Cc: "Fernando Schapachnik" <fernando@mecon.gov.ar>
 Subject: Re: bin/23944: Patch for ftpd to add a cd after the chroot.
 Date: Wed, 29 Jan 2003 10:20:35 -0300
 X-Priority: 3
 X-MSMail-Priority: Normal
 X-Mailer: Microsoft Outlook Express 6.00.2800.1106
 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1106
 
 Yar,
 
  You could contact Fernando at fernando@mecon.gov.ar. 
 
 
 
 ----- Original Message ----- 
 From: "Yar Tikhiy" <yar@FreeBSD.org>
 To: <freebsd-gnats-submit@FreeBSD.org>; <fpscha@ns1.via-net-works.net.ar>
 Sent: Wednesday, January 29, 2003 6:02 AM
 Subject: Re: bin/23944: Patch for ftpd to add a cd after the chroot.
 
 
 > Hi Fernando,
 > 
 > I'm installing a patch to FreeBSD-current that should add the feature
 > you proposed 2 years ago to ftpd(8) (it's a shame it took us that
 > long to deal with your proposal.)  Could you test my solution in
 > -current, or shall I provide a patch against 4.7-stable for your
 > convenience?
 > 
 > -- 
 > Yar
 > 
 
 ----- End forwarded message -----

From: Yar Tikhiy <yar@FreeBSD.org>
To: Fernando Schapachnik <fernando@mecon.gov.ar>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: bin/23944: Patch for ftpd to add a cd after the chroot. (fwd)
Date: Wed, 29 Jan 2003 19:41:45 +0300

 Fernando,
 
 On Wed, Jan 29, 2003 at 10:28:01AM -0300, Fernando Schapachnik wrote:
 >
 > I'm relocated now. Unfortunatedly all I have are RELENG_4_7 machines.
 > 
 > I'd gladly test it. I can also provide my current patches, in case you
 > need them.
 
 Thank you.  I'll make a patch against RELENG_4_7 and send it to you ASAP.
 As for your current patches, may I have a look at them?
 
 -- 
 Yar

From: Fernando Schapachnik <fernando@mecon.gov.ar>
To: Yar Tikhiy <yar@FreeBSD.org>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: bin/23944: Patch for ftpd to add a cd after the chroot. (fwd)
Date: Wed, 29 Jan 2003 14:09:13 -0300

 --4Ckj6UjgE2iN1+kY
 Content-Type: text/plain; charset=iso-8859-1
 Content-Disposition: inline
 Content-Transfer-Encoding: 8bit
 
 En un mensaje anterior, Yar Tikhiy escribi:
 > Thank you.  I'll make a patch against RELENG_4_7 and send it to you ASAP.
 > As for your current patches, may I have a look at them?
 
 Here you have it.
 
 They are against 4.6.1, but I think there aplied cleanly against 4.7.
 
 Kind regards.
 
 Fernando.
 
 --4Ckj6UjgE2iN1+kY
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename="ftpd.patch-4.6.1"
 
 --- ftpd.c.orig	Wed Jun 19 00:45:27 2002
 +++ ftpd.c	Mon Aug  5 07:37:06 2002
 @@ -138,6 +138,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;
 @@ -190,6 +191,9 @@
  
  char	*pid_file = NULL;
  
 +/* WARNING: FTP_CHROOT_SEPARATOR *MUST* end in / */
 +#define FTP_CHROOT_SEPARATOR	"/./"
 +
  /*
   * Limit number of pathnames that glob can return.
   * A limit of 0 indicates the number of pathnames is unlimited.
 @@ -262,6 +266,7 @@
  static char	*sgetsave __P((char *));
  static void	 reapchild __P((int));
  static void      logxfer __P((char *, off_t, time_t));
 +static void      get_chroot_and_cd_dirs __P((char *, char **, char **));
  
  static char *
  curdir()
 @@ -1082,6 +1087,14 @@
  	logged_in = 0;
  	guest = 0;
  	dochroot = 0;
 +	if (chroot_dir!=NULL) {
 +		free(chroot_dir);
 +		chroot_dir= NULL;
 +	}
 +	if (cd_dir!=NULL) {
 +		free(cd_dir);
 +		cd_dir= NULL;
 +	}
  }
  
  #if !defined(NOPAM)
 @@ -1346,7 +1359,8 @@
  			goto bad;
  		}
  	} else if (dochroot) {
 -		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
 +		get_chroot_and_cd_dirs(pw->pw_dir, &chroot_dir, &cd_dir);
 +		if (chroot(chroot_dir) < 0 || chdir(cd_dir) < 0) {
  			reply(550, "Can't change root.");
  			goto bad;
  		}
 @@ -2890,5 +2904,53 @@
  			path, name, (long long)size,
  			(long)(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;
 +	int len= strlen(user_home_dir);
 +
 +	/* 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)
 +			fatalerror("Ran out of memory.");
 +		 if ((*cd_dir = (char *) strdup("/")) == NULL)
 +			fatalerror("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(len)) == NULL)
 +			fatalerror("Ran out of memory.");
 +		 if ((*cd_dir = malloc(len)) == NULL)
 +			fatalerror("Ran out of memory.");
 +		 (void) strncpy(*chroot_dir, user_home_dir, len-strlen(p));
 +		 *(*chroot_dir+(len-strlen(p)))= '\0';
 +		 /* Skip FTP_CHROOT_SEPARATOR (except the last /). */
 +		 p += strlen(FTP_CHROOT_SEPARATOR)-1;
 +		 (void) strncpy(*cd_dir, p, strlen(p));
 +		 *(*cd_dir+strlen(p))= '\0';
  	}
  }
 --- ftpd.8.orig	Wed Jun 19 00:45:27 2002
 +++ ftpd.8	Mon Aug  5 07:28:09 2002
 @@ -324,13 +324,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 .
 --- ftpcmd.y.orig	Wed Jun 19 00:45:27 2002
 +++ ftpcmd.y	Mon Aug  5 07:28:09 2002
 @@ -95,6 +95,8 @@
  extern	int noepsv;
  extern	int noretr;
  extern	int noguestretr;
 +extern	int dochroot;
 +extern	char *cd_dir, *chroot_dir;
  
  off_t	restart_point;
  
 @@ -536,7 +538,9 @@
  			if ($2) {
  				if (guest)
  					cwd("/");
 -				else
 +				else if (dochroot) {
 +					cwd(cd_dir);
 +				} else
  					cwd(pw->pw_dir);
  			}
  		}
 
 --4Ckj6UjgE2iN1+kY--
State-Changed-From-To: patched->closed 
State-Changed-By: yar 
State-Changed-When: Tue Feb 11 06:52:26 PST 2003 
State-Changed-Why:  
The proposed feature has been merged to STABLE as well.  Thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=23944 
>Unformatted:
