Extend the format of /etc/ftpchroot so an alternative chroot

directory can be specified for a user or a group.

Add the manpage ftpchroot(5) since the file's format has grown
complex enough.

PR:			bin/45327
Portions submitted by:	Hideki SAKAMOTO <sakamoto@hlla.is.tsukuba.ac.jp>
MFC after:		1 week
This commit is contained in:
Yaroslav Tykhiy 2003-01-26 19:02:56 +00:00
parent 53f1eb8620
commit 8657b576d8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=109893
4 changed files with 171 additions and 24 deletions

View File

@ -2,7 +2,7 @@
# $FreeBSD$
PROG= ftpd
MAN= ftpd.8
MAN= ftpd.8 ftpchroot.5
SRCS= ftpd.c ftpcmd.y logwtmp.c popen.c
CFLAGS+=-DSETPROCTITLE -DLOGIN_CAP -DVIRTUAL_HOSTING

109
libexec/ftpd/ftpchroot.5 Normal file
View File

@ -0,0 +1,109 @@
.\" Copyright (c) 2003 FreeBSD Project
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd January 26, 2003
.Dt FTPCHROOT 5
.Os
.Sh NAME
.Nm ftpchroot
.Nd list users and groups subject to FTP access restrictions
.Sh DESCRIPTION
The file
.Nm
is read by
.Xr ftpd 8
at the beginning of an FTP session, after having authenticated the user.
Each line in
.Nm
corresponds to a user or group. If a line in
.Nm
matches the current user or a group he is a member of,
access restrictions will be applied to this
session by changing its root directory with
.Xr chroot 2
to that specified on the line or to the user's login directory.
.Pp
The order of records in
.Nm
is important because the first match will be used.
Fields on each line are separated by tabs or spaces.
.Pp
The first field specifies a user or group name.
If it is prefixed by an
.Qq at
sign,
.Ql \&@ ,
it specifies a group name;
the line will match each user who is a member of this group.
As a special case, a single
.Ql \&@
in this field will match any user.
A username is specified otherwise.
.Pp
The optional second field describes the directory for the user
or each member of the group to be locked up in using
.Xr chroot 2 .
If it is not an absolute pathname, then it will be relative
to the user's login directory.
Be this field omitted, the user's login directory will be used.
.Sh FILES
.Bl -tag -width /etc/ftpchroot -compact
.It Pa /etc/ftpchroot
.El
.Sh EXAMPLES
These lines in
.Nm
will lock up the user
.Qq webuser
and each member of the group
.Qq hostee
in their respective login directories:
.Bd -literal -offset indent
webuser
@hostee
.Ed
.Pp
And this line will lock up the user
.Qq joe
in
.Pa /var/spool/ftp :
.Bd -literal -offset indent
joe /var/spool/ftp
.Ed
.Pp
And finally the following line will lock up every user connecting
through FTP in his respective
.Pa \&~/public_html ,
thus lowering possible impact on the system
from intrinsic insecurity of FTP:
.Bd -literal -offset indent
@ public_html
.Ed
.Sh SEE ALSO
.Xr chroot 2 ,
.Xr group 5 ,
.Xr passwd 5 ,
.Xr ftpd 8 .

View File

@ -358,13 +358,17 @@ If the user name appears in the file
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 directory specified
in this file or to the user's login directory by
.Xr chroot 2
as for an
.Dq anonymous
or
.Dq ftp
account (see next item).
See
.Xr ftpchroot 5
for a detailed description of the format of this file.
This facility may also be triggered by enabling the boolean "ftp-chroot"
capability in
.Xr login.conf 5 .
@ -518,6 +522,7 @@ Default place for session logs.
.Xr key 1 ,
.Xr umask 2 ,
.Xr getusershell 3 ,
.Xr ftpchroot 5 ,
.Xr login.conf 5 ,
.Xr inetd 8 ,
.Xr syslogd 8

View File

@ -239,7 +239,7 @@ static void selecthost(union sockunion *);
static void ack(char *);
static void sigurg(int);
static void myoob(void);
static int checkuser(char *, char *, int);
static int checkuser(char *, char *, int, char **);
static FILE *dataconn(char *, off_t, char *);
static void dolog(struct sockaddr *);
static char *curdir(void);
@ -1000,8 +1000,8 @@ user(char *name)
guest = 0;
if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
if (checkuser(_PATH_FTPUSERS, "ftp", 0) ||
checkuser(_PATH_FTPUSERS, "anonymous", 0))
if (checkuser(_PATH_FTPUSERS, "ftp", 0, NULL) ||
checkuser(_PATH_FTPUSERS, "anonymous", 0, NULL))
reply(530, "User %s access denied.", name);
#ifdef VIRTUAL_HOSTING
else if ((pw = sgetpwnam(thishost->anonuser)) != NULL) {
@ -1032,7 +1032,7 @@ user(char *name)
break;
endusershell();
if (cp == NULL || checkuser(_PATH_FTPUSERS, name, 1)) {
if (cp == NULL || checkuser(_PATH_FTPUSERS, name, 1, NULL)) {
reply(530, "User %s access denied.", name);
if (logging)
syslog(LOG_NOTICE,
@ -1069,10 +1069,12 @@ user(char *name)
}
/*
* Check if a user is in the file "fname"
* Check if a user is in the file "fname",
* return a pointer to a malloc'd string with the rest
* of the matching line in "residue" if not NULL.
*/
static int
checkuser(char *fname, char *name, int pwset)
checkuser(char *fname, char *name, int pwset, char **residue)
{
FILE *fd;
int found = 0;
@ -1106,26 +1108,40 @@ checkuser(char *fname, char *name, int pwset)
int i = 0;
struct group *grp;
if ((grp = getgrnam(p+1)) == NULL)
goto nextline;
/*
* Check user's default group
*/
if (pwset && grp->gr_gid == pw->pw_gid)
if (p[1] == '\0') /* single @ matches anyone */
found = 1;
/*
* Check supplementary groups
*/
while (!found && grp->gr_mem[i])
found = strcmp(name,
grp->gr_mem[i++])
== 0;
else {
if ((grp = getgrnam(p+1)) == NULL)
goto nextline;
/*
* Check user's default group
*/
if (pwset && grp->gr_gid == pw->pw_gid)
found = 1;
/*
* Check supplementary groups
*/
while (!found && grp->gr_mem[i])
found = strcmp(name,
grp->gr_mem[i++])
== 0;
}
}
/*
* Otherwise, just check for username match
*/
else
found = strcmp(p, name) == 0;
/*
* Save the rest of line to "residue" if matched
*/
if (found && residue) {
if ((p = strtok(NULL, "")) != NULL) {
if ((*residue = strdup(p)) == NULL)
fatalerror("Ran out of memory.");
} else
*residue = NULL;
}
nextline:
if (mp)
free(mp);
@ -1331,6 +1347,7 @@ pass(char *passwd)
#ifdef USE_PAM
int e;
#endif
char *chrootdir;
char *xpasswd;
if (logged_in || askpasswd == 0) {
@ -1447,10 +1464,11 @@ pass(char *passwd)
stats = 0;
dochroot =
checkuser(_PATH_FTPCHROOT, pw->pw_name, 1, &chrootdir)
#ifdef LOGIN_CAP /* Allow login.conf configuration as well */
login_getcapbool(lc, "ftp-chroot", 0) ||
|| login_getcapbool(lc, "ftp-chroot", 0)
#endif
checkuser(_PATH_FTPCHROOT, pw->pw_name, 1);
;
if (guest) {
/*
* We MUST do a chdir() after the chroot. Otherwise
@ -1462,10 +1480,25 @@ pass(char *passwd)
goto bad;
}
} else if (dochroot) {
if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
if (chrootdir) { /* chroot dir set in ftpchroot(5) */
if (chrootdir[0] != '/') { /* relative to homedir */
char *p;
asprintf(&p, "%s/%s", pw->pw_dir, chrootdir);
if (p == NULL)
fatalerror("Ran out of memory.");
free(chrootdir);
chrootdir = p;
}
} else
if ((chrootdir = strdup(pw->pw_dir)) == NULL)
fatalerror("Ran out of memory.");
if (chroot(chrootdir) < 0 || chdir("/") < 0) {
reply(550, "Can't change root.");
free(chrootdir);
goto bad;
}
free(chrootdir);
} else if (chdir(pw->pw_dir) < 0) {
if (chdir("/") < 0) {
reply(530, "User %s: can't change directory to %s.",