Import of LukeM's ftpd taken from the NetBSD CVS repo on 5-Jan-2003.

The "portable" release of this is just lagging way too far behind
what is in NetBSD's base.
This commit is contained in:
David E. O'Brien 2003-01-06 00:06:49 +00:00
parent 3d982f73f3
commit 33bc027019
14 changed files with 976 additions and 524 deletions

View File

@ -0,0 +1,46 @@
# $NetBSD: Makefile,v 1.49 2002/08/22 00:09:38 christos Exp $
# @(#)Makefile 8.2 (Berkeley) 4/4/94
.include <bsd.own.mk>
PROG= ftpd
SRCS= cmds.c conf.c ftpd.c ftpcmd.y logutmp.c logwtmp.c popen.c
CPPFLAGS+=-I${.CURDIR} -DSUPPORT_UTMP -DSUPPORT_UTMPX
DPADD+= ${LIBCRYPT} ${LIBUTIL}
LDADD+= -lcrypt -lutil
MAN= ftpd.conf.5 ftpusers.5 ftpd.8
MLINKS= ftpusers.5 ftpchroot.5
# for `internal' ls
SRCS+= ls.c cmp.c print.c stat_flags.c util.c
.PATH: ${NETBSDSRCDIR}/bin/ls
CPPFLAGS+=-DINET6
.include <bsd.own.mk>
WARNS=2
.if (${USE_SKEY} != "no")
CPPFLAGS+=-DSKEY
DPADD+= ${LIBSKEY}
LDADD+= -lskey
.endif
ftpd.o ftpcmd.o: version.h
# XXX Kerberos support is broken right now.
#.PATH: ${NETBSDSRCDIR}/usr.bin/login
#.ifdef KERBEROS5
#SRCS+= k5login.c
#CPPFLAGS+=-DKERBEROS5
#DPADD+= ${LIBKRB5} ${LIBK5CRYPTO} ${LIBCOM_ERR}
#LDADD+= -lkrb5 -lk5crypto -lcom_err
#.else
#SRCS+= klogin.c
#CPPFLAGS+=-DKERBEROS
#DPADD+= ${LIBKRB} ${LIBDES} ${LIBCOM_ERR}
#LDADD+= -lkrb -kdes -lcom_err
#.endif
.include <bsd.prog.mk>

View File

@ -1,4 +1,4 @@
/* $NetBSD: cmds.c,v 1.16 2002/02/13 15:15:23 lukem Exp $ */
/* $NetBSD: cmds.c,v 1.18 2002/10/12 08:35:16 darrenr Exp $ */
/*
* Copyright (c) 1999-2001 The NetBSD Foundation, Inc.
@ -98,7 +98,30 @@
* SUCH DAMAGE.
*/
#include "lukemftpd.h"
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: cmds.c,v 1.18 2002/10/12 08:35:16 darrenr Exp $");
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <arpa/ftp.h>
#include <dirent.h>
#include <errno.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tzfile.h>
#include <unistd.h>
#include <ctype.h>
#ifdef KERBEROS5
#include <krb5/krb5.h>
#endif
#include "extern.h"
@ -307,11 +330,11 @@ opts(const char *command)
*ep++ = '\0';
c = lookup(cmdtab, command);
if (c == NULL) {
reply(502, "Unknown command %s.", command);
reply(502, "Unknown command '%s'.", command);
return;
}
if (! CMD_IMPLEMENTED(c)) {
reply(501, "%s command not implemented.", c->name);
reply(502, "%s command not implemented.", c->name);
return;
}
if (! CMD_HAS_OPTIONS(c)) {
@ -484,12 +507,14 @@ statfilecmd(const char *filename)
{
FILE *fin;
int c;
int atstart;
char *argv[] = { INTERNAL_LS, "-lgA", "", NULL };
argv[2] = (char *)filename;
fin = ftpd_popen(argv, "r", STDOUT_FILENO);
reply(-211, "status of %s:", filename);
/* XXX: use fgetln() or fparseln() here? */
atstart = 1;
while ((c = getc(fin)) != EOF) {
if (c == '\n') {
if (ferror(stdout)){
@ -505,7 +530,10 @@ statfilecmd(const char *filename)
}
CPUTC('\r', stdout);
}
if (atstart && isdigit(c))
CPUTC(' ', stdout);
CPUTC(c, stdout);
atstart = (c == '\n');
}
(void) ftpd_pclose(fin);
reply(211, "End of Status");

View File

@ -1,4 +1,4 @@
/* $NetBSD: conf.c,v 1.46 2001/12/04 13:54:12 lukem Exp $ */
/* $NetBSD: conf.c,v 1.50 2002/11/16 03:10:34 itojun Exp $ */
/*-
* Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
@ -36,7 +36,35 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "lukemftpd.h"
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: conf.c,v 1.50 2002/11/16 03:10:34 itojun Exp $");
#endif /* not lint */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
#include <netdb.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include <util.h>
#ifdef KERBEROS5
#include <krb5/krb5.h>
#endif
#include "extern.h"
#include "pathnames.h"
@ -91,6 +119,11 @@ init_curclass(void)
curclass.timeout = DEFAULT_TIMEOUT;
/* curclass.type is set elsewhere */
curclass.umask = DEFAULT_UMASK;
curclass.mmapsize = 0;
curclass.readsize = 0;
curclass.writesize = 0;
curclass.sendbufsize = 0;
curclass.sendlowat = 0;
CURCLASS_FLAGS_SET(checkportcmd);
CURCLASS_FLAGS_CLR(denyquick);
@ -113,11 +146,10 @@ parse_conf(const char *findclass)
size_t len;
LLT llval;
int none, match;
char *endp;
char *endp, errbuf[100];
char *class, *word, *arg, *template;
const char *infile;
size_t line;
unsigned int timeout;
struct ftpconv *conv, *cnext;
init_curclass();
@ -136,7 +168,7 @@ parse_conf(const char *findclass)
template = NULL;
for (;
(buf = fparseln(f, &len, &line, NULL, FPARSELN_UNESCCOMM |
FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL;
FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL;
free(buf)) {
none = match = 0;
p = buf;
@ -160,24 +192,37 @@ parse_conf(const char *findclass)
strcasecmp(class, "all") == 0) )
continue;
#define CONF_FLAG(x) \
do { \
if (none || \
(!EMPTYSTR(arg) && strcasecmp(arg, "off") == 0)) \
CURCLASS_FLAGS_CLR(x); \
else \
CURCLASS_FLAGS_SET(x); \
#define CONF_FLAG(Field) \
do { \
if (none || \
(!EMPTYSTR(arg) && strcasecmp(arg, "off") == 0)) \
CURCLASS_FLAGS_CLR(Field); \
else \
CURCLASS_FLAGS_SET(Field); \
} while (0)
#define CONF_STRING(x) \
do { \
if (none || EMPTYSTR(arg)) \
arg = NULL; \
else \
arg = xstrdup(arg); \
REASSIGN(curclass.x, arg); \
#define CONF_STRING(Field) \
do { \
if (none || EMPTYSTR(arg)) \
arg = NULL; \
else \
arg = xstrdup(arg); \
REASSIGN(curclass.Field, arg); \
} while (0)
#define CONF_LL(Field,Arg,Min,Max) \
do { \
if (none || EMPTYSTR(Arg)) \
goto nextline; \
llval = strsuftollx(#Field, Arg, Min, Max, \
errbuf, sizeof(errbuf)); \
if (errbuf[0]) { \
syslog(LOG_WARNING, "%s line %d: %s", \
infile, (int)line, errbuf); \
goto nextline; \
} \
curclass.Field = llval; \
} while(0)
if (0) {
/* no-op */
@ -314,61 +359,40 @@ parse_conf(const char *findclass)
CONF_STRING(homedir);
} else if (strcasecmp(word, "limit") == 0) {
int limit;
curclass.limit = DEFAULT_LIMIT;
REASSIGN(curclass.limitfile, NULL);
if (none || EMPTYSTR(arg))
continue;
limit = (int)strtol(arg, &endp, 10);
if (*endp != 0) {
syslog(LOG_WARNING,
"%s line %d: invalid limit %s",
infile, (int)line, arg);
continue;
}
curclass.limit = limit;
CONF_LL(limit, arg, -1, LLTMAX);
REASSIGN(curclass.limitfile,
EMPTYSTR(p) ? NULL : xstrdup(p));
} else if (strcasecmp(word, "maxfilesize") == 0) {
curclass.maxfilesize = DEFAULT_MAXFILESIZE;
if (none || EMPTYSTR(arg))
continue;
llval = strsuftoll(arg);
if (llval == -1) {
syslog(LOG_WARNING,
"%s line %d: invalid maxfilesize %s",
infile, (int)line, arg);
continue;
}
curclass.maxfilesize = llval;
CONF_LL(maxfilesize, arg, -1, LLTMAX);
} else if (strcasecmp(word, "maxtimeout") == 0) {
curclass.maxtimeout = DEFAULT_MAXTIMEOUT;
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, (int)line, arg);
continue;
}
if (timeout < 30) {
syslog(LOG_WARNING,
"%s line %d: maxtimeout %d < 30 seconds",
infile, (int)line, timeout);
continue;
}
if (timeout < curclass.timeout) {
syslog(LOG_WARNING,
"%s line %d: maxtimeout %d < timeout (%d)",
infile, (int)line, timeout,
curclass.timeout);
continue;
}
curclass.maxtimeout = timeout;
CONF_LL(maxtimeout, arg,
MIN(30, curclass.timeout), LLTMAX);
} else if (strcasecmp(word, "mmapsize") == 0) {
curclass.mmapsize = 0;
CONF_LL(mmapsize, arg, 0, LLTMAX);
} else if (strcasecmp(word, "readsize") == 0) {
curclass.readsize = 0;
CONF_LL(readsize, arg, 0, LLTMAX);
} else if (strcasecmp(word, "writesize") == 0) {
curclass.writesize = 0;
CONF_LL(writesize, arg, 0, LLTMAX);
} else if (strcasecmp(word, "sendbufsize") == 0) {
curclass.sendbufsize = 0;
CONF_LL(sendbufsize, arg, 0, LLTMAX);
} else if (strcasecmp(word, "sendlowat") == 0) {
curclass.sendlowat = 0;
CONF_LL(sendlowat, arg, 0, LLTMAX);
} else if (strcasecmp(word, "modify") == 0) {
CONF_FLAG(modify);
@ -383,107 +407,60 @@ parse_conf(const char *findclass)
CONF_FLAG(passive);
} else if (strcasecmp(word, "portrange") == 0) {
int minport, maxport;
char *min, *max;
long minport, maxport;
curclass.portmin = 0;
curclass.portmax = 0;
if (none || EMPTYSTR(arg))
continue;
min = arg;
NEXTWORD(p, max);
if (EMPTYSTR(max)) {
if (EMPTYSTR(p)) {
syslog(LOG_WARNING,
"%s line %d: missing maxport argument",
infile, (int)line);
continue;
}
minport = (int)strtol(min, &endp, 10);
if (*endp != 0 || minport < IPPORT_RESERVED ||
minport > IPPORT_ANONMAX) {
syslog(LOG_WARNING,
"%s line %d: invalid minport %s",
infile, (int)line, min);
minport = strsuftollx("minport", arg, IPPORT_RESERVED,
IPPORT_ANONMAX, errbuf, sizeof(errbuf));
if (errbuf[0]) {
syslog(LOG_WARNING, "%s line %d: %s",
infile, (int)line, errbuf);
continue;
}
maxport = (int)strtol(max, &endp, 10);
if (*endp != 0 || maxport < IPPORT_RESERVED ||
maxport > IPPORT_ANONMAX) {
syslog(LOG_WARNING,
"%s line %d: invalid maxport %s",
infile, (int)line, max);
maxport = strsuftollx("maxport", p, IPPORT_RESERVED,
IPPORT_ANONMAX, errbuf, sizeof(errbuf));
if (errbuf[0]) {
syslog(LOG_WARNING, "%s line %d: %s",
infile, (int)line, errbuf);
continue;
}
if (minport >= maxport) {
syslog(LOG_WARNING,
"%s line %d: minport %d >= maxport %d",
"%s line %d: minport %ld >= maxport %ld",
infile, (int)line, minport, maxport);
continue;
}
curclass.portmin = minport;
curclass.portmax = maxport;
curclass.portmin = (int)minport;
curclass.portmax = (int)maxport;
} else if (strcasecmp(word, "private") == 0) {
CONF_FLAG(private);
} else if (strcasecmp(word, "rateget") == 0) {
curclass.maxrateget = 0;
curclass.rateget = 0;
if (none || EMPTYSTR(arg))
continue;
llval = strsuftoll(arg);
if (llval == -1) {
syslog(LOG_WARNING,
"%s line %d: invalid rateget %s",
infile, (int)line, arg);
continue;
}
curclass.maxrateget = llval;
curclass.rateget = llval;
curclass.maxrateget = curclass.rateget = 0;
CONF_LL(rateget, arg, 0, LLTMAX);
curclass.maxrateget = curclass.rateget;
} else if (strcasecmp(word, "rateput") == 0) {
curclass.maxrateput = 0;
curclass.rateput = 0;
if (none || EMPTYSTR(arg))
continue;
llval = strsuftoll(arg);
if (llval == -1) {
syslog(LOG_WARNING,
"%s line %d: invalid rateput %s",
infile, (int)line, arg);
continue;
}
curclass.maxrateput = llval;
curclass.rateput = llval;
curclass.maxrateput = curclass.rateput = 0;
CONF_LL(rateput, arg, 0, LLTMAX);
curclass.maxrateput = curclass.rateput;
} else if (strcasecmp(word, "sanenames") == 0) {
CONF_FLAG(sanenames);
} else if (strcasecmp(word, "timeout") == 0) {
curclass.timeout = DEFAULT_TIMEOUT;
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, (int)line, arg);
continue;
}
if (timeout < 30) {
syslog(LOG_WARNING,
"%s line %d: timeout %d < 30 seconds",
infile, (int)line, timeout);
continue;
}
if (timeout > curclass.maxtimeout) {
syslog(LOG_WARNING,
"%s line %d: timeout %d > maxtimeout (%d)",
infile, (int)line, timeout,
curclass.maxtimeout);
continue;
}
curclass.timeout = timeout;
CONF_LL(timeout, arg, 30, curclass.maxtimeout);
} else if (strcasecmp(word, "template") == 0) {
if (none)
@ -491,19 +468,22 @@ parse_conf(const char *findclass)
REASSIGN(template, EMPTYSTR(arg) ? NULL : xstrdup(arg));
} else if (strcasecmp(word, "umask") == 0) {
mode_t fumask;
u_long fumask;
curclass.umask = DEFAULT_UMASK;
if (none || EMPTYSTR(arg))
continue;
fumask = (mode_t)strtoul(arg, &endp, 8);
if (*endp != 0 || fumask > 0777) {
errno = 0;
endp = NULL;
fumask = strtoul(arg, &endp, 8);
if (errno || *arg == '\0' || *endp != '\0' ||
fumask > 0777) {
syslog(LOG_WARNING,
"%s line %d: invalid umask %s",
infile, (int)line, arg);
continue;
}
curclass.umask = fumask;
curclass.umask = (mode_t)fumask;
} else if (strcasecmp(word, "upload") == 0) {
CONF_FLAG(upload);
@ -516,6 +496,8 @@ parse_conf(const char *findclass)
infile, (int)line, word);
continue;
}
nextline:
;
}
REASSIGN(template, NULL);
fclose(f);
@ -578,7 +560,7 @@ show_chdir_messages(int code)
return;
memset(&gl, 0, sizeof(gl));
if (glob(curclass.notify, GLOB_LIMIT, NULL, &gl) != 0
if (glob(curclass.notify, GLOB_BRACE|GLOB_LIMIT, NULL, &gl) != 0
|| gl.gl_matchc == 0) {
globfree(&gl);
return;
@ -669,8 +651,8 @@ display_file(const char *file, int code)
cprintf(stdout, "unlimited");
lastnum = 0;
} else {
cprintf(stdout, "%d",
curclass.limit);
cprintf(stdout, LLF,
(LLT)curclass.limit);
lastnum = curclass.limit;
}
break;
@ -890,51 +872,6 @@ do_conversion(const char *fname)
return(NULL);
}
/*
* Convert the string `arg' to a long long, which may have an optional SI suffix
* (`b', `k', `m', `g', `t'). Returns the number for success, -1 otherwise.
*/
LLT
strsuftoll(const char *arg)
{
char *cp;
LLT val;
if (!isdigit((unsigned char)arg[0]))
return (-1);
val = STRTOLL(arg, &cp, 10);
if (cp != NULL) {
if (cp[0] != '\0' && cp[1] != '\0')
return (-1);
switch (tolower((unsigned char)cp[0])) {
case '\0':
case 'b':
break;
case 'k':
val <<= 10;
break;
case 'm':
val <<= 20;
break;
case 'g':
val <<= 30;
break;
#ifndef NO_LONG_LONG
case 't':
val <<= 40;
break;
#endif
default:
return (-1);
}
}
if (val < 0)
return (-1);
return (val);
}
/*
* Count the number of current connections, reading from
* /var/run/ftpd.pids-<class>
@ -959,15 +896,8 @@ count_users(void)
if ((fd = open(fn, O_RDWR | O_CREAT, 0600)) == -1)
return;
#if HAVE_LOCKF
if (lockf(fd, F_TLOCK, 0) == -1)
goto cleanup_count;
#elif HAVE_FLOCK
if (flock(fd, LOCK_EX | LOCK_NB) != 0)
goto cleanup_count;
#else
/* XXX: use fcntl ? */
#endif
if (fstat(fd, &sb) == -1)
goto cleanup_count;
if ((pids = malloc(sb.st_size + sizeof(pid_t))) == NULL)
@ -1005,14 +935,8 @@ count_users(void)
(void)ftruncate(fd, count);
cleanup_count:
#if HAVE_LOCKF
if (lseek(fd, 0, SEEK_SET) != -1)
(void)lockf(fd, F_ULOCK, 0);
#elif HAVE_FLOCK
(void)flock(fd, LOCK_UN);
#else
/* XXX: use fcntl ? */
#endif
close(fd);
REASSIGN(pids, NULL);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: extern.h,v 1.43 2001/12/04 13:54:12 lukem Exp $ */
/* $NetBSD: extern.h,v 1.44 2002/05/30 00:24:47 enami Exp $ */
/*-
* Copyright (c) 1992, 1993
@ -108,15 +108,8 @@
# define ULLFP(x) "%" x "lu"
# define ULLT unsigned long
# define STRTOLL(x,y,z) strtol(x,y,z)
#else
#if HAVE_PRINTF_QD
# define LLF "%qd"
# define LLFP(x) "%" x "qd"
# define LLT long long
# define ULLF "%qu"
# define ULLFP(x) "%" x "qu"
# define ULLT unsigned long long
# define STRTOLL(x,y,z) strtoll(x,y,z)
# define LLTMIN LONG_MIN
# define LLTMAX LONG_MAX
#else
# define LLF "%lld"
# define LLFP(x) "%" x "lld"
@ -125,7 +118,8 @@
# define ULLFP(x) "%" x "llu"
# define ULLT unsigned long long
# define STRTOLL(x,y,z) strtoll(x,y,z)
#endif
# define LLTMIN LLONG_MIN
# define LLTMAX LLONG_MAX
#endif
#define FTP_BUFLEN 512
@ -137,7 +131,7 @@ char *conffilename(const char *);
char **copyblk(char **);
void count_users(void);
void cprintf(FILE *, const char *, ...)
;
__attribute__((__format__(__printf__, 2, 3)));
void cwd(const char *);
FILE *dataconn(const char *, off_t, const char *);
void delete(const char *);
@ -177,7 +171,7 @@ void removedir(const char *);
void renamecmd(const char *, const char *);
char *renamefrom(const char *);
void reply(int, const char *, ...)
;
__attribute__((__format__(__printf__, 2, 3)));
void retrieve(char *[], const char *);
void send_file_list(const char *);
void show_chdir_messages(int);
@ -186,7 +180,6 @@ void statcmd(void);
void statfilecmd(const char *);
void statxfer(void);
void store(const char *, const char *, int);
LLT strsuftoll(const char *);
void user(const char *);
char *xstrdup(const char *);
void yyerror(char *);
@ -271,24 +264,29 @@ struct ftpclass {
char *display; /* File to display upon chdir */
char *homedir; /* Directory to chdir(2) to at login */
classflag_t flags; /* Flags; see classflag_t above */
int limit; /* Max connections (-1 = unlimited) */
LLT limit; /* Max connections (-1 = unlimited) */
char *limitfile; /* File to display if limit reached */
LLT maxfilesize; /* Maximum file size of uploads */
LLT maxrateget; /* Maximum get transfer rate throttle */
LLT maxrateput; /* Maximum put transfer rate throttle */
unsigned int maxtimeout; /* Maximum permitted timeout */
LLT maxtimeout; /* Maximum permitted timeout */
char *motd; /* MotD file to display after login */
char *notify; /* Files to notify about upon chdir */
int portmin; /* Minumum port for passive mode */
int portmax; /* Maximum port for passive mode */
LLT portmin; /* Minumum port for passive mode */
LLT portmax; /* Maximum port for passive mode */
LLT rateget; /* Get (RETR) transfer rate throttle */
LLT rateput; /* Put (STOR) transfer rate throttle */
unsigned int timeout; /* Default timeout */
LLT timeout; /* Default timeout */
class_ft type; /* Class type */
mode_t umask; /* Umask to use */
LLT mmapsize; /* mmap window size */
LLT readsize; /* data read size */
LLT writesize; /* data write size */
LLT sendbufsize; /* SO_SNDBUF size */
LLT sendlowat; /* SO_SNDLOWAT size */
};
extern void ftp_loop(void);
extern void ftp_loop(void) __attribute__ ((noreturn));
extern void ftp_handle_line(char *);
#ifndef GLOBAL
@ -355,8 +353,8 @@ extern struct tab cmdtab[];
} while (0);
#define CURCLASSTYPE curclass.type == CLASS_GUEST ? "GUEST" : \
curclass.type == CLASS_CHROOT ? "CHROOT" : \
curclass.type == CLASS_REAL ? "REAL" : \
curclass.type == CLASS_CHROOT ? "CHROOT" : \
curclass.type == CLASS_REAL ? "REAL" : \
"<unknown>"
#define ISDOTDIR(x) (x[0] == '.' && x[1] == '\0')

View File

@ -1,7 +1,7 @@
/* $NetBSD: ftpcmd.y,v 1.66 2001/12/01 10:25:30 lukem Exp $ */
/* $NetBSD: ftpcmd.y,v 1.71 2002/10/12 08:35:17 darrenr Exp $ */
/*-
* Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
* Copyright (c) 1997-2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -77,7 +77,41 @@
*/
%{
#include "lukemftpd.h"
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94";
#else
__RCSID("$NetBSD: ftpcmd.y,v 1.71 2002/10/12 08:35:17 darrenr Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/ftp.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <tzfile.h>
#include <unistd.h>
#include <netdb.h>
#ifdef KERBEROS5
#include <krb5/krb5.h>
#endif
#include "extern.h"
#include "version.h"
@ -93,7 +127,10 @@ char *fromname;
%}
%union {
int i;
struct {
off_t o;
int i;
} u;
char *s;
}
@ -128,10 +165,10 @@ char *fromname;
%token <s> STRING
%token <s> ALL
%token <i> NUMBER
%token <u> NUMBER
%type <i> check_login octal_number byte_size
%type <i> struct_code mode_code type_code form_code decimal_integer
%type <u.i> check_login octal_number byte_size
%type <u.i> struct_code mode_code type_code form_code decimal_integer
%type <s> pathstring pathname password username
%type <s> mechanism_name base64data prot_code
@ -259,32 +296,48 @@ cmd
| LPSV check_login CRLF
{
if ($2) {
if (epsvall)
reply(501,
"LPSV disallowed after EPSV ALL");
else
long_passive("LPSV", PF_UNSPEC);
if (CURCLASS_FLAGS_ISSET(passive)) {
if (epsvall)
reply(501,
"LPSV disallowed after EPSV ALL");
else
long_passive("LPSV", PF_UNSPEC);
} else
reply(500, "LPSV mode not available.");
}
}
| EPSV check_login SP NUMBER CRLF
{
if ($2)
long_passive("EPSV", epsvproto2af($4));
if ($2) {
if (CURCLASS_FLAGS_ISSET(passive))
long_passive("EPSV",
epsvproto2af($4.i));
else
reply(500, "EPSV mode not available.");
}
}
| EPSV check_login SP ALL CRLF
{
if ($2) {
reply(200, "EPSV ALL command successful.");
epsvall++;
if (CURCLASS_FLAGS_ISSET(passive)) {
reply(200,
"EPSV ALL command successful.");
epsvall++;
} else
reply(500, "EPSV mode not available.");
}
}
| EPSV check_login CRLF
{
if ($2)
long_passive("EPSV", PF_UNSPEC);
if ($2) {
if (CURCLASS_FLAGS_ISSET(passive))
long_passive("EPSV", PF_UNSPEC);
else
reply(500, "EPSV mode not available.");
}
}
| TYPE check_login SP type_code CRLF
@ -517,24 +570,28 @@ cmd
{
if ($4) {
reply(200,
"Current IDLE time limit is %d seconds; max %d",
curclass.timeout, curclass.maxtimeout);
"Current IDLE time limit is " LLF
" seconds; max " LLF,
(LLT)curclass.timeout,
(LLT)curclass.maxtimeout);
}
}
| SITE SP IDLE check_login SP NUMBER CRLF
{
if ($4) {
if ($6 < 30 || $6 > curclass.maxtimeout) {
if ($6.i < 30 || $6.i > curclass.maxtimeout) {
reply(501,
"IDLE time limit must be between 30 and %d seconds",
curclass.maxtimeout);
"IDLE time limit must be between 30 and "
LLF " seconds",
(LLT)curclass.maxtimeout);
} else {
curclass.timeout = $6;
curclass.timeout = $6.i;
(void) alarm(curclass.timeout);
reply(200,
"IDLE time limit set to %d seconds",
curclass.timeout);
"IDLE time limit set to "
LLF " seconds",
(LLT)curclass.timeout);
}
}
}
@ -550,19 +607,17 @@ cmd
| SITE SP RATEGET check_login SP STRING CRLF
{
char errbuf[100];
char *p = $6;
LLT rate;
if ($4) {
rate = strsuftoll(p);
if (rate == -1)
reply(501, "Invalid RATEGET %s", p);
else if (curclass.maxrateget &&
rate > curclass.maxrateget)
reply(501,
"RATEGET " LLF " is larger than maximum RATEGET " LLF,
(LLT)rate,
(LLT)curclass.maxrateget);
rate = strsuftollx("RATEGET", p, 0,
curclass.maxrateget
? curclass.maxrateget
: LLTMAX, errbuf, sizeof(errbuf));
if (errbuf[0])
reply(501, "%s", errbuf);
else {
curclass.rateget = rate;
reply(200,
@ -584,19 +639,17 @@ cmd
| SITE SP RATEPUT check_login SP STRING CRLF
{
char errbuf[100];
char *p = $6;
LLT rate;
if ($4) {
rate = strsuftoll(p);
if (rate == -1)
reply(501, "Invalid RATEPUT %s", p);
else if (curclass.maxrateput &&
rate > curclass.maxrateput)
reply(501,
"RATEPUT " LLF " is larger than maximum RATEPUT " LLF,
(LLT)rate,
(LLT)curclass.maxrateput);
rate = strsuftollx("RATEPUT", p, 0,
curclass.maxrateput
? curclass.maxrateput
: LLTMAX, errbuf, sizeof(errbuf));
if (errbuf[0])
reply(501, "%s", errbuf);
else {
curclass.rateput = rate;
reply(200,
@ -622,7 +675,7 @@ cmd
{
int oldmask;
if ($4 && CURCLASS_FLAGS_ISSET(modify)) {
if ($4 && check_write("", 0)) {
if (($6 == -1) || ($6 > 0777)) {
reply(501, "Bad UMASK value");
} else {
@ -827,11 +880,11 @@ cmd
;
rcmd
: REST check_login SP byte_size CRLF
: REST check_login SP NUMBER CRLF
{
if ($2) {
fromname = NULL;
restart_point = $4; /* XXX: $4 is only "int" */
restart_point = $4.o;
reply(350,
"Restarting at " LLF ". Send STORE or RETRIEVE to initiate transfer.",
(LLT)restart_point);
@ -863,6 +916,9 @@ password
byte_size
: NUMBER
{
$$ = $1.i;
}
;
host_port
@ -875,9 +931,9 @@ host_port
data_dest.su_len = sizeof(struct sockaddr_in);
data_dest.su_family = AF_INET;
p = (char *)&data_dest.su_port;
p[0] = $9; p[1] = $11;
p[0] = $9.i; p[1] = $11.i;
a = (char *)&data_dest.su_addr;
a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
a[0] = $1.i; a[1] = $3.i; a[2] = $5.i; a[3] = $7.i;
}
;
@ -892,12 +948,12 @@ host_long_port4
data_dest.su_len = sizeof(struct sockaddr_in);
data_dest.su_family = AF_INET;
p = (char *)&data_dest.su_port;
p[0] = $15; p[1] = $17;
p[0] = $15.i; p[1] = $17.i;
a = (char *)&data_dest.su_addr;
a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11;
a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i;
/* reject invalid LPRT command */
if ($1 != 4 || $3 != 4 || $13 != 2)
if ($1.i != 4 || $3.i != 4 || $13.i != 2)
memset(&data_dest, 0, sizeof(data_dest));
}
;
@ -917,12 +973,12 @@ host_long_port6
data_dest.su_len = sizeof(struct sockaddr_in6);
data_dest.su_family = AF_INET6;
p = (char *)&data_dest.su_port;
p[0] = $39; p[1] = $41;
p[0] = $39.i; p[1] = $41.i;
a = (char *)&data_dest.si_su.su_sin6.sin6_addr;
a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11;
a[4] = $13; a[5] = $15; a[6] = $17; a[7] = $19;
a[8] = $21; a[9] = $23; a[10] = $25; a[11] = $27;
a[12] = $29; a[13] = $31; a[14] = $33; a[15] = $35;
a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i;
a[4] = $13.i; a[5] = $15.i; a[6] = $17.i; a[7] = $19.i;
a[8] = $21.i; a[9] = $23.i; a[10] = $25.i; a[11] = $27.i;
a[12] = $29.i; a[13] = $31.i; a[14] = $33.i; a[15] = $35.i;
if (his_addr.su_family == AF_INET6) {
/* XXX: more sanity checks! */
data_dest.su_scope_id = his_addr.su_scope_id;
@ -931,7 +987,7 @@ host_long_port6
memset(&data_dest, 0, sizeof(data_dest));
#endif /* INET6 */
/* reject invalid LPRT command */
if ($1 != 6 || $3 != 16 || $37 != 2)
if ($1.i != 6.i || $3.i != 16.i || $37.i != 2)
memset(&data_dest, 0, sizeof(data_dest));
}
;
@ -1093,7 +1149,7 @@ octal_number
* Convert a number that was read as decimal number
* to what it would be if it had been read as octal.
*/
dec = $1;
dec = $1.i;
multby = 1;
ret = 0;
while (dec) {
@ -1124,6 +1180,9 @@ prot_code
decimal_integer
: NUMBER
{
$$ = $1.i;
}
;
check_login
@ -1231,13 +1290,13 @@ struct tab cmdtab[] = {
};
struct tab sitetab[] = {
{ "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" },
{ "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
{ "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" },
{ "RATEGET", RATEGET,OSTR, 1, "[ <sp> get-throttle-rate ]" },
{ "RATEPUT", RATEPUT,OSTR, 1, "[ <sp> put-throttle-rate ]" },
{ "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" },
{ NULL, 0, 0, 0, NULL }
{ "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" },
{ "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
{ "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" },
{ "RATEGET", RATEGET,OSTR, 1, "[ <sp> get-throttle-rate ]" },
{ "RATEPUT", RATEPUT,OSTR, 1, "[ <sp> put-throttle-rate ]" },
{ "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" },
{ NULL, 0, 0, 0, NULL }
};
static int check_write(const char *, int);
@ -1251,6 +1310,8 @@ extern int epsvall;
/*
* Check if a filename is allowed to be modified (isupload == 0) or
* uploaded (isupload == 1), and if necessary, check the filename is `sane'.
* If the filename is NULL, fail.
* If the filename is "", don't do the sane name check.
*/
static int
check_write(const char *file, int isupload)
@ -1271,8 +1332,9 @@ check_write(const char *file, int isupload)
reply(502, "No permission to use this command.");
return (0);
}
/* checking sanenames */
if (CURCLASS_FLAGS_ISSET(sanenames)) {
if (file[0] != '\0' && CURCLASS_FLAGS_ISSET(sanenames)) {
const char *p;
if (file[0] == '.')
@ -1392,11 +1454,11 @@ toolong(int signo)
{
reply(421,
"Timeout (%d seconds): closing control connection.",
curclass.timeout);
"Timeout (" LLF " seconds): closing control connection.",
(LLT)curclass.timeout);
if (logging)
syslog(LOG_INFO, "User %s timed out after %d seconds",
(pw ? pw->pw_name : "unknown"), curclass.timeout);
syslog(LOG_INFO, "User %s timed out after " LLF " seconds",
(pw ? pw->pw_name : "unknown"), (LLT)curclass.timeout);
dologout(1);
}
@ -1548,7 +1610,7 @@ yylex(void)
;
c = cmdp[cpos];
cmdp[cpos] = '\0';
yylval.i = atoi(cp);
yylval.u.i = atoi(cp);
cmdp[cpos] = c;
state = STR1;
return (NUMBER);
@ -1563,7 +1625,8 @@ yylex(void)
;
c = cmdp[cpos];
cmdp[cpos] = '\0';
yylval.i = atoi(cp);
yylval.u.i = atoi(cp);
yylval.u.o = strtoull(cp, (char **)NULL, 10);
cmdp[cpos] = c;
return (NUMBER);
}
@ -1736,13 +1799,13 @@ help(struct tab *ctab, const char *s)
}
c = lookup(ctab, s);
if (c == (struct tab *)0) {
reply(502, "Unknown command %s.", s);
reply(502, "Unknown command '%s'.", s);
return;
}
if (CMD_IMPLEMENTED(c))
reply(214, "Syntax: %s%s %s", htype, c->name, c->help);
else
reply(214, "%s%-*s\t%s; not implemented.", htype, width,
reply(504, "%s%-*s\t%s; not implemented.", htype, width,
c->name, c->help);
}

View File

@ -1,6 +1,6 @@
.\" $NetBSD: ftpd.8,v 1.69 2002/02/08 01:30:07 ross Exp $
.\"
.\" Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
.\" Copyright (c) 1997-2002 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
@ -67,7 +67,7 @@
.\"
.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
.\"
.Dd October 13, 2001
.Dd October 25, 2002
.Dt FTPD 8
.Os
.Sh NAME
@ -734,7 +734,7 @@ and
.Cm draft-ietf-ftpext-mlst-11
support was implemented in
.Nx 1.3
and later releases by Luke Mewburn \*[Lt]lukem@netbsd.org\*[Gt].
and later releases by Luke Mewburn.
.Sh BUGS
The server must run as the super-user to create sockets with
privileged port numbers (i.e, those less than

View File

@ -1,4 +1,4 @@
/* $NetBSD: ftpd.c,v 1.138 2002/02/11 11:45:07 lukem Exp $ */
/* $NetBSD: ftpd.c,v 1.147 2002/11/29 14:40:00 lukem Exp $ */
/*
* Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
@ -98,20 +98,69 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT(
"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n");
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
#else
__RCSID("$NetBSD: ftpd.c,v 1.147 2002/11/29 14:40:00 lukem Exp $");
#endif
#endif /* not lint */
/*
* FTP server.
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#define FTP_NAMES
#include "lukemftpd.h"
#if HAVE_GETSPNAM
#include <shadow.h>
#endif
#include <arpa/ftp.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>
#include <ctype.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <glob.h>
#include <grp.h>
#include <limits.h>
#include <netdb.h>
#include <pwd.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <tzfile.h>
#include <unistd.h>
#include <util.h>
#ifdef SUPPORT_UTMP
#include <utmp.h>
#endif
#ifdef SUPPORT_UTMPX
#include <utmpx.h>
#endif
#ifdef SKEY
#include <skey.h>
#endif
@ -140,7 +189,12 @@ int mapped; /* IPv4 connection on AF_INET6 socket */
off_t file_size;
off_t byte_count;
static char ttyline[20];
#ifdef SUPPORT_UTMP
static struct utmp utmp; /* for utmp */
#endif
#ifdef SUPPORT_UTMPX
static struct utmpx utmpx; /* for utmpx */
#endif
static const char *anondir = NULL;
static const char *confdir = _DEFAULT_CONFDIR;
@ -166,6 +220,13 @@ int epsvall = 0;
int swaitmax = SWAITMAX;
int swaitint = SWAITINT;
enum send_status {
SS_SUCCESS,
SS_NO_TRANSFER, /* no transfer made yet */
SS_FILE_ERROR, /* file read error */
SS_DATA_ERROR /* data send error */
};
static int bind_pasv_addr(void);
static int checkuser(const char *, const char *, int, int, char **);
static int checkaccess(const char *);
@ -173,12 +234,21 @@ static int checkpassword(const struct passwd *, const char *);
static void end_login(void);
static FILE *getdatasock(const char *);
static char *gunique(const char *);
static void login_utmp(const char *, const char *, const char *);
static void logremotehost(struct sockinet *);
static void lostconn(int);
static void myoob(int);
static int receive_data(FILE *, FILE *);
static int send_data(FILE *, FILE *, off_t, int);
static int send_data(FILE *, FILE *, const struct stat *, int);
static struct passwd *sgetpwnam(const char *);
static int write_data(int, char *, size_t, off_t *, struct timeval *,
int);
static enum send_status
send_data_with_read(int, int, const struct stat *, int);
static enum send_status
send_data_with_mmap(int, int, const struct stat *, int);
static void logrusage(const struct rusage *, const struct rusage *);
static void logout_utmp(void);
int main(int, char *[]);
@ -191,8 +261,6 @@ int k5login(struct passwd *, char *, char *, char *);
void k5destroy(void);
#endif
char * __progname;
int
main(int argc, char *argv[])
{
@ -201,12 +269,7 @@ main(int argc, char *argv[])
krb5_error_code kerror;
#endif
char *p;
__progname = strrchr(argv[0], '/');
if (__progname == NULL)
__progname = argv[0];
else
__progname++;
long l;
connections = 1;
debug = 0;
@ -232,7 +295,7 @@ main(int argc, char *argv[])
* LOG_NDELAY sets up the logging connection immediately,
* necessary for anonymous ftp's that chroot and can't do it later.
*/
openlog("ftpd", LOG_PID | LOG_NDELAY, FTPD_LOGTYPE);
openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
while ((ch = getopt(argc, argv, "a:c:C:de:h:HlP:qQrst:T:uUvV:wWX"))
!= -1) {
@ -274,13 +337,17 @@ main(int argc, char *argv[])
break;
case 'P':
dataport = (int)strtol(optarg, &p, 10);
if (*p != '\0' || dataport < IPPORT_RESERVED ||
dataport > IPPORT_ANONMAX) {
errno = 0;
p = NULL;
l = strtol(optarg, &p, 10);
if (errno || *optarg == '\0' || *p != '\0' ||
l < IPPORT_RESERVED ||
l > IPPORT_ANONMAX) {
syslog(LOG_WARNING, "Invalid dataport %s",
optarg);
dataport = 0;
}
dataport = (int)l;
break;
case 'q':
@ -529,7 +596,7 @@ sgetpwnam(const char *name)
static int login_attempts; /* number of failed login attempts */
static int askpasswd; /* had USER command, ask for PASSwd */
static int permitted; /* USER permitted */
static char curname[10]; /* current USER name */
static char curname[LOGIN_NAME_MAX]; /* current USER name */
/*
* USER command.
@ -733,7 +800,7 @@ checkuser(const char *fname, const char *name, int def, int nofile,
line = 0;
for (;
(buf = fparseln(fd, &len, &line, NULL, FPARSELN_UNESCCOMM |
FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL;
FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL;
free(buf), buf = NULL) {
word = perm = class = NULL;
p = buf;
@ -850,6 +917,69 @@ checkaccess(const char *name)
return (checkuser(_PATH_FTPUSERS, name, 1, 0, NULL));
}
static void
login_utmp(const char *line, const char *name, const char *host)
{
#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
struct timeval tv;
(void)gettimeofday(&tv, NULL);
#endif
#ifdef SUPPORT_UTMPX
if (doutmp) {
(void)memset(&utmpx, 0, sizeof(utmpx));
utmpx.ut_tv = tv;
utmpx.ut_pid = getpid();
utmpx.ut_id[0] = 'f';
utmpx.ut_id[1] = 't';
utmpx.ut_id[2] = 'p';
utmpx.ut_id[3] = '*';
utmpx.ut_type = USER_PROCESS;
(void)strncpy(utmpx.ut_name, name, sizeof(utmpx.ut_name));
(void)strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line));
(void)strncpy(utmpx.ut_host, host, sizeof(utmpx.ut_host));
loginx(&utmpx);
}
if (dowtmp)
logwtmpx(line, name, host, 0, USER_PROCESS);
#endif
#ifdef SUPPORT_UTMP
if (doutmp) {
(void)memset(&utmp, 0, sizeof(utmp));
(void)time(&utmp.ut_time);
(void)strncpy(utmp.ut_name, name, sizeof(utmp.ut_name));
(void)strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
(void)strncpy(utmp.ut_host, host, sizeof(utmp.ut_host));
login(&utmp);
}
if (dowtmp)
logwtmp(line, name, host);
#endif
}
static void
logout_utmp(void)
{
int okwtmp = dowtmp;
if (logged_in) {
if (doutmp) {
#ifdef SUPPORT_UTMPX
okwtmp = logoutx(ttyline, 0, DEAD_PROCESS) & dowtmp;
#endif
#ifdef SUPPORT_UTMP
okwtmp = logout(ttyline) & dowtmp;
#endif
}
if (okwtmp) {
#ifdef SUPPORT_UTMPX
logwtmpx(ttyline, "", "", 0, DEAD_PROCESS);
#endif
#ifdef SUPPORT_UTMP
logwtmp(ttyline, "", "");
#endif
}
}
}
/*
* Terminate login as previous user (if any), resetting state;
* used when USER command is given or login fails.
@ -857,16 +987,7 @@ checkaccess(const char *name)
static void
end_login(void)
{
if (logged_in) {
#ifdef NO_UTMP
if (dowtmp)
logwtmp(ttyline, "", "");
if (doutmp)
logout(utmp.ut_line);
#endif /* NO_UTMP */
}
/* reset login state */
logout_utmp();
show_chdir_messages(-1); /* flush chdir cache */
if (pw != NULL && pw->pw_passwd != NULL)
memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
@ -885,8 +1006,6 @@ pass(const char *passwd)
{
int rval;
char root[MAXPATHLEN];
char *p;
int len;
if (logged_in || askpasswd == 0) {
reply(503, "Login with USER first.");
@ -976,21 +1095,8 @@ pass(const char *passwd)
/* cache groups for cmds.c::matchgroup() */
gidcount = getgroups(sizeof(gidlist), gidlist);
/* open wtmp before chroot */
#ifdef NO_UTMP
if (dowtmp)
logwtmp(ttyline, pw->pw_name, remotehost);
/* open utmp before chroot */
if (doutmp) {
memset((void *)&utmp, 0, sizeof(utmp));
(void)time(&utmp.ut_time);
(void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));
(void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));
(void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));
login(&utmp);
}
#endif /* NO_UTMP */
/* open utmp/wtmp before chroot */
login_utmp(ttyline, pw->pw_name, remotehost);
logged_in = 1;
@ -1002,11 +1108,13 @@ pass(const char *passwd)
(void)display_file(conffilename(curclass.limitfile),
530);
reply(530,
"User %s access denied, connection limit of %d reached.",
pw->pw_name, curclass.limit);
"User %s access denied, connection limit of " LLF
" reached.",
pw->pw_name, (LLT)curclass.limit);
syslog(LOG_NOTICE,
"Maximum connection limit of %d for class %s reached, login refused for %s",
curclass.limit, curclass.classname, pw->pw_name);
"Maximum connection limit of " LLF
" for class %s reached, login refused for %s",
(LLT)curclass.limit, curclass.classname, pw->pw_name);
goto bad;
}
@ -1099,9 +1207,7 @@ pass(const char *passwd)
}
break;
}
#if HAVE_SETLOGIN
setlogin(pw->pw_name);
#endif
if (dropprivs ||
(curclass.type != CLASS_REAL &&
ntohs(ctrl_addr.su_port) > IPPORT_RESERVED + 1)) {
@ -1120,15 +1226,7 @@ pass(const char *passwd)
goto bad;
}
}
len = sizeof("HOME=") + strlen(homedir) + 1;;
p = malloc(len);
if (p == NULL) {
reply(550, "Local resource failure: malloc");
goto bad;
}
snprintf(p, len, "HOME=%s", homedir);
putenv(p);
free(p);
setenv("HOME", homedir, 1);
if (curclass.type == CLASS_GUEST && passwd[0] == '-')
quietmessages = 1;
@ -1186,19 +1284,20 @@ retrieve(char *argv[], const char *name)
FILE *fin, *dout;
struct stat st;
int (*closefunc)(FILE *) = NULL;
int log, sendrv, closerv, stderrfd, isconversion, isdata, isls;
int dolog, sendrv, closerv, stderrfd, isconversion, isdata, isls;
struct timeval start, finish, td, *tdp;
struct rusage rusage_before, rusage_after;
const char *dispname;
char *error;
sendrv = closerv = stderrfd = -1;
isconversion = isdata = isls = log = 0;
isconversion = isdata = isls = dolog = 0;
tdp = NULL;
dispname = name;
fin = dout = NULL;
error = NULL;
if (argv == NULL) { /* if not running a command ... */
log = 1;
dolog = 1;
isdata = 1;
fin = fopen(name, "r");
closefunc = fclose;
@ -1231,7 +1330,7 @@ retrieve(char *argv[], const char *name)
if (fin == NULL) {
if (errno != 0) {
perror_reply(550, dispname);
if (log)
if (dolog)
logxfer("get", -1, name, NULL, NULL,
strerror(errno));
}
@ -1268,15 +1367,20 @@ retrieve(char *argv[], const char *name)
if (dout == NULL)
goto done;
(void)getrusage(RUSAGE_SELF, &rusage_before);
(void)gettimeofday(&start, NULL);
sendrv = send_data(fin, dout, st.st_blksize, isdata);
sendrv = send_data(fin, dout, &st, isdata);
(void)gettimeofday(&finish, NULL);
(void)getrusage(RUSAGE_SELF, &rusage_after);
closedataconn(dout); /* close now to affect timing stats */
timersub(&finish, &start, &td);
tdp = &td;
done:
if (log)
if (dolog) {
logxfer("get", byte_count, name, NULL, tdp, error);
if (tdp != NULL)
logrusage(&rusage_before, &rusage_after);
}
closerv = (*closefunc)(fin);
if (sendrv == 0) {
FILE *errf;
@ -1567,21 +1671,173 @@ closedataconn(FILE *fd)
pdata = -1;
}
int
write_data(int fd, char *buf, size_t size, off_t *bufrem,
struct timeval *then, int isdata)
{
struct timeval now, td;
ssize_t c;
while (size > 0) {
c = size;
if (curclass.writesize) {
if (curclass.writesize < c)
c = curclass.writesize;
}
if (curclass.rateget) {
if (*bufrem < c)
c = *bufrem;
}
(void) alarm(curclass.timeout);
c = write(fd, buf, c);
if (c <= 0)
return (1);
buf += c;
size -= c;
byte_count += c;
if (isdata) {
total_data_out += c;
total_data += c;
}
total_bytes_out += c;
total_bytes += c;
if (curclass.rateget) {
*bufrem -= c;
if (*bufrem == 0) {
(void)gettimeofday(&now, NULL);
timersub(&now, then, &td);
if (td.tv_sec == 0) {
usleep(1000000 - td.tv_usec);
(void)gettimeofday(then, NULL);
} else
*then = now;
*bufrem = curclass.rateget;
}
}
}
return (0);
}
static enum send_status
send_data_with_read(int filefd, int netfd, const struct stat *st, int isdata)
{
struct timeval then;
off_t bufrem;
size_t readsize;
char *buf;
int c, error;
if (curclass.readsize)
readsize = curclass.readsize;
else
readsize = (size_t)st->st_blksize;
if ((buf = malloc(readsize)) == NULL) {
perror_reply(451, "Local resource failure: malloc");
return (SS_NO_TRANSFER);
}
if (curclass.rateget) {
bufrem = curclass.rateget;
(void)gettimeofday(&then, NULL);
}
while (1) {
(void) alarm(curclass.timeout);
c = read(filefd, buf, readsize);
if (c == 0)
error = SS_SUCCESS;
else if (c < 0)
error = SS_FILE_ERROR;
else if (write_data(netfd, buf, c, &bufrem, &then, isdata))
error = SS_DATA_ERROR;
else
continue;
free(buf);
return (error);
}
}
static enum send_status
send_data_with_mmap(int filefd, int netfd, const struct stat *st, int isdata)
{
struct timeval then;
off_t bufrem, filesize, off, origoff;
size_t mapsize, winsize;
int error, sendbufsize, sendlowat;
void *win;
if (curclass.sendbufsize) {
sendbufsize = curclass.sendbufsize;
if (setsockopt(netfd, SOL_SOCKET, SO_SNDBUF,
&sendbufsize, sizeof(int)) == -1)
syslog(LOG_WARNING, "setsockopt(SO_SNDBUF, %d): %m",
sendbufsize);
}
if (curclass.sendlowat) {
sendlowat = curclass.sendlowat;
if (setsockopt(netfd, SOL_SOCKET, SO_SNDLOWAT,
&sendlowat, sizeof(int)) == -1)
syslog(LOG_WARNING, "setsockopt(SO_SNDLOWAT, %d): %m",
sendlowat);
}
winsize = curclass.mmapsize;
filesize = st->st_size;
if (debug)
syslog(LOG_INFO, "mmapsize = %ld, writesize = %ld",
(long)winsize, (long)curclass.writesize);
if (winsize == 0)
goto try_read;
off = lseek(filefd, (off_t)0, SEEK_CUR);
if (off == -1)
goto try_read;
origoff = off;
if (curclass.rateget) {
bufrem = curclass.rateget;
(void)gettimeofday(&then, NULL);
}
while (1) {
mapsize = MIN(filesize - off, winsize);
if (mapsize == 0)
break;
win = mmap(NULL, mapsize, PROT_READ,
MAP_FILE|MAP_SHARED, filefd, off);
if (win == MAP_FAILED) {
if (off == origoff)
goto try_read;
return (SS_FILE_ERROR);
}
(void) madvise(win, mapsize, MADV_SEQUENTIAL);
error = write_data(netfd, win, mapsize, &bufrem, &then,
isdata);
(void) madvise(win, mapsize, MADV_DONTNEED);
munmap(win, mapsize);
if (error)
return (SS_DATA_ERROR);
off += mapsize;
}
return (SS_SUCCESS);
try_read:
return (send_data_with_read(filefd, netfd, st, isdata));
}
/*
* Tranfer the contents of "instr" to "outstr" peer using the appropriate
* encapsulation of the data subject * to Mode, Structure, and Type.
* encapsulation of the data subject to Mode, Structure, and Type.
*
* NB: Form isn't handled.
*/
static int
send_data(FILE *instr, FILE *outstr, off_t blksize, int isdata)
send_data(FILE *instr, FILE *outstr, const struct stat *st, int isdata)
{
int c, filefd, netfd, rval;
char *buf;
transflag = 1;
rval = -1;
buf = NULL;
if (setjmp(urgcatch))
goto cleanup_send_data;
@ -1624,66 +1880,22 @@ send_data(FILE *instr, FILE *outstr, off_t blksize, int isdata)
case TYPE_I:
case TYPE_L:
if ((buf = malloc((size_t)blksize)) == NULL) {
perror_reply(451, "Local resource failure: malloc");
goto cleanup_send_data;
}
filefd = fileno(instr);
netfd = fileno(outstr);
(void) alarm(curclass.timeout);
if (curclass.rateget) {
while (1) {
int d;
struct timeval then, now, td;
off_t bufrem;
char *bufp;
switch (send_data_with_mmap(filefd, netfd, st, isdata)) {
(void)gettimeofday(&then, NULL);
errno = c = d = 0;
bufrem = curclass.rateget;
while (bufrem > 0) {
if ((c = read(filefd, buf,
MIN(blksize, bufrem))) <= 0)
goto senddone;
(void) alarm(curclass.timeout);
bufrem -= c;
byte_count += c;
if (isdata) {
total_data_out += c;
total_data += c;
}
total_bytes_out += c;
total_bytes += c;
for (bufp = buf; c > 0;
c -= d, bufp += d)
if ((d =
write(netfd, bufp, c)) <= 0)
break;
if (d < 0)
goto data_err;
}
(void)gettimeofday(&now, NULL);
timersub(&now, &then, &td);
if (td.tv_sec == 0)
usleep(1000000 - td.tv_usec);
}
} else {
while ((c = read(filefd, buf, (size_t)blksize)) > 0) {
if (write(netfd, buf, c) != c)
goto data_err;
(void) alarm(curclass.timeout);
byte_count += c;
if (isdata) {
total_data_out += c;
total_data += c;
}
total_bytes_out += c;
total_bytes += c;
}
}
senddone:
if (c < 0)
case SS_SUCCESS:
break;
case SS_NO_TRANSFER:
goto cleanup_send_data;
case SS_FILE_ERROR:
goto file_err;
case SS_DATA_ERROR:
goto data_err;
}
rval = 0;
goto cleanup_send_data;
@ -1705,8 +1917,6 @@ send_data(FILE *instr, FILE *outstr, off_t blksize, int isdata)
cleanup_send_data:
(void) alarm(0);
transflag = 0;
if (buf)
free(buf);
if (isdata) {
total_files_out++;
total_files++;
@ -1888,7 +2098,7 @@ statcmd(void)
{
struct sockinet *su = NULL;
static char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
u_char *a, *p;
u_char *a, *p;
int ispassive, af;
off_t otbi, otbo, otb;
@ -1929,7 +2139,7 @@ statcmd(void)
strunames[stru], modenames[mode]);
ispassive = 0;
if (data != -1) {
reply(0, "Data connection open");
reply(0, "Data connection open");
su = NULL;
} else if (pdata != -1) {
reply(0, "in Passive mode");
@ -2053,13 +2263,14 @@ statcmd(void)
reply(0, "Display file: %s", curclass.display);
if (! EMPTYSTR(curclass.notify))
reply(0, "Notify fileglob: %s", curclass.notify);
reply(0, "Idle timeout: %d, maximum timeout: %d",
curclass.timeout, curclass.maxtimeout);
reply(0, "Idle timeout: " LLF ", maximum timeout: " LLF,
(LLT)curclass.timeout, (LLT)curclass.maxtimeout);
reply(0, "Current connections: %d", connections);
if (curclass.limit == -1)
reply(0, "Maximum connections: unlimited");
else
reply(0, "Maximum connections: %d", curclass.limit);
reply(0, "Maximum connections: " LLF,
(LLT)curclass.limit);
if (curclass.limitfile)
reply(0, "Connection limit exceeded message file: %s",
conffilename(curclass.limitfile));
@ -2096,8 +2307,8 @@ statcmd(void)
reply(0, "PASV advertise address: %s", bp);
}
if (curclass.portmin && curclass.portmax)
reply(0, "PASV port range: %d - %d",
curclass.portmin, curclass.portmax);
reply(0, "PASV port range: " LLF " - " LLF,
(LLT)curclass.portmin, (LLT)curclass.portmax);
if (curclass.rateget)
reply(0, "Rate get limit: " LLF " bytes/sec",
(LLT)curclass.rateget);
@ -2108,6 +2319,28 @@ statcmd(void)
(LLT)curclass.rateput);
else
reply(0, "Rate put limit: disabled");
if (curclass.mmapsize)
reply(0, "Mmap size: " LLF, (LLT)curclass.mmapsize);
else
reply(0, "Mmap size: disabled");
if (curclass.readsize)
reply(0, "Read size: " LLF, (LLT)curclass.readsize);
else
reply(0, "Read size: default");
if (curclass.writesize)
reply(0, "Write size: " LLF, (LLT)curclass.writesize);
else
reply(0, "Write size: default");
if (curclass.sendbufsize)
reply(0, "Send buffer size: " LLF,
(LLT)curclass.sendbufsize);
else
reply(0, "Send buffer size: default");
if (curclass.sendlowat)
reply(0, "Send low water mark: " LLF,
(LLT)curclass.sendlowat);
else
reply(0, "Send low water mark: default");
reply(0, "Umask: %.04o", curclass.umask);
for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
if (cp->suffix == NULL || cp->types == NULL ||
@ -2195,14 +2428,8 @@ dologout(int status)
* back to the main program loop.
*/
transflag = 0;
logout_utmp();
if (logged_in) {
#ifdef NO_UTMP
if (dowtmp)
logwtmp(ttyline, "", "");
if (doutmp)
logout(utmp.ut_line);
#endif /* NO_UTMP */
#ifdef KERBEROS
if (!notickets && krbtkfile_env)
unlink(krbtkfile_env);
@ -2535,13 +2762,15 @@ extended_port(const char *arg)
}
/* some more sanity checks */
errno = 0;
p = NULL;
(void)strtoul(result[2], &p, 10);
if (!*result[2] || *p)
if (errno || !*result[2] || *p)
goto parsefail;
errno = 0;
p = NULL;
proto = strtoul(result[0], &p, 10);
if (!*result[0] || *p)
if (errno || !*result[0] || *p)
goto protounsupp;
memset(&hints, 0, sizeof(hints));
@ -2830,12 +3059,12 @@ conffilename(const char *s)
* if elapsed != NULL, append "in xxx.yyy seconds"
* if error != NULL, append ": " + error
*
* if doxferlog != 0, bytes != -1, and command is "get", "put",
* if doxferlog != 0, bytes != -1, and command is "get", "put",
* or "append", syslog a wu-ftpd style xferlog entry
*/
void
logxfer(const char *command, off_t bytes, const char *file1, const char *file2,
const struct timeval *elapsed, const char *error)
const struct timeval *elapsed, const char *error)
{
char buf[MAXPATHLEN * 2 + 100], realfile[MAXPATHLEN];
const char *r1, *r2;
@ -2921,6 +3150,31 @@ logxfer(const char *command, off_t bytes, const char *file1, const char *file2,
);
}
/*
* Log the resource usage.
*
* XXX: more resource usage to logging?
*/
void
logrusage(const struct rusage *rusage_before,
const struct rusage *rusage_after)
{
struct timeval usrtime, systime;
if (logging <= 1)
return;
timersub(&rusage_after->ru_utime, &rusage_before->ru_utime, &usrtime);
timersub(&rusage_after->ru_stime, &rusage_before->ru_stime, &systime);
syslog(LOG_INFO, "%ld.%.03du %ld.%.03ds %ld+%ldio %ldpf+%ldw",
usrtime.tv_sec, (int)(usrtime.tv_usec / 1000),
systime.tv_sec, (int)(systime.tv_usec / 1000),
rusage_after->ru_inblock - rusage_before->ru_inblock,
rusage_after->ru_oublock - rusage_before->ru_oublock,
rusage_after->ru_majflt - rusage_before->ru_majflt,
rusage_after->ru_nswap - rusage_before->ru_nswap);
}
/*
* Determine if `password' is valid for user given in `pw'.
* Returns 2 if password expired, 1 if otherwise failed, 0 if ok
@ -2930,24 +3184,13 @@ checkpassword(const struct passwd *pwent, const char *password)
{
char *orig, *new;
time_t expire;
#if HAVE_GETSPNAM
struct spwd *spw;
#endif
expire = 0;
if (pwent == NULL)
return 1;
#if HAVE_GETSPNAM
if ((spw = getspnam(pwent->pw_name)) == NULL)
return 1;
orig = spw->sp_pwdp;
#else
orig = pwent->pw_passwd; /* save existing password */
#if HAVE_PW_EXPIRE
expire = pwent->pw_expire;
#endif
#endif /* HAVE_GETSPNAM */
if (orig[0] == '\0') /* don't allow empty passwords */
return 1;

View File

@ -1,4 +1,4 @@
.\" $NetBSD: ftpd.conf.5,v 1.19 2002/01/15 02:20:50 wiz Exp $
.\" $NetBSD: ftpd.conf.5,v 1.24 2002/11/29 14:40:00 lukem Exp $
.\"
.\" Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
.\" All rights reserved.
@ -34,7 +34,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd December 5, 2001
.Dd November 30, 2002
.Dt FTPD.CONF 5
.Os
.Sh NAME
@ -121,8 +121,8 @@ directive is set for the class.
.Pp
Each configuration line may be one of:
.Bl -tag -width 4n
.It Sy advertise Ar class Ar host
.It Sy advertize Ar class Ar host
.It Sy advertise Ar class Op Ar host
.It Sy advertize Ar class Op Ar host
Set the address to advertise in the response to the
.Sy PASV
and
@ -137,7 +137,9 @@ If
.Ar class
is
.Dq none
or no argument is given, disable this.
or
.Ar host
not is specified, disable this.
.It Sy checkportcmd Ar class Op Sy off
Check the
.Sy PORT
@ -150,7 +152,7 @@ command connection, or if the remote TCP port number is less than
.Dv IPPORT_RESERVED .
It is
.Em strongly
encouraged that this option be used, espcially for sites concerned
encouraged that this option be used, especially for sites concerned
with potential security problems with
.Tn FTP
bounce attacks.
@ -160,11 +162,11 @@ is
.Dq none
or
.Sy off
is given, disable this feature, otherwise enable it.
is specified, disable this feature, otherwise enable it.
.It Sy chroot Ar class Op Sy pathformat
If
.Ar pathformat
is not given or
is not specified or
.Ar class
is
.Dq none ,
@ -199,7 +201,7 @@ The user's home directory.
.It Sy GUEST
If
.Fl a Ar anondir
is given, use
is specified, use
.Ar anondir ,
otherwise the home directory of the
.Sq ftp
@ -285,11 +287,11 @@ is
.Dq none
or
.Sy off
is given, disable this feature, otherwise enable it.
is specified, disable this feature, otherwise enable it.
.It Sy display Ar class Op Ar file
If
.Ar file
is not given or
is not specified or
.Ar class
is
.Dq none ,
@ -305,7 +307,7 @@ for more information.
.It Sy homedir Ar class Op Sy pathformat
If
.Ar pathformat
is not given or
is not specified or
.Ar class
is
.Dq none ,
@ -331,18 +333,18 @@ and
.Sy CHROOT
users.
.It Xo Sy limit Ar class
.Ar count Op Ar file
.Op Ar count Op Ar file
.Xc
Limit the maximum number of concurrent connections for
.Ar class
to
.Ar count ,
with
.Sq 0
.Sq \-1
meaning unlimited connections.
If the limit is exceeded and
.Ar file
is given, display its contents to the user.
is specified, display its contents to the user.
If
.Ar class
is
@ -356,15 +358,20 @@ is a relative path, it will be searched for in
.Pa /etc
(which can be overridden with
.Fl c Ar confdir ) .
.It Sy maxfilesize Ar class Ar size
.It Sy maxfilesize Ar class Op Ar size
Set the maximum size of an uploaded file to
.Ar size .
.Ar size ,
with
.Sq \-1
meaning unlimited connections.
If
.Ar class
is
.Dq none
or no argument is given, disable this.
.It Sy maxtimeout Ar class Ar time
or
.Ar size
is not specified, disable this.
.It Sy maxtimeout Ar class Op Ar time
Set the maximum timeout period that a client may request,
defaulting to two hours.
This cannot be less than 30 seconds, or the value for
@ -375,7 +382,26 @@ is
.Dq none
or
.Ar time
is not specified, set to default of 2 hours.
is not specified, use the default.
.It Sy mmapsize Ar class Op Ar size
Set the size of the sliding window to map a file using
.Xr mmap 2 .
If zero,
.Xr ftpd 8
will use
.Xr read 2
instead.
The default is zero.
An optional suffix may be provided as per
.Sy rateget .
This option affects only binary transfers.
If
.Ar class
is
.Dq none
or
.Ar size
is not specified, use the default.
.It Sy modify Ar class Op Sy off
If
.Ar class
@ -383,7 +409,7 @@ is
.Dq none
or
.Sy off
is given, disable the following commands:
is specified, disable the following commands:
.Sy CHMOD ,
.Sy DELE ,
.Sy MKD ,
@ -395,7 +421,7 @@ Otherwise, enable them.
.It Sy motd Ar class Op Ar file
If
.Ar file
is not given or
is not specified or
.Ar class
is
.Dq none ,
@ -417,7 +443,7 @@ is a relative path, it will be searched for in
.It Sy notify Ar class Op Ar fileglob
If
.Ar fileglob
is not given or
is not specified or
.Ar class
is
.Dq none ,
@ -432,14 +458,16 @@ is
.Dq none
or
.Sy off
is given, prevent passive
is specified, prevent passive
.Sy ( PASV ,
.Sy LPSV ,
and
.Sy EPSV )
connections.
Otherwise, enable them.
.It Sy portrange Ar class Ar min Ar max
.It Sy portrange Ar class Oo
.Ar min Ar max
.Oc
Set the range of port number which will be used for the passive data port.
.Ar max
must be greater than
@ -451,7 +479,7 @@ If
.Ar class
is
.Dq none
or no arguments are given, disable this.
or no arguments are specified, disable this.
.It Sy private Ar class Op Sy off
If
.Ar class
@ -459,11 +487,11 @@ is
.Dq none
or
.Sy off
is given, do not display class information in the output of the
is specified, do not display class information in the output of the
.Sy STAT
command.
Otherwise, display the information.
.It Sy rateget Ar class Ar rate
.It Sy rateget Ar class Op Ar rate
Set the maximum get
.Pq Sy RETR
transfer rate throttle for
@ -478,14 +506,17 @@ If
.Ar class
is
.Dq none
or no arguments are given, disable this.
or
.Ar rate
is not specified, disable this.
.Pp
An optional suffix may be provided, which changes the intrepretation of
An optional suffix may be provided, which changes the interpretation of
.Ar rate
as follows:
.Bl -tag -width 3n -offset indent -compact
.It b
Causes no modification. (Default; optional)
Causes no modification.
(Default; optional)
.It k
Kilo; multiply the argument by 1024
.It m
@ -495,7 +526,7 @@ Giga; multiply the argument by 1073741824
.It t
Tera; multiply the argument by 1099511627776
.El
.It Sy rateput Ar class Ar rate
.It Sy rateput Ar class Op Ar rate
Set the maximum put
.Pq Sy STOR
transfer rate throttle for
@ -509,7 +540,24 @@ If
.Ar class
is
.Dq none
or no arguments are given, disable this.
or
.Ar rate
is not specified, disable this.
.It Sy readsize Ar class Op Ar size
Set the size of the read buffer to
.Xr read 2
a file.
The default is the file system block size.
An optional suffix may be provided as per
.Sy rateget .
This option affects only binary transfers.
If
.Ar class
is
.Dq none
or
.Ar size
is not specified, use the default.
.It Sy sanenames Ar class Op Sy off
If
.Ar class
@ -517,12 +565,38 @@ is
.Dq none
or
.Sy off
is given, allow uploaded file names to contain any characters valid for a
is specified, allow uploaded file names to contain any characters valid for a
file name.
Otherwise, only permit file names which don't start with a
.Sq \&.
and only comprise of characters from the set
.Dq [-+,._A-Za-z0-9] .
.It Sy sendbufsize Ar class Op Ar size
Set the size of the socket send buffer.
An optional suffix may be provided as per
.Sy rateget .
The default is zero and the system default value will be used.
This option affects only binary transfers.
If
.Ar class
is
.Dq none
or
.Ar size
is not specified, use the default.
.It Sy sendlowat Ar class Op Ar size
Set the low water mark of socket send buffer.
An optional suffix may be provided as per
.Sy rateget .
The default is zero and system default value will be used.
This option affects only for binary transfer.
If
.Ar class
is
.Dq none
or
.Ar size
is not specified, use the default.
.It Sy template Ar class Op Ar refclass
Define
.Ar refclass
@ -540,9 +614,9 @@ duplication.
There can be only one template defined at a time.
If
.Ar refclass
is not given, disable the template for
is not specified, disable the template for
.Ar class .
.It Sy timeout Ar class Ar time
.It Sy timeout Ar class Op Ar time
Set the inactivity timeout period.
(the default is fifteen minutes).
This cannot be less than 30 seconds, or greater than the value for
@ -553,8 +627,8 @@ is
.Dq none
or
.Ar time
is not specified, set to the default of 15 minutes.
.It Sy umask Ar class Ar umaskval
is not specified, use the default.
.It Sy umask Ar class Op Ar umaskval
Set the umask to
.Ar umaskval .
If
@ -572,7 +646,7 @@ is
.Dq none
or
.Sy off
is given, disable the following commands:
is specified, disable the following commands:
.Sy APPE ,
.Sy STOR ,
and
@ -586,6 +660,25 @@ as well as the modify commands:
and
.Sy UMASK .
Otherwise, enable them.
.It Sy writesize Ar class Op Ar size
Limit the number of bytes to
.Xr write 2
at a time.
The default is zero, which means all the data available as a result of
.Xr mmap 2
or
.Xr read 2
will be written at a time.
An optional suffix may be provided as per
.Sy rateget .
This option affects only binary transfers.
If
.Ar class
is
.Dq none
or
.Ar size
is not specified, use the default.
.El
.Sh DEFAULTS
The following defaults are used:
@ -596,7 +689,7 @@ classtype chroot CHROOT
classtype guest GUEST
classtype real REAL
display none
limit all -1 # unlimited connections
limit all \-1 # unlimited connections
maxtimeout all 7200 # 2 hours
modify all
motd all motd
@ -618,6 +711,7 @@ A sample
file.
.El
.Sh SEE ALSO
.Xr strsuftoll 3 ,
.Xr ftpchroot 5 ,
.Xr ftpusers 5 ,
.Xr ftpd 8

View File

@ -1,4 +1,4 @@
.\" $NetBSD: ftpusers.5,v 1.13 2001/12/01 16:24:24 wiz Exp $
.\" $NetBSD: ftpusers.5,v 1.12 2001/12/01 10:16:06 lukem Exp $
.\"
.\" Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
.\" All rights reserved.

View File

@ -32,7 +32,16 @@
* SUCH DAMAGE.
*/
#include "lukemftpd.h"
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ttyent.h>
#include <unistd.h>
#include <utmp.h>
#include <util.h>
typedef struct utmp UTMP;
@ -60,7 +69,7 @@ login(const UTMP *ut)
}
if ((topslot < 0) || ((fd < 0)
&& (fd = open(_PATH_UTMP, O_RDWR|O_CREAT, 0644)) < 0))
return;
return;
/*
* Now find a slot that's not in use...

View File

@ -1,4 +1,4 @@
/* $NetBSD: logwtmp.c,v 1.16 2001/02/04 22:04:12 christos Exp $ */
/* $NetBSD: logwtmp.c,v 1.17 2002/09/12 08:55:31 itojun Exp $ */
/*
* Copyright (c) 1988, 1993
@ -34,7 +34,34 @@
*
*/
#include "lukemftpd.h"
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)logwtmp.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: logwtmp.c,v 1.17 2002/09/12 08:55:31 itojun Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <utmp.h>
#include <util.h>
#ifdef KERBEROS5
#include <krb5/krb5.h>
#endif
#include "extern.h"

View File

@ -1,4 +1,4 @@
/* $NetBSD: pathnames.h,v 1.10 2000/03/06 21:42:26 lukem Exp $ */
/* $NetBSD: pathnames.h,v 1.9 2000/01/08 11:09:56 lukem Exp $ */
/*
* Copyright (c) 1989, 1993
@ -35,6 +35,8 @@
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
*/
#include <paths.h>
#ifndef _DEFAULT_CONFDIR
#define _DEFAULT_CONFDIR "/etc"
#endif
@ -42,7 +44,6 @@
#define _PATH_FTPCHROOT "ftpchroot"
#define _PATH_FTPDCONF "ftpd.conf"
#define _PATH_FTPLOGINMESG "motd"
#undef _PATH_FTPUSERS
#define _PATH_FTPUSERS "ftpusers"
#define _PATH_FTPWELCOME "ftpwelcome"

View File

@ -1,4 +1,4 @@
/* $NetBSD: popen.c,v 1.27 2001/12/01 10:25:30 lukem Exp $ */
/* $NetBSD: popen.c,v 1.26 2001/04/25 01:46:26 lukem Exp $ */
/*-
* Copyright (c) 1999-2001 The NetBSD Foundation, Inc.
@ -73,7 +73,33 @@
*
*/
#include "lukemftpd.h"
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94";
#else
__RCSID("$NetBSD: popen.c,v 1.26 2001/04/25 01:46:26 lukem Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <errno.h>
#include <glob.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <syslog.h>
#include <unistd.h>
#ifdef KERBEROS5
#include <krb5/krb5.h>
#endif
#include "extern.h"
@ -146,11 +172,7 @@ ftpd_popen(char *argv[], const char *ptype, int stderrfd)
isls = (strcmp(sl->sl_str[0], INTERNAL_LS) == 0);
#endif
#if HAVE_VFORK
pid = isls ? fork() : vfork();
#else
pid = fork();
#endif
switch (pid) {
case -1: /* error */
(void)close(pdes[0]);
@ -177,10 +199,7 @@ ftpd_popen(char *argv[], const char *ptype, int stderrfd)
}
#ifndef NO_INTERNAL_LS
if (isls) { /* use internal ls */
#if HAVE_OPTRESET
optreset = 1;
#endif
optind = optopt = 1;
optreset = optind = optopt = 1;
closelog();
exit(ls_main(sl->sl_cur - 1, sl->sl_str));
}

View File

@ -1,6 +1,6 @@
/* $NetBSD: version.h,v 1.42 2002/02/13 15:15:23 lukem Exp $ */
/* $NetBSD: version.h,v 1.48 2002/10/26 04:19:56 lukem Exp $ */
/*-
* Copyright (c) 1999-2001 The NetBSD Foundation, Inc.
* Copyright (c) 1999-2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -36,5 +36,5 @@
*/
#ifndef FTPD_VERSION
#define FTPD_VERSION "NetBSD-ftpd 20020214"
#define FTPD_VERSION "NetBSD-ftpd 20021130"
#endif