maxfilesize set the maximum size of uploaded files
sanenames if set, only permit uploaded filenames that contain
characters from the set "-+,._A-Za-z0-9" and that
don't start with `.'
- new/changed command line options:
-e emailaddr define email address for %E (see below)
-P dataport use dataport as the dataport (instead of ctrlport-1)
-q use pid files to count users [default]
-Q don't use pid files to count users
-u write entries to utmp
-U don't write entries to utmp [default]
-w write entries to wtmp [default]
-W don't write entries to wtmp
NOTE: -U used to mean `write utmp entries'. Its meaning has changed
so that it's orthogonal with -q/-Q and -w/-W. This isn't
considered a major problem, because using -U isn't going to
enable something you don't want, but will disable something
you did want (which is safer).
- new display file escape sequences:
%E email address
%s literal `s' if the previous %M or %N wasn't ``1''.
%S literal `S' if the previous %M or %N wasn't ``1''.
- expand the description of building ~ftp/incoming to cover the
appropriate ftpd.conf(5) directives (which are defaults, but it pays
to explicitly explain them)
- replace strsuftoi() with strsuftoll(), which returns a long long if
supported, otherwise a long
- rework the way that check_modify and check_upload are done in the yacc
parser; they're merged into a common check_write() function which is
called explicitly
- merge all ftpclass `flag variables' into a single bitfield-based flag element
- move various common bits of parse_conf() into a couple of macros
- clean up some comments
* replace union sockunion {} with struct sockinet {}, and modify the code
accordingly. this is possibly more portable, as it doesn't rely upon
the structure alignment within the union for our own stuff. uses local
su_len unless HAVE_SOCKADDR_SA_LEN is defined (set ifdef BSD4_4)
(XXX: haven't tested the ipv6 stuff)
* always use getaddrinfo() and getnameinfo() instead of maintaining two code
paths. (lukemftpd will provide replacements for these on older systems)
* use lockf() instead of open(.., O_EXLOCK) to lock the pid file
* minor KNF
* clean up long long support: create helper #defines and use as appropriate:
#define NO_LONG_LONG ! NO_LONG_LONG
------- ------------ --------------
LLF "%ld" "%lld"
LLFP(x) "%" x "ld" "%" x "lld"
LLT long long long
ULLF "%lu" "%llu"
ULLFP(x) "%" x "lu" "%" x "llu"
ULLT unsigned long unsigned long long
STRTOLL(x,y,z) strtol(x,y,z) strtoll(x,y,z)
return 522 on unknown protocol identifier on EPRT.
- clarify EPSV/EPRT/LPSV/LPRT behavior.
- repair memory leak and lack of boundary check on EPRT.
- make sure we do not resolve DNS on EPRT.
sync with kame.
This ftpd now compiles and runs on NetBSD/1.4.2 with:
CPPFLAGS+= \
'-Dstrlcpy(a,b,c)=(strncpy(a,b,c),strlen(a))' \
'-Dstrlcat=strncat' \
'-Dsl_add(a,b)=(sl_add(a,b),0)'
prevents the ftp bounce attack, and we should be secure out of the
box, not require users to tweak obscure stuff.
* allow the version string reported to clients to be changed with '-V vers'.
if vers is empty or `-', don't report a version.
* if -r is given, permanently drop root privs
* if not a REAL user (i.e, GUEST or CHROOT), and ftpd is running on a port
> IPPORT_RESERVED+1, permanently drop root privs
* don't bother reverting to root privs to logout of wtmp/utmp; since the
file descriptor is already open this isn't necessary.
* fix the binding of the port for the PORT/LPRT/EPRT connection to be the
ctrl_addr.su_port-1, not hardcoded to `20' (this was broken in the ipv6
merge). if root privs have been dropped, and this would be a port <
IPPORT_RESERVED, use a random port instead (which isn't RFC959 compliant
but it doesn't appear that many clients care).
* prevent login of a new user if privs have been dropped and already logged
in as a REAL user (existing check already stops GUEST & CHROOT users).
* move the port check stuff into a separate port_check() function, and use
for PORT, LPRT, and EPRT checks. inspired by freebsd
* minor KNF
* minor man page cleanup
chroot specify dir to chroot to for GUEST and CHROOT users, to
override -a anondir or the user's homedir.
homedir specify dir to change to upon login; also used for ~ expansion
and $HOME for subprocesses)
both of these can take % escapes: %u (username), %d (homedir), %c (class).
* fix NLST to take a pathname not a STRING, so that ~ expansion works
* modify CWD to use the homedir parsed from curclass.homedir
* implement format_path(dst, src), to parse src expanding % escapes (see above)
into dst.
* rename format_file() to display_file()
appears to match that of 'mimencode' (from metamail).
problem noted by kre@munnari.oz.au.
- fact_unique(): encode a combined dev_t+ino_t chunk rather than separate bits
* fix RATE{GET,PUT} under some situations when the client is slower than
the server (something i missed when migrating the rate limiting code
i wrote in ftp(1) to ftpd(8))
* document what units RATE{GET,PUT} use
adding support for Heimdal/KTH Kerberos where easy to do so. Eliminate
bsd.crypto.mk.
There is still a bunch more work to do, but crypto is now more-or-less
fully merged into the base NetBSD distribution.
* implement closedataconn() and use appropriately (including in mlsd())
* only put leading space in front of MLST output (not MLSD output)
* MLSD: only output pdir and cdir entries when the type fact is requested.
* change error code for giving MLSD a non-directory from 550 to 501
* remove MLSx Type fact support for UNIX.* for now; it's not standardised yet.
* do a check_login when MLSD and MLST are given no args
* detect & complain about null facts in OPTS MLST
* cache getgroups() at login instead of calling each time in fact_perm()
other mods:
* implement cprintf(); as per fprintf() but increments total_bytes{,_out}
* implement CPUTC(); as per putc() but increments total_bytes{,_out}
* implement base64_encode()
* fact_unique() display base64 encoding of dev_t and ino_t rather than
hex output; should scale if size of those changes
* change reply() so that a negative code acts as the initial line in a reply,
code == 0 prefixes the line with 4 spaces, and code > 0 works as before.
deprecate lreply(code, ) and lreply(0, ) in favour of reply(-code, ) and
reply(0, ) respectively.
* use cprintf() and CPUTC() appropriately (often instead of printf(),
lreply(-2, ) or lreply(-1, ).
now we actually account for the data sent by MLST and MLSD.
* remove DEBUG support for sending MLSD output to control connection instead
of data connection (my ftp client now supports MLSD :-)
* implement draft-ietf-ftpext-mlst-10 commands, especially MLST and MLSD.
we already supported SIZE and MDTM. add the appropriate FEAT output lines.
* migrate a lot of the command code from ftpcmd.y and ftpd.c to cmds.c
* make dataconn(), feat(), lookup(), opts() and sizecmd() public
* modify struct tab so that it has a `flags' instead of `implemented' element,
and remove the `hasopts' element. If flags == 1, the command is implemented.
if flags == 2, the command is implemented and takes options
* add macros ISDOTDIR(x) (is x ".") and ISDOTDOTDIR(x) (is x "..")
* modify lreply() so that lreply(-2, ...) just outputs the given info without
a prefix or trailing \r\n. this saves doing b = printf(); total_* += b;
* enhance statcmd(). still needs work in the LPRT status stuff.
* crank version
Problem noted in [bin/9642] by Takahiro Kambe <taca@sky.yamashina.kyoto.jp>,
(part of which already had been solved by itojun a while ago), and provided
patch covered most of the fixes needed. (Thanks Takahiro!)
- Consistently indent goto labels by one space.
of the port range used by passive connections. based on work in [bin/9158]
from Takahiro Kambe <taca@sky.yamashina.kyoto.jp>
* change the way global variables are defined and extern-ed to be more
consistent.
template class [refclass]
following directives for refclass will apply to class as well.
this makes setting up a `template' class with many default settings
easy, whilst allowing for class-specific overrides
* prevent crash when the optional limitfile wasn't given to limit
* document count_users()
* document default setting of limit in ftpd.conf(5)
* crank version
* add connection limits (`limit' keyword in ftpd.conf)
* move initialisation of curclass from parse_conf() to new function
init_curclass()
* implement count_users(), which determines the number of users in a given
class. a file - /var/run/ftpd.pids-<class> - is used to store a list
of pids in use (effectively an array of pid_t's), and its size is reduced
as necessary.
* new % modifiers in format_file:
%c class
%M maximum connection count
%N current connection count
* always end_login()s, even for refused connections
bugs fixed:
* remove \n from %T output
* fix some inconsistencies in the man pages
* ensure that both `ftp' *and* `anonymous' are allowed in ftpusers.
(this was accidently broken in a recent commit to be ``or'' not ``and'')
* use MAXPATHLEN not MAXPATHLEN+1
* crank copyright date on modified files
* crank version
the name advertised to the client, even if ftpd can determine it from
the ip address that ftpd is bound to. requested by mrg.
* remove -4/-6; they were effectively no-ops since itojun's change in 1.75.
* crank version
* use .Dv and .Tn in the man pages as appropriate
* KNF a bit
The following were inspired by similar changes in openbsd, but may
have additional improvements by me:
* add more check_login tests to the parser rules
* nuke a few memory leaks in the parser rules
* clear passwords before free()ing them, for safety
* don't display \r\n in setproctitle() output
* add support for -U, which enables managing /var/run/utmp entries for
connections. solves [bin/2217] by Jason Downs <downsj@teeny.org>
* fix oob handling for STAT command
* use SIG_ERR instead of -1
as (useful for virtual ftp servers in conjunction with inetd.conf(5)'s
ability to bind to a specific address).
if this option is used, add `hostname' to the syslog messages.
* improve documentation of command-line options
* don't allow class names of `all' or `none' in ftpusers
userglob [allow|deny]
to
userglob[@host] [allow|deny [classname]]
where class is a userdefined classname.
- if host is given it may either be a CIDR address (e.g, `1.2.3.0/24') or a
hostglob (e.g, `*.foo.com'), and the remote host is matched against that.
- if classname is given, use that to match entries in ftpd.conf (defaults
to `guest' for `anonymous'/`ftp' logins, `chroot' for users found in
/etc/ftpchroot, and `real' for everyone else.
* implement new /etc/ftpd.conf directives:
classtype classname type set type of classname to GUEST, CHROOT, or REAL
motd classname file file to use instead of /etc/motd
rateget classname rate set rateget throttle to rate
rateput classname rate set rateput throttle to rate
upload classname allow/deny uploads (STOU, STOR, APPE). if
denied, also acts as `modify deny'.
* implement new `SITE' commands:
RATEGET as per /etc/ftpd.conf rateget, but cannot exceed that
RATEPUT as per /etc/ftpd.conf rateput, but cannot exceed that
* implement format_file(), which outputs a file to the user, parsing %
escapes. use to print /etc/ftpwelcome, /etc/motd, and the `display' file.
* implement strsuftoi() (from ftp(1)), which parses a number and
optional suffix (for use with rateget, etc)
* don't bother seteuid(0) ; bind(...) ; seteuid(pw->pw_uid), since
we don't need reserved ports (at wasn't getting them anyway).
* update & reorder copyrights
* use strlcpy() as appropriate
the string tokenisation must be performed by the caller (which is
generally easy because it's almost always a static command).
* change do_conversion() to return a char *argv[] instead of char *cmd.
tokenisation of the command is done internally.
* change retrieve() to take char *argv[] instead of char *cmd.
(to take advantage of the above changes). fixes [bin/8173]
* use fparseln() instead of fgetln()
* store conversions in listed order (rather than reverse order)
* use stringlists instead of handrolling code to manage an argv.
connection destination, hoping this to help ftpd's behavior with
scoped IPv6 addresses.
I'm not sure if it is the right way, but it is the best way available to us.
LPRT or EPRT command gives no information about which interface (or scope)
to be used for new data connection.
ftp(1): On data connection establishment, warn if scoped address is used.
If peer (ftp daemon) does not handle scoped address, data connection
may not work right.
This seems to be sort of protocol spec hole, not implementation issue.
(this was broken in the last commit). problem noticed by simonb@
* don't display the stderr output of the internal ls.
* modify usage of lreply so that generally only one `XXX-' code per
`block' is displayed; the rest of the lines have four spaces instead.
i find this easier to read.
* fix a couple places where byte accounting wasn't correct
* implement xferstats. full stats are displayed for `STAT', and a
summary is displayed upon exit (and syslogged). inspired by wu-ftpd.
* wrap data xfers in {send,receive}_data with alarm() timeouts. this
should remove the majority of the `hanging ftpd' problems that
people were still seeing. inspired by wu-ftpd.
* link with ../../bin/ls, so that bin/ls is not required under a
chroot()ed area for `LIST' to work. based on [bin/4497] from
"Soren S. Jorvang" <soren@t.dk>
* migrate code from util.c into ftpd.c, so that it doesn't conflict
with ls' util.c.
* remove man page comment about ~ftp/bin/ls being necessary.
* bump version to 7.2.0.
* syslog xfer time with xfer stats.
* if appropriate, syslog error message with command.
internal code stuff:
* change arguments of various functions from `char *' to `const char *'.
* define PLURAL(x) macro, which returns `' if x == 1, `s' otherwise.
use macro appropriately
* lreply(): a code of -1 means ``send line as is''. a code of 0
means ``send line with 4 space prefix''. don't print a space after
the `-' for any other code.
* logcmd(): add `const struct timeval *elapsed' and `const char *error'
for more flexible error reporting
solution with less code replication. use realpath() in logcmd() so
that all logged filenames are sane.
* support `REST STREAM' in `FEAT' reply (from draft-ietf-ftpext-mlst-05)
* in 'HELP', suffix unimplemented commands with `-' instead of `*'; the
former is easier to differentiate from `+'.
* deprecate curdir() now that logcmd() doesn't use it.
* ensure all filename buffers are at least MAXPATHLEN+1 in size.
* move jmp_buf errcatch out of extern.h, removing need to #include <setjmp.h>
in every file.
* implement FEAT and OPTS from RFC2389. FEAT returns SIZE and MDTM.
OPTS only works on NOOP (as a test).
* extend format of /etc/ftpchroot similar to /etc/ftpusers; each entry
can take an optional trailing `yes' or `no' which indicates if
chroot should be done (defaults to `yes').
based on patches from Ty Sarna <tsarna@endicor.com> in [bin/4769]
cleanups/bugs:
* reorder and reformat entries in yacc parser to match cmdtab[].
add a blank line between each rule.
* add short hasopts and char *options to struct tab, to support OPTS.
* deprecate upper(); use strcasecmp() instead of strcmp()
* remove unnecessary for (;;) { } in yylex();
* replace copy() and sgetsave() with xstrdup()
* fix a couple of `hasyyerrored = 1' that were accidently removed.
problem; move `hasyyerrored' state flag out of yylex() so that
check_{login,modify} can also set it.
* check result of check_login for PORT command
* set initial timeout before the "setjmp(); for(;;) yyparse()",
otherwise an invalid command after login incorrectly sets the timeout
to 5 minutes (rather than what was set in ftpd.conf)
* replace (char *)0 with NULL
* move yyerror() from ftpd.c to ftpcmd.y
* remove need for -Dunix, by using the version string from ftpd.c
(instead of `BSD-199506')
* move all extern-ed vars into extern.h
fixes long standing ftpd bug where two replies would be returned
to the client if a command was flagged as accepting `ARGS' but the
parser didn't know how to cope. obvious symptom of this would be
ftp client is always one error message `behind' the server.
* consistently refer to the RFC as `RFC 959' not `RFC959' or `RFC-959',
and replace refs to RFC 765 with RFC 959.
* change order of commands in cmdtab[] to: RFC 959, BSD extras, and obsolete.
* whitespace police, deprecate register, replace malloc/strcpy with strdup
- ensure hostname from gethostname() is nul-terminated in all cases
- minor KNF
- use MAXHOSTNAMELEN over various other values/defines
- be safe will buffers that hold hostnames
the user at the end of a transfer.
this generates a file in /tmp, so anonymous requires a
writable ~ftp/tmp, which you may not want to do (because it may
allow people to unwanted upload files).
XXX: a better method of storing the stderr output would be nice, but
is a lot more effort to implement. this feature can at least be
used temporarily whilst debugging why an ftp conversion doesn't
work.
want to timeout using this value that are executed before the conf file
is parsed will work. fixes ``stale ftpd stuck in connection phase''
* in PASV mode, wrap accept() in an alarm timeout. fixes ``stale ftpd because
of client disappearing in pasv mode (usually browsers)''
* main() doesn't need envp argument
* display current setting of checkportcmd in STAT
* ensure that curclass.checkportcmd is initialised to 0
* document default setting of checkportcmd in ftpd(8)
* cleanup code a bit, putting code for "checkportcmd" in alphabetical order
(0 == user allowed in /etc/ftpusers, 1 == user denied in /etc/ftpusers).
from Jim Bernard <jbernard@tater.mines.edu> in [security/4061] with mods
- getopt returns -1 not EOF
- in lostcon(), call dologout(1) not dologout(-1);
257 "dirname" some message
(any "s in dirname should be doubled, per the RFC)
- don't put an extra / in the output of NLST if the last char in the
directory is a /
- bump the version to 7.01 because of these fixes
from Tatoku Ogaito <tacha@tera.fukui-med.ac.jp> in [bin/3967]
* fgetln() doesn't \0 terminate its string. look for the \n and replace
it with \0 (if no \n, ignore the line - it's most likely corrupt)
* more intensive checks on strdup() returns (not a current mem leak,
but depended upon code elsewhere to cleanup - not good)
* cleanup some syslog error messages
printf format strings, you've got to make sure you cast quantities
passed to %qd to long long because on 64-bit machines they're often
just long, which is not the same, even when it's the same size.
controllable on a per class (which is one of: real, chroot, guest,
all or none) basis:
* on-the-fly execution of a command to build the file (a ``conversion''),
providing support for "get dirname.tar" and the like.
* displaying the contents of a file when a directory is entered
for the first time.
* maximum value for timeout (replaces -T).
* control usage of CHMOD, DELE, MKD, RMD, UMASK; replacing -DINSECURE_GUEST.
* notifying the user of the existance of a files matching a glob
pattern when a directory is entered for the first time.
* default value for timeout (replaces -t).
* default umask (replaces -DGUEST_CMASK and -u).
The conversion, display, and notify functionality was based on code by
Simon Burge <simonb@telstra.com.au>.
* clean up and re-order parts of the man page into subsections.
* STAT displays the settings defined for the class of the current user.
* bump version from 6.00 to 7.00, because of ftpd.conf.
* deprecate -DGUEST_CMASK and -DINSECURE_GUEST in the Makefile, and
-t, -T and -u, as ftpd.conf allows finer control of these.
* add "nostderr" argument to ftpd_popen(), because you don't want the
stderr stream mixing with the stdout stream during a conversion,
as this can corrupt the stream.
information in the same file by following the username with `allow'
or `deny'. Also, the user `*' can be used to set the default for
users not listed in the file. This is entirely backward compatable
with old /etc/ftpusers files.
Also, do the /etc/ftpusers and the valid login shell checks after
the password is verified, rather than before, so as not to give away
whether or not a particular user ID is present on the system.
* Set umask to 707;
* Disable UMASK, CHMOD, DELE, RMD and MKD commands.
Compile-time options let you change that umask and go back to the
old, insecure way if you like.