Adds anon ftp virtual host capability to ftpd, using /etc/ftphosts for

definition of a system's virtual hosts.
This commit is contained in:
David Nugent 1997-04-29 12:42:08 +00:00
parent e9dff5569a
commit ea4e54b942
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=25283
4 changed files with 271 additions and 17 deletions

View File

@ -1,11 +1,11 @@
# @(#)Makefile 8.2 (Berkeley) 4/4/94
# $Id: Makefile,v 1.20 1997/04/23 04:56:39 davidn Exp $
# $Id: Makefile,v 1.21 1997/04/26 12:12:10 davidn Exp $
PROG= ftpd
MAN8= ftpd.8
SRCS= ftpd.c ftpcmd.c logwtmp.c popen.c skey-stuff.c
CFLAGS+=-DSETPROCTITLE -DSKEY -DLOGIN_CAP -Wall
CFLAGS+=-DSETPROCTITLE -DSKEY -DLOGIN_CAP -DVIRTUAL_HOSTING -Wall
LDADD= -lskey -lmd -lcrypt -lutil
DPADD= ${LIBSKEY} ${LIBMD} ${LIBCRYPT} ${LIBUTIL}

View File

@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
.\" $Id: ftpd.8,v 1.16 1997/04/26 12:23:51 davidn Exp $
.\" $Id: ftpd.8,v 1.17 1997/04/27 08:29:21 davidn Exp $
.\"
.Dd April 19, 1994
.Dt FTPD 8
@ -286,8 +286,8 @@ This facility may also be triggered by enabling the boolean "ftp-chroot"
capability in
.Xr login.conf 5 .
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.
This feature is intended as a compromise between a fully anonymous
account and a fully privileged account.
The account should also be set up as for an anonymous account.
.It
If the user name is
@ -357,6 +357,51 @@ can then place files which are to be accessible via the anonymous
account in this directory.
.El
.Pp
If the system has multiple IP addresses,
.Nm ftpd
supports the idea of virtual hosts, which provides the ability to
define multiple anonymous ftp areas, each one allocated to a different
internet address.
The file
.Pa /etc/ftphosts
contains information pertaining to each of the virtual hosts.
Each host is defined on its own line which contains a number of
fields separated by whitespace:
.Bl -tag -offset indent -width hostname
.It hostname
Contains the hostname or IP address of the virtual host.
.It user
Contains a user record in the system password file.
As with normal anonymous ftp, this user's access uid, gid and group
memberships determine file access to the anonymous ftp area.
The anonymous ftp area (to which any user is chrooted on login)
is determined by the home directory defined for the account.
User id and group for any ftp account may be the same as for the
standard ftp user.
.It statfile
File to which all file transfers are logged, which
defaults to
.Pa /var/log/ftpd .
.It welcome
This file is the welcome message displayed before the server ready
prompt.
It defaults to
.Pa /etc/ftpwelcome .
.It motd
This file is displayed after the user logs in.
It defaults to
.Pa /etc/ftpmotd .
.El
.Pp
Defining a virtual host for the primary IP address or hostname
changes the default for ftp logins to that address.
The 'user', 'statfile', 'welcome' and 'motd' fields may be left
blank, or a single hypen '-' used to indicate that the default
value is to be used.
.Pp
As with any anonymous login configuration, due care must be given
to setup and maintenance to guard against security related problems.
.Pp
If compiled with the
.Em INTERNAL_LS
option,

View File

@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ftpd.c,v 1.36 1997/04/26 12:12:10 davidn Exp $
* $Id: ftpd.c,v 1.37 1997/04/27 08:29:21 davidn Exp $
*/
#if 0
@ -151,7 +151,23 @@ off_t byte_count;
#endif
int defumask = CMASK; /* default umask value */
char tmpline[7];
#ifdef VIRTUAL_HOSTING
char *hostname;
char *ftpuser;
static struct ftphost {
struct ftphost *next;
struct in_addr hostaddr;
char *hostname;
char *anonuser;
char *statfile;
char *welcome;
char *loginmsg;
} *thishost, *firsthost;
#else
char hostname[MAXHOSTNAMELEN];
#endif
char remotehost[MAXHOSTNAMELEN];
char *ident = NULL;
@ -214,6 +230,10 @@ char addr_string[20]; /* XXX */
cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
}
#ifdef VIRTUAL_HOSTING
static void inithosts __P((void));
static void selecthost __P((struct in_addr *));
#endif
static void ack __P((char *));
static void myoob __P((int));
static int checkuser __P((char *, char *));
@ -341,6 +361,9 @@ main(argc, argv, envp)
}
}
#ifdef VIRTUAL_HOSTING
inithosts();
#endif
(void) freopen(_PATH_DEVNULL, "w", stderr);
/*
@ -450,6 +473,10 @@ main(argc, argv, envp)
syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
exit(1);
}
#ifdef VIRTUAL_HOSTING
/* select our identity from virtual host table */
selecthost(&ctrl_addr.sin_addr);
#endif
#ifdef IP_TOS
tos = IPTOS_LOWDELAY;
if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
@ -493,7 +520,11 @@ main(argc, argv, envp)
reply(530, "System not available.");
exit(0);
}
#ifdef VIRTUAL_HOSTING
if ((fd = fopen(thishost->welcome, "r")) != NULL) {
#else
if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
#endif
while (fgets(line, sizeof(line), fd) != NULL) {
if ((cp = strchr(line, '\n')) != NULL)
*cp = '\0';
@ -503,7 +534,9 @@ main(argc, argv, envp)
(void) fclose(fd);
/* reply(220,) must follow */
}
#ifndef VIRTUAL_HOSTING
(void) gethostname(hostname, sizeof(hostname));
#endif
reply(220, "%s FTP server (%s) ready.", hostname, version);
(void) setjmp(errcatch);
for (;;)
@ -521,6 +554,147 @@ lostconn(signo)
dologout(-1);
}
#ifdef VIRTUAL_HOSTING
/*
* read in virtual host tables (if they exist)
*/
static void
inithosts()
{
FILE *fp;
char *cp;
struct hostent *hp;
struct ftphost *hrp, *lhrp;
char line[1024];
/*
* Fill in the default host information
*/
if (gethostname(line, sizeof(line)) < 0)
line[0] = '\0';
if ((hrp = malloc(sizeof(struct ftphost))) == NULL ||
(hrp->hostname = strdup(line)) == NULL)
fatal("Ran out of memory.");
memset(&hrp->hostaddr, 0, sizeof hrp->hostaddr);
if ((hp = gethostbyname(hrp->hostname)) != NULL)
(void) memcpy(&hrp->hostaddr,
hp->h_addr_list[0],
sizeof(hrp->hostaddr));
hrp->statfile = _PATH_FTPDSTATFILE;
hrp->welcome = _PATH_FTPWELCOME;
hrp->loginmsg = _PATH_FTPLOGINMESG;
hrp->anonuser = "ftp";
hrp->next = NULL;
thishost = firsthost = lhrp = hrp;
if ((fp = fopen(_PATH_FTPHOSTS, "r")) != NULL) {
while (fgets(line, sizeof(line), fp) != NULL) {
int i;
if ((cp = strchr(line, '\n')) == NULL) {
/* ignore long lines */
while (fgets(line, sizeof(line), fp) != NULL &&
strchr(line, '\n') == NULL)
;
continue;
}
*cp = '\0';
cp = strtok(line, " \t");
/* skip comments and empty lines */
if (cp == NULL || line[0] == '#')
continue;
/* first, try a standard gethostbyname() */
if ((hp = gethostbyname(cp)) == NULL)
continue;
for (hrp = firsthost; hrp != NULL; hrp = hrp->next) {
if (memcmp(&hrp->hostaddr,
hp->h_addr_list[0],
sizeof(hrp->hostaddr)) == 0)
break;
}
if (hrp == NULL) {
if ((hrp = malloc(sizeof(struct ftphost))) == NULL)
continue;
/* defaults */
hrp->statfile = _PATH_FTPDSTATFILE;
hrp->welcome = _PATH_FTPWELCOME;
hrp->loginmsg = _PATH_FTPLOGINMESG;
hrp->anonuser = "ftp";
hrp->next = NULL;
lhrp->next = hrp;
lhrp = hrp;
}
(void) memcpy(&hrp->hostaddr,
hp->h_addr_list[0],
sizeof(hrp->hostaddr));
/*
* determine hostname to use.
* force defined name if it is a valid alias
* otherwise fallback to primary hostname
*/
if ((hp = gethostbyaddr((char*)&hrp->hostaddr,
sizeof(hrp->hostaddr),
AF_INET)) != NULL) {
if (strcmp(cp, hp->h_name) != 0) {
if (hp->h_aliases == NULL)
cp = hp->h_name;
else {
i = 0;
while (hp->h_aliases[i] &&
strcmp(cp, hp->h_aliases[i]) != 0)
++i;
if (hp->h_aliases[i] == NULL)
cp = hp->h_name;
}
}
}
hrp->hostname = strdup(cp);
/* ok, now we now peel off the rest */
i = 0;
while (i < 4 && (cp = strtok(NULL, " \t")) != NULL) {
if (*cp != '-' && (cp = strdup(cp)) != NULL) {
switch (i) {
case 0: /* anon user permissions */
hrp->anonuser = cp;
break;
case 1: /* statistics file */
hrp->statfile = cp;
break;
case 2: /* welcome message */
hrp->welcome = cp;
break;
case 3: /* login message */
hrp->loginmsg = cp;
break;
}
}
++i;
}
}
(void) fclose(fp);
}
}
static void
selecthost(a)
struct in_addr *a;
{
struct ftphost *hrp;
hrp = thishost = firsthost; /* default */
while (hrp != NULL) {
if (memcmp(a, &hrp->hostaddr, sizeof(hrp->hostaddr)) == 0) {
thishost = hrp;
break;
}
hrp = hrp->next;
}
/* setup static variables as appropriate */
hostname = thishost->hostname;
ftpuser = thishost->anonuser;
}
#endif
/*
* Helper function for sgetpwnam().
*/
@ -606,7 +780,11 @@ user(name)
if (checkuser(_PATH_FTPUSERS, "ftp") ||
checkuser(_PATH_FTPUSERS, "anonymous"))
reply(530, "User %s access denied.", name);
#ifdef VIRTUAL_HOSTING
else if ((pw = sgetpwnam(thishost->anonuser)) != NULL) {
#else
else if ((pw = sgetpwnam("ftp")) != NULL) {
#endif
guest = 1;
askpasswd = 1;
reply(331,
@ -820,7 +998,11 @@ pass(passwd)
logged_in = 1;
if (guest && stats && statfd < 0)
#ifdef VIRTUAL_HOSTING
if ((statfd = open(thishost->statfile, O_WRONLY|O_APPEND)) < 0)
#else
if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
#endif
stats = 0;
dochroot =
@ -866,7 +1048,11 @@ pass(passwd)
* Display a login message, if it exists.
* N.B. reply(230,) must follow the message.
*/
#ifdef VIRTUAL_HOSTING
if ((fd = fopen(thishost->loginmsg, "r")) != NULL) {
#else
if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
#endif
char *cp, line[LINE_MAX];
while (fgets(line, sizeof(line), fd) != NULL) {
@ -886,10 +1072,18 @@ pass(passwd)
reply(230, "Guest login ok, access restrictions apply.");
#ifdef SETPROCTITLE
snprintf(proctitle, sizeof(proctitle),
"%s: anonymous/%.*s", remotehost,
sizeof(proctitle) - sizeof(remotehost) -
sizeof(": anonymous/"), passwd);
#ifdef VIRTUAL_HOSTING
if (thishost != firsthost)
snprintf(proctitle, sizeof(proctitle),
"%s: anonymous(%s)/%.*s", remotehost, hostname,
sizeof(proctitle) - sizeof(remotehost) -
sizeof(": anonymous/"), passwd);
else
#endif
snprintf(proctitle, sizeof(proctitle),
"%s: anonymous/%.*s", remotehost,
sizeof(proctitle) - sizeof(remotehost) -
sizeof(": anonymous/"), passwd);
setproctitle("%s", proctitle);
#endif /* SETPROCTITLE */
if (logging)
@ -899,7 +1093,7 @@ pass(passwd)
reply(230, "User %s logged in.", pw->pw_name);
#ifdef SETPROCTITLE
snprintf(proctitle, sizeof(proctitle),
"%s: %s", remotehost, pw->pw_name);
"%s: %s", remotehost, pw->pw_name);
setproctitle("%s", proctitle);
#endif /* SETPROCTITLE */
if (logging)
@ -1695,12 +1889,26 @@ dolog(sin)
(void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
sizeof(remotehost));
#ifdef SETPROCTITLE
snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
#ifdef VIRTUAL_HOSTING
if (thishost != firsthost)
snprintf(proctitle, sizeof(proctitle), "%s: connected (to %s)",
remotehost, hostname);
else
#endif
snprintf(proctitle, sizeof(proctitle), "%s: connected",
remotehost);
setproctitle("%s", proctitle);
#endif /* SETPROCTITLE */
if (logging)
syslog(LOG_INFO, "connection from %s", remotehost);
if (logging) {
#ifdef VIRTUAL_HOSTING
if (thishost != firsthost)
syslog(LOG_INFO, "connection from %s (to %s)",
remotehost, hostname);
else
#endif
syslog(LOG_INFO, "connection from %s", remotehost);
}
}
/*

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
* $Id: pathnames.h,v 1.8 1997/02/22 14:21:29 peter Exp $
* $Id: pathnames.h,v 1.9 1997/04/26 12:12:10 davidn Exp $
*/
#include <paths.h>
@ -39,5 +39,6 @@
#define _PATH_FTPCHROOT "/etc/ftpchroot"
#define _PATH_FTPWELCOME "/etc/ftpwelcome"
#define _PATH_FTPLOGINMESG "/etc/ftpmotd"
#define _PATH_FTPDSTATFILE "/var/log/ftpd"
#define _PATH_LS "/bin/ls"
#define _PATH_FTPHOSTS "/etc/ftphosts"
#define _PATH_FTPDSTATFILE "/var/log/ftpd"
#define _PATH_LS "/bin/ls"