* implement /etc/ftpd.conf, which adds support for the following features,
controllable on a per class (which is one of: real, chroot, guest, all or none) basis: * on-the-fly execution of a command to build the file (a ``conversion''), providing support for "get dirname.tar" and the like. * displaying the contents of a file when a directory is entered for the first time. * maximum value for timeout (replaces -T). * control usage of CHMOD, DELE, MKD, RMD, UMASK; replacing -DINSECURE_GUEST. * notifying the user of the existance of a files matching a glob pattern when a directory is entered for the first time. * default value for timeout (replaces -t). * default umask (replaces -DGUEST_CMASK and -u). The conversion, display, and notify functionality was based on code by Simon Burge <simonb@telstra.com.au>. * clean up and re-order parts of the man page into subsections. * STAT displays the settings defined for the class of the current user. * bump version from 6.00 to 7.00, because of ftpd.conf. * deprecate -DGUEST_CMASK and -DINSECURE_GUEST in the Makefile, and -t, -T and -u, as ftpd.conf allows finer control of these. * add "nostderr" argument to ftpd_popen(), because you don't want the stderr stream mixing with the stdout stream during a conversion, as this can corrupt the stream.
This commit is contained in:
parent
0a5a273048
commit
31547ec641
@ -1,4 +1,4 @@
|
||||
# $NetBSD: Makefile,v 1.16 1997/04/27 03:21:38 lukem Exp $
|
||||
# $NetBSD: Makefile,v 1.17 1997/06/14 08:43:26 lukem Exp $
|
||||
# @(#)Makefile 8.2 (Berkeley) 4/4/94
|
||||
|
||||
# XXX Work-around a compiler bug for now... can't use -O
|
||||
@ -6,14 +6,9 @@
|
||||
CFLAGS=
|
||||
.endif
|
||||
|
||||
# uncomment this to disallow group directory owners access to uploaded files
|
||||
#CFLAGS+= -DGUEST_CMASK=0777
|
||||
# uncomment this to enable umask, rm and other commands for anonymous users
|
||||
#CFLAGS+= -DINSECURE_GUEST
|
||||
|
||||
PROG= ftpd
|
||||
CFLAGS+=-DHASSETPROCTITLE -DSKEY -Dunix
|
||||
SRCS= ftpd.c ftpcmd.c logwtmp.c popen.c
|
||||
SRCS= conf.c ftpd.c ftpcmd.c logwtmp.c popen.c
|
||||
MAN= ftpd.8
|
||||
CLEANFILES+=ftpcmd.c y.tab.h
|
||||
.PATH: ${.CURDIR}/../../usr.bin/ftp ${.CURDIR}/../../usr.bin/login
|
||||
|
434
libexec/ftpd/conf.c
Normal file
434
libexec/ftpd/conf.c
Normal file
@ -0,0 +1,434 @@
|
||||
/* $NetBSD: conf.c,v 1.1 1997/06/14 08:43:27 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Simon Burge and Luke Mewburn.
|
||||
*
|
||||
* 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 REGENTS 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.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] = "$NetBSD: conf.c,v 1.1 1997/06/14 08:43:27 lukem Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <glob.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stringlist.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "extern.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
struct ftpclass curclass;
|
||||
|
||||
/*
|
||||
* Parse the configuration file, looking for the named class, and
|
||||
* define curclass to contain the appropriate settings.
|
||||
*/
|
||||
void
|
||||
parse_conf(findclass)
|
||||
const char *findclass;
|
||||
{
|
||||
FILE *f;
|
||||
char *buf, *p;
|
||||
size_t len;
|
||||
int none, match, cnum;
|
||||
char *endp;
|
||||
char *class, *word, *arg;
|
||||
char *types, *disable, *convcmd;
|
||||
const char *infile;
|
||||
int line;
|
||||
unsigned int timeout;
|
||||
struct ftpconv *conv, *cnext;
|
||||
|
||||
#define REASSIGN(X,Y) if (X) free(X); (X)=(Y)
|
||||
#define NEXTWORD(W) while ((W = strsep(&buf, " \t")) != NULL && *W == '\0')
|
||||
#define EMPTYSTR(W) (W == NULL || *W == '\0')
|
||||
|
||||
REASSIGN(curclass.classname, findclass);
|
||||
for (conv = curclass.conversions; conv != NULL; conv=cnext) {
|
||||
REASSIGN(conv->suffix, NULL);
|
||||
REASSIGN(conv->types, NULL);
|
||||
REASSIGN(conv->disable, NULL);
|
||||
REASSIGN(conv->command, NULL);
|
||||
cnext = conv->next;
|
||||
free(conv);
|
||||
}
|
||||
curclass.conversions = NULL;
|
||||
REASSIGN(curclass.display, NULL);
|
||||
curclass.modify = 1;
|
||||
curclass.maxtimeout = 7200; /* 2 hours */
|
||||
REASSIGN(curclass.notify, NULL);
|
||||
curclass.timeout = 900; /* 15 minutes */
|
||||
curclass.umask = 027;
|
||||
|
||||
if (strcasecmp(findclass, "guest") == 0) {
|
||||
curclass.umask = 0707;
|
||||
curclass.modify = 0;
|
||||
}
|
||||
|
||||
infile = _PATH_FTPDCONF;
|
||||
if ((f = fopen(infile, "r")) == NULL)
|
||||
return;
|
||||
|
||||
line = 0;
|
||||
while ((buf = fgetln(f, &len)) != NULL) {
|
||||
none = match = 0;
|
||||
line++;
|
||||
if (buf[len - 1] == '\n')
|
||||
buf[--len] = '\0';
|
||||
if ((p = strchr(buf, '#')) != NULL)
|
||||
*p = '\0';
|
||||
if (EMPTYSTR(buf))
|
||||
continue;
|
||||
|
||||
NEXTWORD(word);
|
||||
NEXTWORD(class);
|
||||
NEXTWORD(arg);
|
||||
if (EMPTYSTR(word) || EMPTYSTR(class))
|
||||
continue;
|
||||
if (strcasecmp(class, "none") == 0)
|
||||
none = 1;
|
||||
if (strcasecmp(class, findclass) != 0 &&
|
||||
!none && strcasecmp(class, "all") != 0)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(word, "conversion") == 0) {
|
||||
if (EMPTYSTR(arg)) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: %s requires a suffix",
|
||||
infile, line, word);
|
||||
continue; /* need a suffix */
|
||||
}
|
||||
NEXTWORD(types);
|
||||
NEXTWORD(disable);
|
||||
convcmd = buf;
|
||||
if (convcmd)
|
||||
convcmd += strspn(convcmd, " \t");
|
||||
if (none || EMPTYSTR(types) ||
|
||||
EMPTYSTR(disable) || EMPTYSTR(convcmd)) {
|
||||
types = NULL;
|
||||
disable = NULL;
|
||||
convcmd = NULL;
|
||||
} else {
|
||||
types = strdup(types);
|
||||
disable = strdup(disable);
|
||||
convcmd = strdup(convcmd);
|
||||
}
|
||||
for (conv = curclass.conversions; conv != NULL;
|
||||
conv = conv->next) {
|
||||
if (strcmp(conv->suffix, arg) == 0)
|
||||
break;
|
||||
}
|
||||
if (conv == NULL) {
|
||||
conv = (struct ftpconv *)
|
||||
calloc(1, sizeof(struct ftpconv));
|
||||
if (conv == NULL) {
|
||||
syslog(LOG_WARNING, "can't malloc");
|
||||
continue;
|
||||
}
|
||||
conv->next = curclass.conversions;
|
||||
curclass.conversions = conv;
|
||||
}
|
||||
REASSIGN(conv->suffix, arg);
|
||||
REASSIGN(conv->types, types);
|
||||
REASSIGN(conv->disable, disable);
|
||||
REASSIGN(conv->command, convcmd);
|
||||
} else if (strcasecmp(word, "display") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
arg = NULL;
|
||||
else
|
||||
arg = strdup(arg);
|
||||
REASSIGN(curclass.display, arg);
|
||||
} else if (strcasecmp(word, "maxtimeout") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
timeout = (unsigned int)strtoul(arg, &endp, 10);
|
||||
if (*endp != 0) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: invalid maxtimeout %s",
|
||||
infile, line, arg);
|
||||
continue;
|
||||
}
|
||||
if (timeout < 30) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: maxtimeout %d < 30 seconds",
|
||||
infile, line, timeout);
|
||||
continue;
|
||||
}
|
||||
if (timeout < curclass.timeout) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: maxtimeout %d < timeout (%d)",
|
||||
infile, line, timeout, curclass.timeout);
|
||||
continue;
|
||||
}
|
||||
curclass.maxtimeout = timeout;
|
||||
} else if (strcasecmp(word, "modify") == 0) {
|
||||
if (none ||
|
||||
!EMPTYSTR(arg) && strcasecmp(arg, "off") == 0)
|
||||
curclass.modify = 0;
|
||||
else
|
||||
curclass.modify = 1;
|
||||
} else if (strcasecmp(word, "notify") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
arg = NULL;
|
||||
else
|
||||
arg = strdup(arg);
|
||||
REASSIGN(curclass.notify, arg);
|
||||
} else if (strcasecmp(word, "timeout") == 0) {
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
timeout = (unsigned int)strtoul(arg, &endp, 10);
|
||||
if (*endp != 0) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: invalid timeout %s",
|
||||
infile, line, arg);
|
||||
continue;
|
||||
}
|
||||
if (timeout < 30) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: timeout %d < 30 seconds",
|
||||
infile, line, timeout);
|
||||
continue;
|
||||
}
|
||||
if (timeout > curclass.maxtimeout) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: timeout %d > maxtimeout (%d)",
|
||||
infile, line, timeout, curclass.maxtimeout);
|
||||
continue;
|
||||
}
|
||||
curclass.timeout = timeout;
|
||||
} else if (strcasecmp(word, "umask") == 0) {
|
||||
mode_t umask;
|
||||
|
||||
if (none || EMPTYSTR(arg))
|
||||
continue;
|
||||
umask = (mode_t)strtoul(arg, &endp, 8);
|
||||
if (*endp != 0 || umask > 0777) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: invalid umask %s",
|
||||
infile, line, arg);
|
||||
continue;
|
||||
}
|
||||
curclass.umask = umask;
|
||||
} else {
|
||||
syslog(LOG_WARNING,
|
||||
"%s line %d: unknown directive '%s'",
|
||||
infile, line, word);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#undef REASSIGN
|
||||
#undef NEXTWORD
|
||||
#undef EMPTYSTR
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/*
|
||||
* Show file listed in curclass.display first time in, and list all the
|
||||
* files named in curclass.notify in the current directory. Send back
|
||||
* responses with the "reply" prefix.
|
||||
*/
|
||||
void
|
||||
show_chdir_messages(code)
|
||||
int code;
|
||||
{
|
||||
static StringList *slist = NULL;
|
||||
|
||||
struct stat st;
|
||||
struct tm *t;
|
||||
glob_t gl;
|
||||
time_t now, then;
|
||||
int age;
|
||||
char cwd[MAXPATHLEN + 1];
|
||||
char line[BUFSIZ];
|
||||
char *cp, **rlist;
|
||||
FILE *f;
|
||||
|
||||
/* Setup list for directory cache */
|
||||
if (slist == NULL)
|
||||
slist = sl_init();
|
||||
|
||||
/* Check if this directory has already been visited */
|
||||
if (getcwd(cwd, sizeof(cwd) - 1) == NULL) {
|
||||
syslog(LOG_WARNING, "show_chdir_messages: can't malloc");
|
||||
return;
|
||||
}
|
||||
if (sl_find(slist, cwd) != NULL)
|
||||
return;
|
||||
|
||||
if ((cp = strdup(cwd)) == NULL) {
|
||||
syslog(LOG_WARNING, "show_chdir_messages: can't strdup");
|
||||
return;
|
||||
}
|
||||
sl_add(slist, cp);
|
||||
|
||||
/* First check for a display file */
|
||||
if (curclass.display != NULL && curclass.display[0] &&
|
||||
(f = fopen(curclass.display, "r")) != NULL) {
|
||||
while (fgets(line, BUFSIZ, f)) {
|
||||
if ((cp = strchr(line, '\n')) != NULL)
|
||||
*cp = '\0';
|
||||
lreply(code, "%s", line);
|
||||
}
|
||||
fclose(f);
|
||||
lreply(code, "");
|
||||
}
|
||||
|
||||
/* Now see if there are any notify files */
|
||||
if (curclass.notify == NULL || curclass.notify[0] == '\0')
|
||||
return;
|
||||
|
||||
if (glob(curclass.notify, 0, NULL, &gl) != 0 || gl.gl_matchc == 0)
|
||||
return;
|
||||
time(&now);
|
||||
for (rlist = gl.gl_pathv; *rlist != NULL; rlist++) {
|
||||
if (stat(*rlist, &st) != 0)
|
||||
continue;
|
||||
if ((st.st_mode & S_IFMT) != S_IFREG)
|
||||
continue;
|
||||
then = st.st_mtime;
|
||||
lreply(code, "Please read the file %s", *rlist);
|
||||
t = localtime(&now);
|
||||
age = 365 * t->tm_year + t->tm_yday;
|
||||
t = localtime(&then);
|
||||
age -= 365 * t->tm_year + t->tm_yday;
|
||||
lreply(code, " it was last modified on %.24s - %d day%s ago",
|
||||
ctime(&then), age, age == 1 ? "" : "s");
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find s2 at the end of s1. If found, return a string up and up (but
|
||||
* not including) s2, otherwise returns NULL.
|
||||
*/
|
||||
static char *
|
||||
strend(s1, s2)
|
||||
char *s1, *s2;
|
||||
{
|
||||
static char buf[MAXPATHLEN + 1];
|
||||
|
||||
char *start;
|
||||
size_t l1, l2;
|
||||
|
||||
l1 = strlen(s1);
|
||||
l2 = strlen(s2);
|
||||
|
||||
if (l2 >= l1)
|
||||
return(NULL);
|
||||
|
||||
strncpy(buf, s1, MAXPATHLEN);
|
||||
start = buf + (l1 - l2);
|
||||
|
||||
if (strcmp(start, s2) == 0) {
|
||||
*start = '\0';
|
||||
return(buf);
|
||||
} else
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
filetypematch(types, mode)
|
||||
char *types;
|
||||
int mode;
|
||||
{
|
||||
for ( ; types[0] != '\0'; types++)
|
||||
switch (*types) {
|
||||
case 'd':
|
||||
if (S_ISDIR(mode))
|
||||
return(1);
|
||||
break;
|
||||
case 'f':
|
||||
if (S_ISREG(mode))
|
||||
return(1);
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for a conversion. If we succeed, return a pointer to the
|
||||
* command to execute for the conversion.
|
||||
*
|
||||
* The command is stored in a static array so there's no memory
|
||||
* leak problems, and not too much to change in ftpd.c. This
|
||||
* routine doesn't need to be re-entrant unless we start using a
|
||||
* multi-threaded ftpd, and that's not likely for a while...
|
||||
*/
|
||||
char *
|
||||
do_conversion(fname)
|
||||
const char *fname;
|
||||
{
|
||||
static char cmd[LINE_MAX];
|
||||
|
||||
struct ftpconv *cp;
|
||||
struct stat st;
|
||||
int o_errno;
|
||||
char *base;
|
||||
|
||||
o_errno = errno;
|
||||
for (cp = curclass.conversions; cp != NULL; cp = cp->next) {
|
||||
if ((base = strend(fname, cp->suffix)) == NULL)
|
||||
continue;
|
||||
if (cp->suffix == NULL || cp->types == NULL ||
|
||||
cp->command == NULL)
|
||||
continue;
|
||||
/* Is it enabled? */
|
||||
if (strcmp(cp->disable, ".") != 0 &&
|
||||
stat(cp->disable, &st) == 0)
|
||||
continue;
|
||||
/* Does the base exist? */
|
||||
if (stat(base, &st) < 0)
|
||||
continue;
|
||||
/* Is the file type ok */
|
||||
if (!filetypematch(cp->types, st.st_mode))
|
||||
continue;
|
||||
break; /* "We have a winner!" */
|
||||
}
|
||||
|
||||
/* If we got through the list, no conversion */
|
||||
if (cp == NULL) {
|
||||
errno = o_errno;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
snprintf(cmd, LINE_MAX, cp->command, base);
|
||||
syslog(LOG_INFO, "get command is: %s", cmd);
|
||||
return(cmd);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: extern.h,v 1.2 1995/04/11 02:44:49 cgd Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.3 1997/06/14 08:43:28 lukem Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
@ -39,15 +39,17 @@ void blkfree __P((char **));
|
||||
char **copyblk __P((char **));
|
||||
void cwd __P((char *));
|
||||
void delete __P((char *));
|
||||
char *do_conversion __P((const char *));
|
||||
void dologout __P((int));
|
||||
void fatal __P((char *));
|
||||
int ftpd_pclose __P((FILE *));
|
||||
FILE *ftpd_popen __P((char *, char *));
|
||||
FILE *ftpd_popen __P((char *, char *, int));
|
||||
char *getline __P((char *, int, FILE *));
|
||||
void logwtmp __P((char *, char *, char *));
|
||||
void lreply __P((int, const char *, ...));
|
||||
void makedir __P((char *));
|
||||
void nack __P((char *));
|
||||
void parse_conf __P((const char *));
|
||||
void pass __P((char *));
|
||||
void passive __P((void));
|
||||
void perror_reply __P((int, char *));
|
||||
@ -58,10 +60,34 @@ char *renamefrom __P((char *));
|
||||
void reply __P((int, const char *, ...));
|
||||
void retrieve __P((char *, char *));
|
||||
void send_file_list __P((char *));
|
||||
void setproctitle __P((const char *, ...));
|
||||
void show_chdir_messages __P((int));
|
||||
void statcmd __P((void));
|
||||
void statfilecmd __P((char *));
|
||||
void store __P((char *, char *, int));
|
||||
void upper __P((char *));
|
||||
void user __P((char *));
|
||||
void yyerror __P((char *));
|
||||
|
||||
|
||||
#define CLASS_CHROOT "chroot"
|
||||
#define CLASS_GUEST "guest"
|
||||
#define CLASS_REAL "real"
|
||||
|
||||
struct ftpconv {
|
||||
struct ftpconv *next;
|
||||
const char *suffix; /* Suffix of requested name */
|
||||
const char *types; /* Valid file types */
|
||||
const char *disable; /* File to disable conversions */
|
||||
const char *command; /* Command to do the conversion */
|
||||
};
|
||||
|
||||
struct ftpclass {
|
||||
const char *classname; /* Current class */
|
||||
struct ftpconv *conversions; /* List of conversions */
|
||||
const char *display; /* Files to display upon chdir */
|
||||
unsigned int maxtimeout; /* Maximum permitted timeout */
|
||||
int modify; /* Allow dele, mkd, rmd, umask, chmod */
|
||||
const char *notify; /* Files to notify about upon chdir */
|
||||
unsigned int timeout; /* Default timeout */
|
||||
mode_t umask; /* Umask to use */
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ftpcmd.y,v 1.11 1997/05/23 22:09:48 cjs Exp $ */
|
||||
/* $NetBSD: ftpcmd.y,v 1.12 1997/06/14 08:43:29 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1985, 1988, 1993, 1994
|
||||
@ -46,7 +46,7 @@
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94";
|
||||
#else
|
||||
static char rcsid[] = "$NetBSD: ftpcmd.y,v 1.11 1997/05/23 22:09:48 cjs Exp $";
|
||||
static char rcsid[] = "$NetBSD: ftpcmd.y,v 1.12 1997/06/14 08:43:29 lukem Exp $";
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
@ -80,14 +80,13 @@ extern int logging;
|
||||
extern int type;
|
||||
extern int form;
|
||||
extern int debug;
|
||||
extern int timeout;
|
||||
extern int maxtimeout;
|
||||
extern int pdata;
|
||||
extern char hostname[], remotehost[];
|
||||
extern char proctitle[];
|
||||
extern int usedefault;
|
||||
extern int transflag;
|
||||
extern char tmpline[];
|
||||
extern struct ftpclass curclass;
|
||||
|
||||
off_t restart_point;
|
||||
|
||||
@ -125,7 +124,7 @@ char *fromname;
|
||||
%token <s> STRING
|
||||
%token <i> NUMBER
|
||||
|
||||
%type <i> check_login check_login_noguest octal_number byte_size
|
||||
%type <i> check_login check_modify octal_number byte_size
|
||||
%type <i> struct_code mode_code type_code form_code
|
||||
%type <s> pathstring pathname password username
|
||||
|
||||
@ -290,7 +289,7 @@ cmd
|
||||
{
|
||||
statcmd();
|
||||
}
|
||||
| DELE check_login_noguest SP pathname CRLF
|
||||
| DELE check_modify SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
delete($4);
|
||||
@ -347,14 +346,14 @@ cmd
|
||||
{
|
||||
reply(200, "NOOP command successful.");
|
||||
}
|
||||
| MKD check_login_noguest SP pathname CRLF
|
||||
| MKD check_modify SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
makedir($4);
|
||||
if ($4 != NULL)
|
||||
free($4);
|
||||
}
|
||||
| RMD check_login_noguest SP pathname CRLF
|
||||
| RMD check_modify SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
removedir($4);
|
||||
@ -389,7 +388,7 @@ cmd
|
||||
reply(200, "Current UMASK is %03o", oldmask);
|
||||
}
|
||||
}
|
||||
| SITE SP UMASK check_login_noguest SP octal_number CRLF
|
||||
| SITE SP UMASK check_modify SP octal_number CRLF
|
||||
{
|
||||
int oldmask;
|
||||
|
||||
@ -404,7 +403,7 @@ cmd
|
||||
}
|
||||
}
|
||||
}
|
||||
| SITE SP CHMOD check_login_noguest SP octal_number SP pathname CRLF
|
||||
| SITE SP CHMOD check_modify SP octal_number SP pathname CRLF
|
||||
{
|
||||
if ($4 && ($8 != NULL)) {
|
||||
if ($6 > 0777)
|
||||
@ -422,20 +421,20 @@ cmd
|
||||
{
|
||||
reply(200,
|
||||
"Current IDLE time limit is %d seconds; max %d",
|
||||
timeout, maxtimeout);
|
||||
curclass.timeout, curclass.maxtimeout);
|
||||
}
|
||||
| SITE SP IDLE SP NUMBER CRLF
|
||||
{
|
||||
if ($5 < 30 || $5 > maxtimeout) {
|
||||
if ($5 < 30 || $5 > curclass.maxtimeout) {
|
||||
reply(501,
|
||||
"Maximum IDLE time must be between 30 and %d seconds",
|
||||
maxtimeout);
|
||||
"IDLE time limit must be between 30 and %d seconds",
|
||||
curclass.maxtimeout);
|
||||
} else {
|
||||
timeout = $5;
|
||||
(void) alarm((unsigned) timeout);
|
||||
curclass.timeout = $5;
|
||||
(void) alarm(curclass.timeout);
|
||||
reply(200,
|
||||
"Maximum IDLE time set to %d seconds",
|
||||
timeout);
|
||||
"IDLE time limit set to %d seconds",
|
||||
curclass.timeout);
|
||||
}
|
||||
}
|
||||
| STOU check_login SP pathname CRLF
|
||||
@ -730,18 +729,16 @@ check_login
|
||||
}
|
||||
}
|
||||
;
|
||||
check_login_noguest
|
||||
check_modify
|
||||
: /* empty */
|
||||
{
|
||||
if (logged_in) {
|
||||
#ifndef INSECURE_GUEST
|
||||
if (guest) {
|
||||
reply(502,
|
||||
"Guest users may not use this command.");
|
||||
$$ = 0;
|
||||
if (curclass.modify) {
|
||||
$$ = 1;
|
||||
} else
|
||||
#endif
|
||||
$$ = 1;
|
||||
reply(502,
|
||||
"No permission to use this command.");
|
||||
$$ = 0;
|
||||
} else {
|
||||
reply(530, "Please login with USER and PASS.");
|
||||
$$ = 0;
|
||||
@ -936,10 +933,11 @@ toolong(signo)
|
||||
{
|
||||
|
||||
reply(421,
|
||||
"Timeout (%d seconds): closing control connection.", timeout);
|
||||
"Timeout (%d seconds): closing control connection.",
|
||||
curclass.timeout);
|
||||
if (logging)
|
||||
syslog(LOG_INFO, "User %s timed out after %d seconds",
|
||||
(pw ? pw -> pw_name : "unknown"), timeout);
|
||||
(pw ? pw -> pw_name : "unknown"), curclass.timeout);
|
||||
dologout(1);
|
||||
}
|
||||
|
||||
@ -957,7 +955,7 @@ yylex()
|
||||
|
||||
case CMD:
|
||||
(void) signal(SIGALRM, toolong);
|
||||
(void) alarm((unsigned) timeout);
|
||||
(void) alarm(curclass.timeout);
|
||||
if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
|
||||
reply(221, "You could at least say goodbye.");
|
||||
dologout(0);
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: ftpd.8,v 1.13 1997/05/23 22:09:51 cjs Exp $
|
||||
.\" $NetBSD: ftpd.8,v 1.14 1997/06/14 08:43:30 lukem Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1985, 1988, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -33,9 +33,9 @@
|
||||
.\"
|
||||
.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
|
||||
.\"
|
||||
.Dd April 19, 1994
|
||||
.Dd June 10, 1997
|
||||
.Dt FTPD 8
|
||||
.Os BSD 4.2
|
||||
.Os NetBSD
|
||||
.Sh NAME
|
||||
.Nm ftpd
|
||||
.Nd
|
||||
@ -44,9 +44,6 @@ Internet File Transfer Protocol server
|
||||
.Nm
|
||||
.Op Fl dl
|
||||
.Op Fl a Ar anondir
|
||||
.Op Fl T Ar maxtimeout
|
||||
.Op Fl t Ar timeout
|
||||
.Op Fl u Ar umask
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is the
|
||||
@ -62,31 +59,19 @@ service specification; see
|
||||
Available options:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl a
|
||||
Define the directory to which we chroot for anonymous logins.
|
||||
Define the directory to
|
||||
.Xr chroot 2
|
||||
into for anonymous logins.
|
||||
Default is the home directory for the ftp user.
|
||||
.It Fl d
|
||||
Debugging information is written to the syslog using LOG_FTP.
|
||||
.It Fl l
|
||||
Each successful and failed
|
||||
Each successful and failed
|
||||
.Xr ftp 1
|
||||
session is logged using syslog with a facility of LOG_FTP.
|
||||
If this option is specified twice, the retrieve (get), store (put), append,
|
||||
delete, make directory, remove directory and rename operations and
|
||||
their filename arguments are also logged.
|
||||
.It Fl T
|
||||
A client may also request a different timeout period;
|
||||
the maximum period allowed may be set to
|
||||
.Ar timeout
|
||||
seconds with the
|
||||
.Fl T
|
||||
option.
|
||||
The default limit is 2 hours.
|
||||
.It Fl t
|
||||
The inactivity timeout period is set to
|
||||
.Ar timeout
|
||||
seconds (the default is 15 minutes).
|
||||
.It Fl u
|
||||
Sets the default umask. Must be in octal form, e.g. "002"
|
||||
.El
|
||||
.Pp
|
||||
The file
|
||||
@ -99,7 +84,7 @@ If the file
|
||||
.Pa /etc/ftpwelcome
|
||||
exists,
|
||||
.Nm
|
||||
prints it before issuing the
|
||||
prints it before issuing the
|
||||
.Dq ready
|
||||
message.
|
||||
If the file
|
||||
@ -108,29 +93,6 @@ exists,
|
||||
.Nm
|
||||
prints it after a successful login.
|
||||
.Pp
|
||||
The
|
||||
.Pa /etc/ftpusers
|
||||
file is used to determine which users may use ftp.
|
||||
If the file does not exist, all users are denied access. If it
|
||||
does exist, each line is a a comment starting with ``#'' or a
|
||||
glob pattern that uses the same syntax as /bin/sh, optionally
|
||||
followed by whitespace and ``allow'' or ``deny''.
|
||||
Each glob pattern is compared in turn against the username
|
||||
until a match is found. If the word following the matched glob
|
||||
pattern is ``allow'' the user is granted access; if the word is
|
||||
anything else, or nothing at all, the user is denied access.
|
||||
(No further comparisons are attempted after the first successful match.)
|
||||
If no match is found, the user is granted access.
|
||||
This syntax is backward-compatable with the old syntax.
|
||||
.Pp
|
||||
|
||||
If a user requests a guest login, the ftp server checks to see that
|
||||
both ``anonymous'' and ``ftp'' have access, so if you deny all
|
||||
users by default, you will need to add both ``anonymous allow''
|
||||
and ``ftp allow'' to
|
||||
.Pa /etc/ftpusers
|
||||
in order to allow guest logins.
|
||||
.Pp
|
||||
The ftp server currently supports the following ftp requests.
|
||||
The case of the requests is ignored.
|
||||
.Bl -column "Request" -offset indent
|
||||
@ -183,10 +145,10 @@ SITE request.
|
||||
.Pp
|
||||
.Bl -column Request -offset indent
|
||||
.It Sy Request Ta Sy Description
|
||||
.It UMASK Ta change umask, e.g. ``SITE UMASK 002''
|
||||
.It IDLE Ta set idle-timer, e.g. ``SITE IDLE 60''
|
||||
.It CHMOD Ta change mode of a file, e.g. ``SITE CHMOD 755 filename''
|
||||
.It HELP Ta give help information.
|
||||
.It CHMOD Ta "change mode of a file, e.g. ``SITE CHMOD 755 filename''"
|
||||
.It HELP Ta "give help information."
|
||||
.It IDLE Ta "set idle-timer, e.g. ``SITE IDLE 60''"
|
||||
.It UMASK Ta "change umask, e.g. ``SITE UMASK 002''"
|
||||
.El
|
||||
.Pp
|
||||
The remaining ftp requests specified in Internet RFC 959
|
||||
@ -212,9 +174,9 @@ conventions used by
|
||||
.Xr csh 1 .
|
||||
This allows users to utilize the metacharacters
|
||||
.Dq Li \&*?[]{}~ .
|
||||
.Pp
|
||||
.Ss User authentication
|
||||
.Nm
|
||||
authenticates users according to five rules.
|
||||
authenticates users according to five rules.
|
||||
.Pp
|
||||
.Bl -enum -offset indent
|
||||
.It
|
||||
@ -234,9 +196,9 @@ Bellcore.
|
||||
.It
|
||||
The login name must be allowed based on the information in
|
||||
.Pa /etc/ftpusers
|
||||
(see above).
|
||||
(see below).
|
||||
.It
|
||||
The user must have a standard shell returned by
|
||||
The user must have a standard shell returned by
|
||||
.Xr getusershell 3 .
|
||||
.It
|
||||
If the user name appears in the file
|
||||
@ -248,7 +210,7 @@ as for an
|
||||
or
|
||||
.Dq ftp
|
||||
account (see next item). However, the user must still supply a password.
|
||||
This feature is intended as a compromise between a fully anonymous 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
|
||||
@ -263,21 +225,221 @@ file (user
|
||||
In this case the user is allowed
|
||||
to log in by specifying any password (by convention an email address for
|
||||
the user should be used as the password).
|
||||
.El
|
||||
.Pp
|
||||
In the last case,
|
||||
.Nm
|
||||
takes special measures to restrict the client's access privileges.
|
||||
The server disables the MKD, XMKD, RMD, XRMD, DELE, SITE UMASK, and
|
||||
SITE CHMOD commands, sets the umask to 0707, and performs a
|
||||
The server performs a
|
||||
.Xr chroot 2
|
||||
to the home directory of the
|
||||
.Dq ftp
|
||||
user.
|
||||
If other restrictions are required (such as disabling of certain
|
||||
commands and the setting of a specific umask), then appropriate
|
||||
entries in
|
||||
.Pa /etc/ftpd.conf
|
||||
are required.
|
||||
.El
|
||||
.Ss /etc/ftpusers
|
||||
The file
|
||||
.Pa /etc/ftpusers
|
||||
is used to determine which users may use ftp.
|
||||
If the file does not exist, all users are denied access. If it
|
||||
does exist, each line is a a comment starting with
|
||||
.Dq #
|
||||
or a glob pattern that uses the same syntax as /bin/sh,
|
||||
optionally followed by whitespace and
|
||||
.Dq allow
|
||||
or
|
||||
.Dq deny .
|
||||
Each glob pattern is compared in turn against the username
|
||||
until a match is found. If the word following the matched glob
|
||||
pattern is
|
||||
.Dq allow
|
||||
the user is granted access; if the word is
|
||||
anything else, or nothing at all, the user is denied access.
|
||||
(No further comparisons are attempted after the first successful match.)
|
||||
If no match is found, the user is granted access.
|
||||
This syntax is backward-compatable with the old syntax.
|
||||
.Pp
|
||||
If a user requests a guest login, the ftp server checks to see that
|
||||
both
|
||||
.Dq anonymous
|
||||
and
|
||||
.Dq ftp
|
||||
have access, so if you deny all users by default, you will need to add both
|
||||
.Dq "anonymous allow"
|
||||
and
|
||||
.Dq "ftp allow"
|
||||
to
|
||||
.Pa /etc/ftpusers
|
||||
in order to allow guest logins.
|
||||
.Ss /etc/ftpd.conf
|
||||
The file
|
||||
.Pa /etc/ftpd.conf
|
||||
is used to configure various options.
|
||||
Each line starting with a
|
||||
.Dq #
|
||||
is a comment (and ignored), and all other non-blank lines are treated
|
||||
as configuration directives.
|
||||
.Pp
|
||||
Each configuration line may be one of:
|
||||
.Bl -tag -width 4n
|
||||
.It Xo Sy conversion Ar class
|
||||
.Ar suffix Op Ar "type disable command"
|
||||
.Xc
|
||||
Define an automatic in-line file conversion.
|
||||
If a file to retrieve ends in
|
||||
.Ar suffix ,
|
||||
and a real file (sans
|
||||
.Ar suffix )
|
||||
exists, then the output of
|
||||
.Ar command
|
||||
is returned instead of the contents of the file.
|
||||
.Pp
|
||||
.Bl -tag -width "disable" -offset indent
|
||||
.It Ar suffix
|
||||
The suffix to initiate the conversion.
|
||||
.It Ar type
|
||||
A list of valid filetypes for the conversion.
|
||||
Valid types are:
|
||||
.Sq f
|
||||
(file), and
|
||||
.Sq d
|
||||
(directory).
|
||||
.It Ar disable
|
||||
The name of file that will prevent conversion if it exists.
|
||||
A filename of
|
||||
.Pa \&.
|
||||
will prevent this disabling action.
|
||||
.It Ar command
|
||||
The command to run for the conversion.
|
||||
The first word should be the full path name
|
||||
of the command, as
|
||||
.Xr execv 3
|
||||
is used to execute the command.
|
||||
The first instance of
|
||||
.Sq %s
|
||||
in
|
||||
.Ar command
|
||||
is replaced with the requested file (sans
|
||||
.Ar suffix ) .
|
||||
.El
|
||||
.Pp
|
||||
Conversion directives specified later in the file override earlier
|
||||
conversions with the same suffix. The order in which conversions is
|
||||
matched is the reverse of their order in the file (i.e., a LIFO).
|
||||
.It Sy display Ar class Op Ar file
|
||||
If
|
||||
.Ar file
|
||||
isn't given or
|
||||
.Ar class
|
||||
is
|
||||
.Dq none ,
|
||||
disable this.
|
||||
Otherwise, each time the user enters a new directory, check if
|
||||
.Ar file
|
||||
exists, and if so, display its contents to the user.
|
||||
.It Sy maxtimeout Ar class Ar time
|
||||
Set the maximum timeout period that a client may request,
|
||||
defaulting to two hours.
|
||||
This cannot be lesser than 30 seconds, or the value for
|
||||
.Sy timeout .
|
||||
Ignored if class is
|
||||
.Dq none
|
||||
or
|
||||
.Ar time
|
||||
isn't specified.
|
||||
.It Sy modify Ar class Op Sy off
|
||||
If class is
|
||||
.Dq none
|
||||
or
|
||||
.Sy off
|
||||
is given, disable the following commands:
|
||||
CHMOD, DELE, MKD, RMD, and UMASK.
|
||||
Otherwise, enable them.
|
||||
.It Sy notify Ar class Op Ar fileglob
|
||||
If
|
||||
.Ar fileglob
|
||||
isn't given or
|
||||
.Ar class
|
||||
is
|
||||
.Dq none ,
|
||||
disable this.
|
||||
Otherwise, each time the user enters a new directory,
|
||||
notify the user of any files matching
|
||||
.Ar fileglob .
|
||||
.It Sy timeout Ar class Ar time
|
||||
Set the inactivity timeout period.
|
||||
(the default is fifteen minutes).
|
||||
This cannot be lesser than 30 seconds, or greater than the value for
|
||||
.Sy maxtimeout .
|
||||
Ignored if class is
|
||||
.Dq none
|
||||
or
|
||||
.Ar time
|
||||
isn't specified.
|
||||
.It Sy umask Ar class Ar umaskval
|
||||
Set the umask to
|
||||
.Ar umaskval .
|
||||
Ignored if class is
|
||||
.Dq none
|
||||
or
|
||||
.Ar umaskval
|
||||
isn't specified.
|
||||
.El
|
||||
.Pp
|
||||
In any configuration line,
|
||||
.Ar class
|
||||
is one of:
|
||||
.Bl -tag -width "chroot" -compact -offset indent
|
||||
.It Sy real
|
||||
Normal user logins.
|
||||
.It Sy chroot
|
||||
Users that have been
|
||||
.Xr chroot 2 ed.
|
||||
.It Sy guest
|
||||
.Dq anonymous
|
||||
and
|
||||
.Dq ftp
|
||||
users.
|
||||
.It Sy all
|
||||
Matches any class.
|
||||
.It Sy none
|
||||
Matches no class.
|
||||
.El
|
||||
.Pp
|
||||
The following defaults are used:
|
||||
.Bd -literal -offset indent -compact
|
||||
display none
|
||||
maxtimeout all 7200 # 2 hours
|
||||
modify all
|
||||
modify guest off
|
||||
notify none
|
||||
timeout all 900 # 15 minutes
|
||||
umask all 027
|
||||
umask guest 0707
|
||||
.Ed
|
||||
.Pp
|
||||
Directives that appear later in the file override settings by previous
|
||||
directives. This allows
|
||||
.Sq wildcard
|
||||
entries to define defaults, and then have class-specific overrides.
|
||||
.Pp
|
||||
The
|
||||
STAT
|
||||
command will return the class settings for the current user as defined by
|
||||
.Pa /etc/ftpd.conf .
|
||||
.Ss Setting up a restricted ftp subtree
|
||||
In order that system security is not breached, it is recommended
|
||||
that the
|
||||
subtrees for the
|
||||
.Dq ftp
|
||||
subtree be constructed with care, following these rules:
|
||||
and
|
||||
.Dq chroot
|
||||
accounts be constructed with care, following these rules
|
||||
(replace
|
||||
.Dq ftp
|
||||
in the following directory names
|
||||
with the appropriate account name for
|
||||
.Sq chroot
|
||||
users):
|
||||
.Bl -tag -width "~ftp/incoming" -offset indent
|
||||
.It Pa ~ftp
|
||||
Make the home directory owned by
|
||||
@ -303,7 +465,7 @@ and
|
||||
.Pa group
|
||||
(see
|
||||
.Xr group 5 )
|
||||
must be present for the
|
||||
must be present for the
|
||||
.Xr ls
|
||||
command to be able to produce owner names rather than numbers.
|
||||
The password field in
|
||||
@ -321,30 +483,34 @@ and be writable only by them (mode 755 or 775). They should
|
||||
be owned or writable by ftp or its group.
|
||||
.It Pa ~ftp/incoming
|
||||
This directory is where anonymous users place files they upload.
|
||||
The owners should be the user ``ftp'' and an appropriate group.
|
||||
The owners should be the user
|
||||
.Dq ftp
|
||||
and an appropriate group.
|
||||
Members of this group will be the only users with access to these
|
||||
files after they have been uploaded; these should be people who
|
||||
know how to deal with them appropriately. If you wish anonymous
|
||||
ftp users to be able to see the names of the files in this directory
|
||||
the permissions should be 770, otherwise they should be 370.
|
||||
.Pp
|
||||
Anonymous users will be able to upload files files to this directory,
|
||||
Anonymous users will be able to upload files to this directory,
|
||||
but they will not be able to download them, delete them, or overwrite
|
||||
them, due to the umask and disabling of the commands mentioned
|
||||
above.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/ftpwelcome -compact
|
||||
.It Pa /etc/ftpusers
|
||||
List of unwelcome/restricted users.
|
||||
.It Pa /etc/ftpchroot
|
||||
List of normal users who should be chroot'd.
|
||||
.It Pa /etc/ftpd.conf
|
||||
Configure file conversions and other settings.
|
||||
.It Pa /etc/ftpusers
|
||||
List of unwelcome/restricted users.
|
||||
.It Pa /etc/ftpwelcome
|
||||
Welcome notice.
|
||||
.It Pa /etc/motd
|
||||
Welcome notice after login.
|
||||
.It Pa /etc/nologin
|
||||
Displayed and access refused.
|
||||
If it exists, displayed and access is refused.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr ftp 1 ,
|
||||
@ -358,8 +524,21 @@ an effective user id of the logged in user, reverting to
|
||||
the super-user only when binding addresses to sockets. The
|
||||
possible security holes have been extensively
|
||||
scrutinized, but are possibly incomplete.
|
||||
.Pp
|
||||
The feedback to the client is inadequate in the case of an
|
||||
error that occurs during a retrieval that uses a
|
||||
.Dq conversion
|
||||
command
|
||||
(refer to
|
||||
.Sx /etc/ftpd.conf ) .
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Bx 4.2 .
|
||||
.Pp
|
||||
The
|
||||
.Pa /etc/ftpd.conf
|
||||
functionality was implemented in
|
||||
.Nx 1.3
|
||||
by Luke Mewburn, based on work by Simon Burge.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ftpd.c,v 1.23 1997/05/29 10:31:48 lukem Exp $ */
|
||||
/* $NetBSD: ftpd.c,v 1.24 1997/06/14 08:43:31 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
|
||||
@ -43,7 +43,7 @@ static char copyright[] =
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
|
||||
#else
|
||||
static char rcsid[] = "$NetBSD: ftpd.c,v 1.23 1997/05/29 10:31:48 lukem Exp $";
|
||||
static char rcsid[] = "$NetBSD: ftpd.c,v 1.24 1997/06/14 08:43:31 lukem Exp $";
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
@ -84,8 +84,8 @@ static char rcsid[] = "$NetBSD: ftpd.c,v 1.23 1997/05/29 10:31:48 lukem Exp $";
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pathnames.h"
|
||||
#include "extern.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
@ -93,7 +93,7 @@ static char rcsid[] = "$NetBSD: ftpd.c,v 1.23 1997/05/29 10:31:48 lukem Exp $";
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
|
||||
static char version[] = "Version 6.00";
|
||||
static char version[] = "Version 7.00";
|
||||
|
||||
extern off_t restart_point;
|
||||
extern char cbuf[];
|
||||
@ -109,8 +109,6 @@ jmp_buf errcatch, urgcatch;
|
||||
int logged_in;
|
||||
struct passwd *pw;
|
||||
int debug;
|
||||
int timeout = 900; /* timeout after 15 minutes of inactivity */
|
||||
int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
|
||||
int logging;
|
||||
int guest;
|
||||
int dochroot;
|
||||
@ -123,20 +121,15 @@ int pdata = -1; /* for passive mode */
|
||||
sig_atomic_t transflag;
|
||||
off_t file_size;
|
||||
off_t byte_count;
|
||||
#if !defined(CMASK) || CMASK == 0
|
||||
#undef CMASK
|
||||
#define CMASK 027
|
||||
#endif
|
||||
#if !defined(GUEST_CMASK)
|
||||
#define GUEST_CMASK 0707
|
||||
#endif
|
||||
int defumask = CMASK; /* default umask value */
|
||||
char tmpline[7];
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
char remotehost[MAXHOSTNAMELEN];
|
||||
static char ttyline[20];
|
||||
char *tty = ttyline; /* for klogin */
|
||||
static char *anondir = NULL;
|
||||
static struct timeval lastt;
|
||||
|
||||
extern struct ftpclass curclass;
|
||||
|
||||
#if defined(KERBEROS)
|
||||
int notickets = 1;
|
||||
@ -259,28 +252,11 @@ main(argc, argv, envp)
|
||||
break;
|
||||
|
||||
case 't':
|
||||
timeout = atoi(optarg);
|
||||
if (maxtimeout < timeout)
|
||||
maxtimeout = timeout;
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
maxtimeout = atoi(optarg);
|
||||
if (timeout > maxtimeout)
|
||||
timeout = maxtimeout;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
{
|
||||
long val = 0;
|
||||
|
||||
val = strtol(optarg, &optarg, 8);
|
||||
if (*optarg != '\0' || val < 0)
|
||||
warnx("bad value for -u");
|
||||
else
|
||||
defumask = val;
|
||||
warnx("-%c has be deprecated in favour of ftpd.conf",
|
||||
ch);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
warnx("unknown flag -%c ignored", optopt);
|
||||
@ -671,13 +647,23 @@ skip:
|
||||
logged_in = 1;
|
||||
|
||||
dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name);
|
||||
|
||||
/* parse ftpd.conf, setting up various parameters */
|
||||
if (guest)
|
||||
parse_conf(CLASS_GUEST);
|
||||
else if (dochroot)
|
||||
parse_conf(CLASS_CHROOT);
|
||||
else
|
||||
parse_conf(CLASS_REAL);
|
||||
|
||||
if (guest) {
|
||||
/*
|
||||
* We MUST do a chdir() after the chroot. Otherwise
|
||||
* the old current directory will be accessible as "."
|
||||
* outside the new root!
|
||||
*/
|
||||
if (chroot(anondir ? anondir : pw->pw_dir) < 0 || chdir("/") < 0) {
|
||||
if (chroot(anondir ? anondir : pw->pw_dir) < 0 ||
|
||||
chdir("/") < 0) {
|
||||
reply(550, "Can't set guest privileges.");
|
||||
goto bad;
|
||||
}
|
||||
@ -713,6 +699,7 @@ skip:
|
||||
(void) fflush(stdout);
|
||||
(void) fclose(fd);
|
||||
}
|
||||
show_chdir_messages(230);
|
||||
if (guest) {
|
||||
reply(230, "Guest login ok, access restrictions apply.");
|
||||
#ifdef HASSETPROCTITLE
|
||||
@ -736,12 +723,7 @@ skip:
|
||||
syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
|
||||
remotehost, pw->pw_name);
|
||||
}
|
||||
#ifndef INSECURE_GUEST
|
||||
if (guest)
|
||||
(void) umask(GUEST_CMASK);
|
||||
else
|
||||
#endif
|
||||
(void) umask(defumask);
|
||||
(void) umask(curclass.umask);
|
||||
return;
|
||||
bad:
|
||||
/* Forget all about it... */
|
||||
@ -755,22 +737,26 @@ retrieve(cmd, name)
|
||||
FILE *fin, *dout;
|
||||
struct stat st;
|
||||
int (*closefunc) __P((FILE *));
|
||||
int log;
|
||||
|
||||
log = (cmd == 0);
|
||||
if (cmd == 0) {
|
||||
fin = fopen(name, "r"), closefunc = fclose;
|
||||
st.st_size = 0;
|
||||
} else {
|
||||
if (fin == NULL)
|
||||
cmd = do_conversion(name);
|
||||
}
|
||||
if (cmd) {
|
||||
char line[BUFSIZ];
|
||||
|
||||
(void) sprintf(line, cmd, name), name = line;
|
||||
fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
|
||||
fin = ftpd_popen(line, "r", 1), closefunc = ftpd_pclose;
|
||||
st.st_size = -1;
|
||||
st.st_blksize = BUFSIZ;
|
||||
}
|
||||
if (fin == NULL) {
|
||||
if (errno != 0) {
|
||||
perror_reply(550, name);
|
||||
if (cmd == 0) {
|
||||
if (log) {
|
||||
LOGCMD("get", name);
|
||||
}
|
||||
}
|
||||
@ -809,7 +795,7 @@ retrieve(cmd, name)
|
||||
data = -1;
|
||||
pdata = -1;
|
||||
done:
|
||||
if (cmd == 0)
|
||||
if (log)
|
||||
LOGBYTES("get", name, byte_count);
|
||||
(*closefunc)(fin);
|
||||
}
|
||||
@ -1012,14 +998,15 @@ send_data(instr, outstr, blksize)
|
||||
FILE *instr, *outstr;
|
||||
off_t blksize;
|
||||
{
|
||||
int c, cnt, filefd, netfd;
|
||||
char *buf;
|
||||
int c, cnt, filefd, netfd;
|
||||
char *buf;
|
||||
|
||||
transflag++;
|
||||
if (setjmp(urgcatch)) {
|
||||
transflag = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
||||
case TYPE_A:
|
||||
@ -1088,15 +1075,16 @@ static int
|
||||
receive_data(instr, outstr)
|
||||
FILE *instr, *outstr;
|
||||
{
|
||||
int c;
|
||||
int cnt, bare_lfs = 0;
|
||||
char buf[BUFSIZ];
|
||||
int c, cnt, bare_lfs;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
bare_lfs = 0;
|
||||
transflag++;
|
||||
if (setjmp(urgcatch)) {
|
||||
transflag = 0;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
||||
case TYPE_I:
|
||||
@ -1172,7 +1160,7 @@ statfilecmd(filename)
|
||||
char line[LINE_MAX];
|
||||
|
||||
(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
|
||||
fin = ftpd_popen(line, "r");
|
||||
fin = ftpd_popen(line, "r", 0);
|
||||
lreply(211, "status of %s:", filename);
|
||||
while ((c = getc(fin)) != EOF) {
|
||||
if (c == '\n') {
|
||||
@ -1201,22 +1189,23 @@ statcmd()
|
||||
struct sockaddr_in *sin;
|
||||
u_char *a, *p;
|
||||
|
||||
lreply(211, "%s FTP server status:", hostname, version);
|
||||
printf(" %s\r\n", version);
|
||||
printf(" Connected to %s", remotehost);
|
||||
if (!isdigit(remotehost[0]))
|
||||
printf(" (%s)", inet_ntoa(his_addr.sin_addr));
|
||||
printf("\r\n");
|
||||
lreply(211, "%s FTP server status:", hostname);
|
||||
lreply(211, "%s", version);
|
||||
if (isdigit(remotehost[0]))
|
||||
lreply(211, "Connected to %s", remotehost);
|
||||
else
|
||||
lreply(211, "Connected to %s (%s)", remotehost,
|
||||
inet_ntoa(his_addr.sin_addr));
|
||||
if (logged_in) {
|
||||
if (guest)
|
||||
printf(" Logged in anonymously\r\n");
|
||||
lreply(211, "Logged in anonymously");
|
||||
else
|
||||
printf(" Logged in as %s\r\n", pw->pw_name);
|
||||
lreply(211, "Logged in as %s", pw->pw_name);
|
||||
} else if (askpasswd)
|
||||
printf(" Waiting for password\r\n");
|
||||
lreply(211, "Waiting for password");
|
||||
else
|
||||
printf(" Waiting for user name\r\n");
|
||||
printf(" TYPE: %s", typenames[type]);
|
||||
lreply(211, "Waiting for user name");
|
||||
printf("211- TYPE: %s", typenames[type]);
|
||||
if (type == TYPE_A || type == TYPE_E)
|
||||
printf(", FORM: %s", formnames[form]);
|
||||
if (type == TYPE_L)
|
||||
@ -1228,13 +1217,13 @@ statcmd()
|
||||
printf("; STRUcture: %s; transfer MODE: %s\r\n",
|
||||
strunames[stru], modenames[mode]);
|
||||
if (data != -1)
|
||||
printf(" Data connection open\r\n");
|
||||
lreply(211, "Data connection open");
|
||||
else if (pdata != -1) {
|
||||
printf(" in Passive mode");
|
||||
printf("211- in Passive mode");
|
||||
sin = &pasv_addr;
|
||||
goto printaddr;
|
||||
} else if (usedefault == 0) {
|
||||
printf(" PORT");
|
||||
printf("211- PORT");
|
||||
sin = &data_dest;
|
||||
printaddr:
|
||||
a = (u_char *) &sin->sin_addr;
|
||||
@ -1244,7 +1233,32 @@ printaddr:
|
||||
UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
|
||||
#undef UC
|
||||
} else
|
||||
printf(" No data connection\r\n");
|
||||
lreply(211, "No data connection");
|
||||
|
||||
if (logged_in) {
|
||||
struct ftpconv *cp;
|
||||
|
||||
lreply(211, "");
|
||||
lreply(211, "Class: %s", curclass.classname);
|
||||
if (curclass.display)
|
||||
lreply(211, "Display file: %s", curclass.display);
|
||||
if (curclass.notify)
|
||||
lreply(211, "Notify fileglob: %s", curclass.notify);
|
||||
lreply(211, "Idle timeout: %d, maximum timeout: %d",
|
||||
curclass.timeout, curclass.maxtimeout);
|
||||
lreply(211, "dele, mkd, rmd, umask, chmod: %sabled",
|
||||
curclass.modify ? "en" : "dis");
|
||||
lreply(211, "Umask: %.04o", curclass.umask);
|
||||
for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
|
||||
if (cp->suffix == NULL || cp->types == NULL ||
|
||||
cp->command == NULL)
|
||||
continue;
|
||||
lreply(211,
|
||||
"Conversion: %s [%s] disable: %s, command: %s",
|
||||
cp->suffix, cp->types, cp->disable, cp->command);
|
||||
}
|
||||
}
|
||||
|
||||
reply(211, "End of status");
|
||||
}
|
||||
|
||||
@ -1372,8 +1386,10 @@ cwd(path)
|
||||
|
||||
if (chdir(path) < 0)
|
||||
perror_reply(550, path);
|
||||
else
|
||||
else {
|
||||
show_chdir_messages(250);
|
||||
ack("CWD");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: pathnames.h,v 1.5 1995/04/11 02:44:59 cgd Exp $ */
|
||||
/* $NetBSD: pathnames.h,v 1.6 1997/06/14 08:43:32 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
@ -37,7 +37,8 @@
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#define _PATH_FTPUSERS "/etc/ftpusers"
|
||||
#define _PATH_FTPCHROOT "/etc/ftpchroot"
|
||||
#define _PATH_FTPWELCOME "/etc/ftpwelcome"
|
||||
#define _PATH_FTPDCONF "/etc/ftpd.conf"
|
||||
#define _PATH_FTPLOGINMESG "/etc/motd"
|
||||
#define _PATH_FTPUSERS "/etc/ftpusers"
|
||||
#define _PATH_FTPWELCOME "/etc/ftpwelcome"
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: popen.c,v 1.6 1997/04/27 03:21:43 lukem Exp $ */
|
||||
/* $NetBSD: popen.c,v 1.7 1997/06/14 08:43:33 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988, 1993, 1994
|
||||
@ -41,7 +41,7 @@
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94";
|
||||
#else
|
||||
static char rcsid[] = "$NetBSD: popen.c,v 1.6 1997/04/27 03:21:43 lukem Exp $";
|
||||
static char rcsid[] = "$NetBSD: popen.c,v 1.7 1997/06/14 08:43:33 lukem Exp $";
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
@ -67,8 +67,9 @@ static int *pids;
|
||||
static int fds;
|
||||
|
||||
FILE *
|
||||
ftpd_popen(program, type)
|
||||
ftpd_popen(program, type, nostderr)
|
||||
char *program, *type;
|
||||
int nostderr;
|
||||
{
|
||||
char *cp;
|
||||
FILE *iop;
|
||||
@ -122,7 +123,10 @@ ftpd_popen(program, type)
|
||||
dup2(pdes[1], STDOUT_FILENO);
|
||||
(void)close(pdes[1]);
|
||||
}
|
||||
dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */
|
||||
if (nostderr)
|
||||
(void)close(STDERR_FILENO);
|
||||
else /* stderr too! */
|
||||
dup2(STDOUT_FILENO, STDERR_FILENO);
|
||||
(void)close(pdes[0]);
|
||||
} else {
|
||||
if (pdes[0] != STDIN_FILENO) {
|
||||
|
Loading…
Reference in New Issue
Block a user