Subject: bin/9677: added feature to ftpd
To: None <gnats-bugs@gnats.netbsd.org>
From: Willem Brown <willem@segue.brwn.org>
List: netbsd-bugs
Date: 03/26/2000 12:43:26
>Number:         9677
>Category:       bin
>Synopsis:       added feature to ftpd
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Mar 26 12:42:00 2000
>Last-Modified:
>Originator:     Willem Brown
>Organization:
	
>Release:        NetBSD-1.4.2 RELEASE
>Environment:
	
System: NetBSD segue 1.4.2 NetBSD 1.4.2 (SEGUE) #1: Thu Mar 23 22:21:15 SAST 2000 root@segue:/usr/src/sys/arch/i386/compile/SEGUE i386


>Description:
	I needed an option to specify an alternate chroot directory for chroot users
	without having to change the user's login directory.

	The included patch adds the chrootdir option to specify an alternate directory
	for users in the chroot class.

	This is probably of no use to anyone except me, but here it is anyway.
	
>How-To-Repeat:
	N/A
	
>Fix:
diff -uNr ftpd.orig/conf.c ftpd/conf.c
--- ftpd.orig/conf.c	Wed Feb 24 18:45:13 1999
+++ ftpd/conf.c	Sun Mar 26 21:17:30 2000
@@ -109,6 +109,7 @@
 	curclass.passive =	1;
 	curclass.timeout =	900;		/* 15 minutes */
 	curclass.umask =	027;
+	REASSIGN(curclass.chrootdir, NULL);
 
 	if (strcasecmp(findclass, "guest") == 0) {
 		curclass.modify = 0;
@@ -295,6 +296,12 @@
 				continue;
 			}
 			curclass.umask = umask;
+		} else if (strcasecmp(word, "chrootdir") == 0) {
+			if (strcasecmp(class, "chroot") == 0 && !EMPTYSTR(arg))
+				arg = strdup(arg);
+			else
+				arg = NULL;
+			REASSIGN(curclass.chrootdir, arg);
 		} else {
 			syslog(LOG_WARNING,
 			    "%s line %d: unknown directive '%s'",
diff -uNr ftpd.orig/extern.h ftpd/extern.h
--- ftpd.orig/extern.h	Mon Dec 28 06:54:01 1998
+++ ftpd/extern.h	Sun Mar 26 20:10:20 2000
@@ -92,6 +92,7 @@
 	int		 passive;	/* Allow pasv */
 	unsigned int	 timeout;	/* Default timeout */
 	mode_t		 umask;		/* Umask to use */
+	char		*chrootdir;	/* chroot dir for this class */
 };
 
 extern  int yyparse __P((void));
diff -uNr ftpd.orig/ftpd.8 ftpd/ftpd.8
--- ftpd.orig/ftpd.8	Mon Mar 22 20:25:44 1999
+++ ftpd/ftpd.8	Sun Mar 26 21:51:46 2000
@@ -235,7 +235,13 @@
 .Dq anonymous
 or
 .Dq ftp
-account (see next item).
+account (see next item) unless the 
+.Dq chrootdir
+option is specified for the 
+.Dq chroot
+class in the
+.Pa /etc/ftpd.conf
+file (see below).
 However, the user must still supply a password.
 This feature is intended as a compromise between a fully anonymous account
 and a fully privileged account.
@@ -309,7 +315,11 @@
 The file
 .Pa /etc/ftpchroot
 is used to determine which users will have their session's root changed
-to the user's home directory.
+to the user's home directory or to the directory specified by the 
+.Dq chrootdir
+option for the 
+.Dq chroot
+class (see below). 
 If the file does not exist, the root change is not performed.
 If it does exist, each line is a comment starting with
 .Dq #
@@ -357,6 +367,17 @@
 or
 .Sy off
 is given, disable this feature, otherwise enable it.
+.It Sy chrootdir Ar class Op Ar path
+If
+.Ar path
+isn't given or
+.Ar class
+is not
+.Dq chroot ,
+disable this.
+Otherwise, change the session's root directory to
+.Ar path
+instead of using the user's login directory.
 .It Xo Sy conversion Ar class
 .Ar suffix Op Ar "type disable command"
 .Xc
@@ -496,6 +517,7 @@
 modify        all
 modify        guest  off
 notify        none
+chrootdir     none
 passive       all
 timeout       all    900    # 15 minutes
 umask         all    027
diff -uNr ftpd.orig/ftpd.c ftpd/ftpd.c
--- ftpd.orig/ftpd.c	Fri Oct  1 14:08:06 1999
+++ ftpd/ftpd.c	Sun Mar 26 21:29:50 2000
@@ -671,7 +671,12 @@
 			goto bad;
 		}
 	} else if (dochroot) {
-		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
+		/*
+		 * Use the chrootdir option if it is defined instead of the
+		 * home directory in the password file.
+		 */
+		if (chroot(curclass.chrootdir ? curclass.chrootdir : pw->pw_dir) < 0 || 
+                    chdir("/") < 0) {
 			reply(550, "Can't change root.");
 			goto bad;
 		}
	
>Audit-Trail:
>Unformatted: