From c9e7985f5a090a80dd013a9bd5b8f3fad5c555ea Mon Sep 17 00:00:00 2001 From: obrien Date: Mon, 6 Jan 2003 00:06:49 +0000 Subject: 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. --- contrib/lukemftpd/src/Makefile | 46 ++++ contrib/lukemftpd/src/cmds.c | 36 ++- contrib/lukemftpd/src/conf.c | 320 ++++++++------------- contrib/lukemftpd/src/extern.h | 42 ++- contrib/lukemftpd/src/ftpcmd.y | 213 +++++++++----- contrib/lukemftpd/src/ftpd.8 | 6 +- contrib/lukemftpd/src/ftpd.c | 567 +++++++++++++++++++++++++++----------- contrib/lukemftpd/src/ftpd.conf.5 | 174 +++++++++--- contrib/lukemftpd/src/ftpusers.5 | 2 +- contrib/lukemftpd/src/logutmp.c | 13 +- contrib/lukemftpd/src/logwtmp.c | 31 ++- contrib/lukemftpd/src/pathnames.h | 5 +- contrib/lukemftpd/src/popen.c | 39 ++- contrib/lukemftpd/src/version.h | 6 +- 14 files changed, 976 insertions(+), 524 deletions(-) create mode 100644 contrib/lukemftpd/src/Makefile (limited to 'contrib/lukemftpd') diff --git a/contrib/lukemftpd/src/Makefile b/contrib/lukemftpd/src/Makefile new file mode 100644 index 0000000..a70e43b --- /dev/null +++ b/contrib/lukemftpd/src/Makefile @@ -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 + +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 + +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 diff --git a/contrib/lukemftpd/src/cmds.c b/contrib/lukemftpd/src/cmds.c index 5f5db9f..334078f 100644 --- a/contrib/lukemftpd/src/cmds.c +++ b/contrib/lukemftpd/src/cmds.c @@ -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 +#ifndef lint +__RCSID("$NetBSD: cmds.c,v 1.18 2002/10/12 08:35:16 darrenr Exp $"); +#endif /* not lint */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KERBEROS5 +#include +#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"); diff --git a/contrib/lukemftpd/src/conf.c b/contrib/lukemftpd/src/conf.c index 8ec927f..8f05793 100644 --- a/contrib/lukemftpd/src/conf.c +++ b/contrib/lukemftpd/src/conf.c @@ -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 +#ifndef lint +__RCSID("$NetBSD: conf.c,v 1.50 2002/11/16 03:10:34 itojun Exp $"); +#endif /* not lint */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KERBEROS5 +#include +#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; @@ -891,51 +873,6 @@ do_conversion(const char *fname) } /* - * 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- * Does a kill -0 on each pid in that file, and only counts @@ -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); } diff --git a/contrib/lukemftpd/src/extern.h b/contrib/lukemftpd/src/extern.h index 3ddb6bf..25cdf11 100644 --- a/contrib/lukemftpd/src/extern.h +++ b/contrib/lukemftpd/src/extern.h @@ -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" : \ "" #define ISDOTDIR(x) (x[0] == '.' && x[1] == '\0') diff --git a/contrib/lukemftpd/src/ftpcmd.y b/contrib/lukemftpd/src/ftpcmd.y index 68a598b..1039d51 100644 --- a/contrib/lukemftpd/src/ftpcmd.y +++ b/contrib/lukemftpd/src/ftpcmd.y @@ -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 + +#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 +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KERBEROS5 +#include +#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 STRING %token ALL -%token NUMBER +%token NUMBER -%type check_login octal_number byte_size -%type struct_code mode_code type_code form_code decimal_integer +%type check_login octal_number byte_size +%type struct_code mode_code type_code form_code decimal_integer %type pathstring pathname password username %type 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, " mode file-name" }, - { "HELP", HELP, OSTR, 1, "[ ]" }, - { "IDLE", IDLE, ARGS, 1, "[ maximum-idle-time ]" }, - { "RATEGET", RATEGET,OSTR, 1, "[ get-throttle-rate ]" }, - { "RATEPUT", RATEPUT,OSTR, 1, "[ put-throttle-rate ]" }, - { "UMASK", UMASK, ARGS, 1, "[ umask ]" }, - { NULL, 0, 0, 0, NULL } + { "CHMOD", CHMOD, NSTR, 1, " mode file-name" }, + { "HELP", HELP, OSTR, 1, "[ ]" }, + { "IDLE", IDLE, ARGS, 1, "[ maximum-idle-time ]" }, + { "RATEGET", RATEGET,OSTR, 1, "[ get-throttle-rate ]" }, + { "RATEPUT", RATEPUT,OSTR, 1, "[ put-throttle-rate ]" }, + { "UMASK", UMASK, ARGS, 1, "[ 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); } diff --git a/contrib/lukemftpd/src/ftpd.8 b/contrib/lukemftpd/src/ftpd.8 index 5aaadf0..d024633 100644 --- a/contrib/lukemftpd/src/ftpd.8 +++ b/contrib/lukemftpd/src/ftpd.8 @@ -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 diff --git a/contrib/lukemftpd/src/ftpd.c b/contrib/lukemftpd/src/ftpd.c index 7170536..de19ccc 100644 --- a/contrib/lukemftpd/src/ftpd.c +++ b/contrib/lukemftpd/src/ftpd.c @@ -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 +#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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include #define FTP_NAMES - -#include "lukemftpd.h" - -#if HAVE_GETSPNAM -#include -#endif - +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SUPPORT_UTMP +#include +#endif +#ifdef SUPPORT_UTMPX +#include +#endif #ifdef SKEY #include #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; @@ -2922,6 +3151,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; diff --git a/contrib/lukemftpd/src/ftpd.conf.5 b/contrib/lukemftpd/src/ftpd.conf.5 index df3dbcb..f06c907 100644 --- a/contrib/lukemftpd/src/ftpd.conf.5 +++ b/contrib/lukemftpd/src/ftpd.conf.5 @@ -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 diff --git a/contrib/lukemftpd/src/ftpusers.5 b/contrib/lukemftpd/src/ftpusers.5 index 3e87688..7b26035 100644 --- a/contrib/lukemftpd/src/ftpusers.5 +++ b/contrib/lukemftpd/src/ftpusers.5 @@ -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. diff --git a/contrib/lukemftpd/src/logutmp.c b/contrib/lukemftpd/src/logutmp.c index 7ef6437..cdd05bc 100644 --- a/contrib/lukemftpd/src/logutmp.c +++ b/contrib/lukemftpd/src/logutmp.c @@ -32,7 +32,16 @@ * SUCH DAMAGE. */ -#include "lukemftpd.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include 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... diff --git a/contrib/lukemftpd/src/logwtmp.c b/contrib/lukemftpd/src/logwtmp.c index b7f2925..5da4a1d 100644 --- a/contrib/lukemftpd/src/logwtmp.c +++ b/contrib/lukemftpd/src/logwtmp.c @@ -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 +#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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KERBEROS5 +#include +#endif #include "extern.h" diff --git a/contrib/lukemftpd/src/pathnames.h b/contrib/lukemftpd/src/pathnames.h index a5766b5..056122e 100644 --- a/contrib/lukemftpd/src/pathnames.h +++ b/contrib/lukemftpd/src/pathnames.h @@ -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 + #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" diff --git a/contrib/lukemftpd/src/popen.c b/contrib/lukemftpd/src/popen.c index 95123e7..aaaebca 100644 --- a/contrib/lukemftpd/src/popen.c +++ b/contrib/lukemftpd/src/popen.c @@ -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 +#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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KERBEROS5 +#include +#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)); } diff --git a/contrib/lukemftpd/src/version.h b/contrib/lukemftpd/src/version.h index e741257..482a47a 100644 --- a/contrib/lukemftpd/src/version.h +++ b/contrib/lukemftpd/src/version.h @@ -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 -- cgit v1.1