summaryrefslogtreecommitdiffstats
path: root/libexec/ftpd
diff options
context:
space:
mode:
authordavidn <davidn@FreeBSD.org>1997-04-29 12:42:08 +0000
committerdavidn <davidn@FreeBSD.org>1997-04-29 12:42:08 +0000
commit55c9dac45043b0c4199aaca4735cfa1d01b209e5 (patch)
treecc9b7f6114cd7e1018bffafa906e16f8eda8fb09 /libexec/ftpd
parent559a468aae13aa79431fd99e4f039cabcaa507f4 (diff)
downloadFreeBSD-src-55c9dac45043b0c4199aaca4735cfa1d01b209e5.zip
FreeBSD-src-55c9dac45043b0c4199aaca4735cfa1d01b209e5.tar.gz
Adds anon ftp virtual host capability to ftpd, using /etc/ftphosts for
definition of a system's virtual hosts.
Diffstat (limited to 'libexec/ftpd')
-rw-r--r--libexec/ftpd/Makefile4
-rw-r--r--libexec/ftpd/ftpd.851
-rw-r--r--libexec/ftpd/ftpd.c226
-rw-r--r--libexec/ftpd/pathnames.h7
4 files changed, 271 insertions, 17 deletions
diff --git a/libexec/ftpd/Makefile b/libexec/ftpd/Makefile
index 6bb3bdb..49e98d5 100644
--- a/libexec/ftpd/Makefile
+++ b/libexec/ftpd/Makefile
@@ -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}
diff --git a/libexec/ftpd/ftpd.8 b/libexec/ftpd/ftpd.8
index 6bea61c..b3fa6bd 100644
--- a/libexec/ftpd/ftpd.8
+++ b/libexec/ftpd/ftpd.8
@@ -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,
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index 65e5b97..82c10dd 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -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 @@ skip:
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 @@ skip:
* 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 @@ skip:
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 @@ skip:
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);
+ }
}
/*
diff --git a/libexec/ftpd/pathnames.h b/libexec/ftpd/pathnames.h
index 5b36082..d2f8b73 100644
--- a/libexec/ftpd/pathnames.h
+++ b/libexec/ftpd/pathnames.h
@@ -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"
OpenPOWER on IntegriCloud