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:
parent
53f1eb8620
commit
8657b576d8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=109893
@ -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
109
libexec/ftpd/ftpchroot.5
Normal 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 .
|
@ -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
|
||||
|
@ -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.",
|
||||
|
Loading…
Reference in New Issue
Block a user