summaryrefslogtreecommitdiff
path: root/libexec/ftpd
diff options
context:
space:
mode:
authorlukem <lukem@NetBSD.org>2001-12-04 13:54:12 +0000
committerlukem <lukem@NetBSD.org>2001-12-04 13:54:12 +0000
commitc31e16f75ea78ef2c02ee381b2bbca920883dd9a (patch)
treeb1a72f10a141be62a27d90a9f94f5c089caf6476 /libexec/ftpd
parentc08523b03e6ed056e11129fdfdf4f600f30c3ff6 (diff)
Add two new ftpd.conf(5) directives:
- 'denyquick'; deny a connection so tagged by ftpusers(5) after the USER command instead of the PASS command. whilst this might provide some info leakage of accounts names if you have some `real' or `chroot' users enabled and not others, it does prevent accidental entering of such passwords if you have all such users denied. This option is strongly recommended on anonymous-only servers. Functionality requested by Rob Windsor in [bin/12602] - 'private'; don't display class related information in the output of STAT. For paranoid admins.
Diffstat (limited to 'libexec/ftpd')
-rw-r--r--libexec/ftpd/conf.c12
-rw-r--r--libexec/ftpd/extern.h12
-rw-r--r--libexec/ftpd/ftpd.c181
-rw-r--r--libexec/ftpd/ftpd.conf.549
-rw-r--r--libexec/ftpd/version.h4
5 files changed, 172 insertions, 86 deletions
diff --git a/libexec/ftpd/conf.c b/libexec/ftpd/conf.c
index dd34d4c8a60..7a771e10d7a 100644
--- a/libexec/ftpd/conf.c
+++ b/libexec/ftpd/conf.c
@@ -1,4 +1,4 @@
-/* $NetBSD: conf.c,v 1.45 2001/12/01 10:25:29 lukem Exp $ */
+/* $NetBSD: conf.c,v 1.46 2001/12/04 13:54:12 lukem Exp $ */
/*-
* Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: conf.c,v 1.45 2001/12/01 10:25:29 lukem Exp $");
+__RCSID("$NetBSD: conf.c,v 1.46 2001/12/04 13:54:12 lukem Exp $");
#endif /* not lint */
#include <sys/types.h>
@@ -121,8 +121,10 @@ init_curclass(void)
curclass.umask = DEFAULT_UMASK;
CURCLASS_FLAGS_SET(checkportcmd);
+ CURCLASS_FLAGS_CLR(denyquick);
CURCLASS_FLAGS_SET(modify);
CURCLASS_FLAGS_SET(passive);
+ CURCLASS_FLAGS_CLR(private);
CURCLASS_FLAGS_CLR(sanenames);
CURCLASS_FLAGS_SET(upload);
}
@@ -330,6 +332,9 @@ parse_conf(const char *findclass)
REASSIGN(conv->disable, disable);
REASSIGN(conv->command, convcmd);
+ } else if (strcasecmp(word, "denyquick") == 0) {
+ CONF_FLAG(denyquick);
+
} else if (strcasecmp(word, "display") == 0) {
CONF_STRING(display);
@@ -446,6 +451,9 @@ parse_conf(const char *findclass)
curclass.portmin = minport;
curclass.portmax = maxport;
+ } else if (strcasecmp(word, "private") == 0) {
+ CONF_FLAG(private);
+
} else if (strcasecmp(word, "rateget") == 0) {
curclass.maxrateget = 0;
curclass.rateget = 0;
diff --git a/libexec/ftpd/extern.h b/libexec/ftpd/extern.h
index b7464ad1e37..dc60fc0d22c 100644
--- a/libexec/ftpd/extern.h
+++ b/libexec/ftpd/extern.h
@@ -1,4 +1,4 @@
-/* $NetBSD: extern.h,v 1.42 2001/07/13 05:37:49 lukem Exp $ */
+/* $NetBSD: extern.h,v 1.43 2001/12/04 13:54:12 lukem Exp $ */
/*-
* Copyright (c) 1992, 1993
@@ -239,11 +239,13 @@ typedef enum {
typedef enum {
FLAG_checkportcmd = 1<<0, /* Check port commands */
- FLAG_modify = 1<<1, /* Allow CHMOD, DELE, MKD, RMD, RNFR,
+ FLAG_denyquick = 1<<1, /* Check ftpusers(5) before PASS */
+ FLAG_modify = 1<<2, /* Allow CHMOD, DELE, MKD, RMD, RNFR,
UMASK */
- FLAG_passive = 1<<2, /* Allow PASV mode */
- FLAG_sanenames = 1<<3, /* Restrict names of uploaded files */
- FLAG_upload = 1<<4 /* As per modify, but also allow
+ FLAG_passive = 1<<3, /* Allow PASV mode */
+ FLAG_private = 1<<4, /* Don't publish class info in STAT */
+ FLAG_sanenames = 1<<5, /* Restrict names of uploaded files */
+ FLAG_upload = 1<<6, /* As per modify, but also allow
APPE, STOR, STOU */
} classflag_t;
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index adfdd294ae5..46308ca6f7d 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ftpd.c,v 1.132 2001/12/01 10:25:30 lukem Exp $ */
+/* $NetBSD: ftpd.c,v 1.133 2001/12/04 13:54:12 lukem Exp $ */
/*
* Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
@@ -109,7 +109,7 @@ __COPYRIGHT(
#if 0
static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
#else
-__RCSID("$NetBSD: ftpd.c,v 1.132 2001/12/01 10:25:30 lukem Exp $");
+__RCSID("$NetBSD: ftpd.c,v 1.133 2001/12/04 13:54:12 lukem Exp $");
#endif
#endif /* not lint */
@@ -561,7 +561,8 @@ sgetpwnam(const char *name)
}
static int login_attempts; /* number of failed login attempts */
-static int askpasswd; /* had user command, ask for passwd */
+static int askpasswd; /* had USER command, ask for PASSwd */
+static int permitted; /* USER permitted */
static char curname[10]; /* current USER name */
/*
@@ -578,6 +579,9 @@ static char curname[10]; /* current USER name */
void
user(const char *name)
{
+ char *class;
+
+ class = NULL;
if (logged_in) {
switch (curclass.type) {
case CLASS_GUEST:
@@ -606,6 +610,9 @@ user(const char *name)
#endif
curclass.type = CLASS_REAL;
+ askpasswd = 0;
+ permitted = 0;
+
if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
/* need `pw' setup for checkaccess() and checkuser () */
if ((pw = sgetpwnam("ftp")) == NULL)
@@ -618,34 +625,106 @@ user(const char *name)
reply(331,
"Guest login ok, type your name as password.");
}
- if (!askpasswd && logging)
- syslog(LOG_NOTICE,
- "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
- return;
- }
+ if (!askpasswd) {
+ if (logging)
+ syslog(LOG_NOTICE,
+ "ANONYMOUS FTP LOGIN REFUSED FROM %s",
+ remotehost);
+ end_login();
+ goto cleanup_user;
+ }
+ name = "ftp";
+ } else
+ pw = sgetpwnam(name);
- pw = sgetpwnam(name);
if (logging)
strlcpy(curname, name, sizeof(curname));
-#ifdef SKEY
- if (skey_haskey(name) == 0) {
- const char *myskey;
+ /* check user in /etc/ftpusers, and setup class */
+ permitted = checkuser(_PATH_FTPUSERS, curname, 1, 0, &class);
- myskey = skey_keyinfo(name);
- reply(331, "Password [%s] required for %s.",
- myskey ? myskey : "error getting challenge", name);
- } else
+ /* check user in /etc/ftpchroot */
+ if (checkuser(_PATH_FTPCHROOT, curname, 0, 0, NULL)) {
+ if (curclass.type == CLASS_GUEST) {
+ syslog(LOG_NOTICE,
+ "Can't change guest user to chroot class; remove entry in %s",
+ _PATH_FTPCHROOT);
+ exit(1);
+ }
+ curclass.type = CLASS_CHROOT;
+ }
+ /* determine default class */
+ if (class == NULL) {
+ switch (curclass.type) {
+ case CLASS_GUEST:
+ class = xstrdup("guest");
+ break;
+ case CLASS_CHROOT:
+ class = xstrdup("chroot");
+ break;
+ case CLASS_REAL:
+ class = xstrdup("real");
+ break;
+ default:
+ syslog(LOG_ERR, "unknown curclass.type %d; aborting",
+ curclass.type);
+ abort();
+ }
+ }
+ /* parse ftpd.conf, setting up various parameters */
+ parse_conf(class);
+ /* if not guest user, check for valid shell */
+ if (pw == NULL)
+ permitted = 0;
+ else {
+ const char *cp, *shell;
+
+ if ((shell = pw->pw_shell) == NULL || *shell == 0)
+ shell = _PATH_BSHELL;
+ while ((cp = getusershell()) != NULL)
+ if (strcmp(cp, shell) == 0)
+ break;
+ endusershell();
+ if (cp == NULL && curclass.type != CLASS_GUEST)
+ permitted = 0;
+ }
+
+ /* deny quickly (after USER not PASS) if requested */
+ if (CURCLASS_FLAGS_ISSET(denyquick) && !permitted) {
+ reply(530, "User %s may not use FTP.", curname);
+ if (logging)
+ syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
+ remotehost, curname);
+ end_login();
+ goto cleanup_user;
+ }
+
+ /* if haven't asked yet (i.e, not anon), ask now */
+ if (!askpasswd) {
+ askpasswd = 1;
+#ifdef SKEY
+ if (skey_haskey(curname) == 0) {
+ const char *myskey;
+
+ myskey = skey_keyinfo(curname);
+ reply(331, "Password [%s] required for %s.",
+ myskey ? myskey : "error getting challenge",
+ curname);
+ } else
#endif
- reply(331, "Password required for %s.", name);
+ reply(331, "Password required for %s.", curname);
+ }
- askpasswd = 1;
+ cleanup_user:
/*
* Delay before reading passwd after first failed
* attempt to slow down passwd-guessing programs.
*/
if (login_attempts)
sleep((unsigned) login_attempts);
+
+ if (class)
+ free(class);
}
/*
@@ -740,6 +819,8 @@ checkuser(const char *fname, const char *name, int def, int nofile,
gid_t *groups, *ng;
int gsize, i, found;
+ if (pw == NULL)
+ continue; /* no match for unknown user */
*p++ = '\0';
groups = NULL;
gsize = 16;
@@ -823,6 +904,8 @@ end_login(void)
memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
pw = NULL;
logged_in = 0;
+ askpasswd = 0;
+ permitted = 0;
quietmessages = 0;
gidcount = 0;
curclass.type = CLASS_REAL;
@@ -833,10 +916,8 @@ void
pass(const char *passwd)
{
int rval;
- const char *cp, *shell;
- char *class, root[MAXPATHLEN];
+ char root[MAXPATHLEN];
- class = NULL;
if (logged_in || askpasswd == 0) {
reply(503, "Login with USER first.");
return;
@@ -907,22 +988,8 @@ pass(const char *passwd)
}
}
- /* password ok; see if anything else prevents login */
- if (! checkuser(_PATH_FTPUSERS, pw->pw_name, 1, 0, &class)) {
- reply(530, "User %s may not use FTP.", pw->pw_name);
- if (logging)
- syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
- remotehost, pw->pw_name);
- goto bad;
- }
- /* if not guest user, check for valid shell */
- if ((shell = pw->pw_shell) == NULL || *shell == 0)
- shell = _PATH_BSHELL;
- while ((cp = getusershell()) != NULL)
- if (strcmp(cp, shell) == 0)
- break;
- endusershell();
- if (cp == NULL && curclass.type != CLASS_GUEST) {
+ /* password ok; check if anything else prevents login */
+ if (! permitted) {
reply(530, "User %s may not use FTP.", pw->pw_name);
if (logging)
syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
@@ -955,36 +1022,6 @@ pass(const char *passwd)
logged_in = 1;
- /* check user in /etc/ftpchroot */
- if (checkuser(_PATH_FTPCHROOT, pw->pw_name, 0, 0, NULL)) {
- if (curclass.type == CLASS_GUEST) {
- syslog(LOG_NOTICE,
- "Can't change guest user to chroot class; remove entry in %s",
- _PATH_FTPCHROOT);
- exit(1);
- }
- curclass.type = CLASS_CHROOT;
- }
- if (class == NULL) {
- switch (curclass.type) {
- case CLASS_GUEST:
- class = xstrdup("guest");
- break;
- case CLASS_CHROOT:
- class = xstrdup("chroot");
- break;
- case CLASS_REAL:
- class = xstrdup("real");
- break;
- default:
- syslog(LOG_ERR, "unknown curclass.type %d; aborting",
- curclass.type);
- abort();
- }
- }
-
- /* parse ftpd.conf, setting up various parameters */
- parse_conf(class);
connections = 1;
if (dopidfile)
count_users();
@@ -1154,15 +1191,11 @@ pass(const char *passwd)
curclass.classname, CURCLASSTYPE);
}
(void) umask(curclass.umask);
- goto cleanuppass;
+ return;
bad:
/* Forget all about it... */
end_login();
-
- cleanuppass:
- if (class)
- free(class);
}
void
@@ -2019,7 +2052,7 @@ statcmd(void)
(LLT)otb, PLURAL(otb),
(LLT)total_xfers, PLURAL(total_xfers));
- if (logged_in) {
+ if (logged_in && !CURCLASS_FLAGS_ISSET(private)) {
struct ftpconv *cp;
reply(0, "%s", "");
@@ -2043,6 +2076,8 @@ statcmd(void)
conffilename(curclass.limitfile));
if (! EMPTYSTR(curclass.chroot))
reply(0, "Chroot format: %s", curclass.chroot);
+ reply(0, "Deny bad ftpusers(5) quickly: : %sabled",
+ CURCLASS_FLAGS_ISSET(denyquick) ? "en" : "dis");
if (! EMPTYSTR(curclass.homedir))
reply(0, "Homedir format: %s", curclass.homedir);
if (curclass.maxfilesize == -1)
diff --git a/libexec/ftpd/ftpd.conf.5 b/libexec/ftpd/ftpd.conf.5
index ff42342f3b0..4ee2a31530a 100644
--- a/libexec/ftpd/ftpd.conf.5
+++ b/libexec/ftpd/ftpd.conf.5
@@ -1,4 +1,4 @@
-.\" $NetBSD: ftpd.conf.5,v 1.17 2001/07/08 07:27:14 lukem Exp $
+.\" $NetBSD: ftpd.conf.5,v 1.18 2001/12/04 13:54:13 lukem Exp $
.\"
.\" Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -34,7 +34,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd July 8, 2001
+.Dd December 5, 2001
.Dt FTPD.CONF 5
.Os
.Sh NAME
@@ -114,7 +114,10 @@ The
.Xr ftpd 8
.Sy STAT
command will return the class settings for the current user as defined by
-.Nm "" .
+.Nm "" ,
+unless the
+.Sy private
+directive is set for the class.
.Pp
Each configuration line may be one of:
.Bl -tag -width 4n
@@ -256,6 +259,33 @@ are replaced with the requested file (sans
.Pp
Conversion directives specified later in the file override earlier
conversions with the same suffix.
+.It Sy denyquick Ar class Op Sy off
+Enforce
+.Xr ftpusers 5
+rules after the
+.Sy USER
+command is received, rather than after the
+.Sy PASS
+command is received.
+Whilst enabling this feature may allow information leakage about
+available accounts (for example, if you allow some users of a
+.Sy REAL
+or
+.Sy CHROOT
+class but not others), it is useful in preventing a denied user
+(such as
+.Sq root )
+from entering their password across an insecure connection.
+This option is
+.Em strongly
+recommended for servers which run an anonymous-only service.
+If
+.Ar class
+is
+.Dq none
+or
+.Sy off
+is given, disable this feature, otherwise enable it.
.It Sy display Ar class Op Ar file
If
.Ar file
@@ -402,7 +432,7 @@ is
.Dq none
or
.Sy off
-is given, disallow passive
+is given, prevent passive
.Sy ( PASV ,
.Sy LPSV ,
and
@@ -422,6 +452,17 @@ If
is
.Dq none
or no arguments are given, disable this.
+.It Sy private Ar class Op Sy off
+If
+.Ar class
+is
+.Dq none
+or
+.Sy off
+is given, do not display class information in the output of the
+.Sy STAT
+command.
+Otherwise, display the information.
.It Sy rateget Ar class Ar rate
Set the maximum get
.Pq Sy RETR
diff --git a/libexec/ftpd/version.h b/libexec/ftpd/version.h
index 9f9c60df7dd..8ff3a975399 100644
--- a/libexec/ftpd/version.h
+++ b/libexec/ftpd/version.h
@@ -1,4 +1,4 @@
-/* $NetBSD: version.h,v 1.36 2001/12/01 10:25:30 lukem Exp $ */
+/* $NetBSD: version.h,v 1.37 2001/12/04 13:54:13 lukem Exp $ */
/*-
* Copyright (c) 1999-2001 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -36,5 +36,5 @@
*/
#ifndef FTPD_VERSION
-#define FTPD_VERSION "NetBSD-ftpd 20011201"
+#define FTPD_VERSION "NetBSD-ftpd 20011205"
#endif