This prevents CSRF-like attacks, when a web browser is used to access
an ftp server.
Reported by Maksymilian Arciemowicz <cxib@securityreason.com>.
Fix mostly derived from OpenBSD, written by Moritz Jodeit <moritz@OpenBSD.org>
This adds a -L to all ls command arguments so that the file or directory
the link references is listed rather than the link itself. This was
inspired by IRIX ftpd's -S option.
[Discussed with lukem some time ago.]
* Crank version.h [right Luke? :-)]
* Fix yacc parser error recovery so that setjmp(3)/longjmp(3) is unnecessary.
* Fix SIGURG handler to set an urgflag that's later tested, rather than
abusing setjmp(3)/longjmp(3).
* Use "volatile sig_atomic_t" as the type of variables modified by sig handlers.
* Use sigaction(3) instead of signal(3) to set the signal handlers.
* Only set the main SIGALRM handler once. If we need to change it,
cache the old handler and restore appropriately...
* Remove a bunch of signal races by improving the signal handlers.
* Fix memory leak with 'ESPV ALL'.
My stuff:
* Clean up the debug message in reply(); use vsnprintf(3) instead of vsyslog(3).
* Rework parsing of OOB commands to _not_ use the yacc parser, since the
latter isn't reentrant and the hacks to work around that are ugly.
We now examine urgflag at appropriate locations and call handleoobcmd()
if it's set. Since the only OOB commands we currently implement are
ABOR and STAT, this isn't an issue. (I also can't find the reference in
RFC2228 where MIC, CONF & ENC are OOB-only commands. Go figure.)
I could clean up the is_oob stuff some more, but the remaining stuff
in ftpcmd.y is harmless and it's unnecessary churn right this moment.
- use LLT (aka 'long long type') for all numeric class parameters
- improve description of various ftpd.conf(5) options
- statcmd(): print out: mmapsize readsize writesize sendbufsize sendlowat
check_write(), so that a user who has modify disabled gets an error
message rather than a hung connection.
Noted by M.J. Rutter <mjr19@cus.cam.ac.uk> in private email.
This involved changing the yacc syntax to be line-oriented, rather than
having it run against the entire input at once, and adding a flag to
struct tab, to indicate if or not it's acceptable for a command to occur
OOB.
* Add ftpd.conf(5) directive `advertise'; change the address that is
advertised to the client for PASV transfers. this may be useful in
certain firewall/NAT environments.
Feature requested in [bin/9606] by Scott Presnell.
* Add -X option; syslog wu-ftpd style xferlog messages, prefixed with
`xferlog: '. An example line from syslog (wrapped):
Dec 16 18:50:24 odysseus ftpd[571]: xferlog: Sat Dec 16 18:50:24 2000
2 localhost 3747328 /pub/WLW2K601.EXE b _ o a lukem@ FTP 0 * c
These messages can be converted to a wu-ftpd style xferlog file
suitable for parsing with third-party tools with something like:
grep 'xferlog: ' /var/log/xferlog | \
sed -e 's/^.*xferlog: //' >wuxferlog
The format is the same as the wu-ftpd xferlog entries (with the leading
syslog stuff), but different from the wu-ftpd syslogged xferlog entries
because the latter is not as easy to convert into the standard xferlog
file format.
The choice to only syslog the xferlog messages rather than append to
a /var/log/xferlog file was made because the latter doesn't work to
well in the situation where the logfile is rotated and compressed and
a long-running ftpd still has a file-descriptor to the now nonexistant
xferlog file, and the log message will then get lost.
Feature requested in [bin/11651] by Hubert Feyrer.
Fixes:
* In ftpd(8), clarify the -a and -c options.
* More clarifications in ftpd.conf(5).
* Ensure that all ftpd.conf commands set a parameter back to sane defaults
if an argument of `none' or bad settings are given.
* Support the `chroot' directive for `REAL' users too (for consistency).
* For `GUEST' users, store the supplied password in pw->pw_passwd for use
later in the xferlog.
* If show_chdir_messages() is given a code of -1, flush the cache of
visited directories. Invoke show_chdir_messages(-1) in end_login().
* Only syslog session stats if logging is requested.
* Rename logcmd() -> logxfer(), and dolog() -> logremotehost().
* Use cprintf() instead of fprintf() where appropriate.
* Minor KNF, and make a couple of functions static that were declared static.
in porting to other systems.
- don't syslog() or setproctitle() "ACCT" lines (as per "PASS")
- replace #ifdef HASSETPROCTITLE with #if HAVE_SETPROCTITLE, and set the
latter #ifdef BSD4_4
- don't compile in internal `ls' #ifdef NO_INTERNAL_LS. will need Makefile
support if this is to be used on NetBSD.
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()
* 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