Date: Thu, 4 Jan 2001 12:14:41 -0500 (EST) From: Daniel Hagan <dhagan@colltech.com> To: freebsd-audit@freebsd.org Cc: freebsd-security@freebsd.org Subject: Re: ftpd and anonymous setup (modified ftpd) Message-ID: <200101041714.f04HEfB75136@athena.cs.vt.edu>
next in thread | raw e-mail | index | archive | help
Here's a quick patch that includes the chroot/cwd patch mentioned earlier
and a login.conf capability to set a session to read-only.
[Apologies if you receive this twice, I think it got bounced at freebsd.org]
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 16:58:49
@@ -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 "ftp-readonly". Once set in a session
+it cannot be cleared (i.e. by USER).
.It Fl E
Disable the EPSV command.
This is useful for servers behind older firewalls.
@@ -311,13 +315,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 17:00:42
@@ -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,13 @@
logged_in = 0;
guest = 0;
dochroot = 0;
+ /*
+ * do not reset readonly to 0 b/c once session is ro, we leave it
+ * that way for security's sake.
+ */
+ free(chroot_dir);
+ free(cd_dir);
+ chroot_dir = cd_dir = NULL;
}
#if !defined(NOPAM)
@@ -1291,19 +1303,24 @@
login_getcapbool(lc, "ftp-chroot", 0) ||
#endif
checkuser(_PATH_FTPCHROOT, pw->pw_name, 1);
- if (guest) {
+#ifdef LOGIN_CAP /* Check for ftp-readonly */
+ if (readonly = 0)
+ readonly = 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 +2819,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?200101041714.f04HEfB75136>
