summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2001-07-19 16:25:08 +0000
committerobrien <obrien@FreeBSD.org>2001-07-19 16:25:08 +0000
commite4751f9e00971d0c774736bb50344b7ea67d40b0 (patch)
tree5e3fc097f0652fa73b8d2880dc1208f8bf557809
downloadFreeBSD-src-e4751f9e00971d0c774736bb50344b7ea67d40b0.zip
FreeBSD-src-e4751f9e00971d0c774736bb50344b7ea67d40b0.tar.gz
Import of LukeM's ftpd version 1.1.
-rw-r--r--contrib/lukemftpd/COPYING47
-rw-r--r--contrib/lukemftpd/ChangeLog176
-rw-r--r--contrib/lukemftpd/INSTALL98
-rw-r--r--contrib/lukemftpd/Makefile.in29
-rw-r--r--contrib/lukemftpd/NEWS13
-rw-r--r--contrib/lukemftpd/README102
-rw-r--r--contrib/lukemftpd/THANKS9
-rw-r--r--contrib/lukemftpd/acconfig.h101
-rw-r--r--contrib/lukemftpd/aclocal.m4257
-rw-r--r--contrib/lukemftpd/config.h.in274
-rwxr-xr-xcontrib/lukemftpd/configure4091
-rw-r--r--contrib/lukemftpd/configure.in300
-rwxr-xr-xcontrib/lukemftpd/install-sh251
-rw-r--r--contrib/lukemftpd/lukemftpd.h396
-rw-r--r--contrib/lukemftpd/src/Makefile.in61
-rw-r--r--contrib/lukemftpd/src/arpaftp.h111
-rw-r--r--contrib/lukemftpd/src/cmds.c791
-rw-r--r--contrib/lukemftpd/src/conf.c1007
-rw-r--r--contrib/lukemftpd/src/extern.h372
-rw-r--r--contrib/lukemftpd/src/ftpcmd.y1808
-rw-r--r--contrib/lukemftpd/src/ftpd.8833
-rw-r--r--contrib/lukemftpd/src/ftpd.c2947
-rw-r--r--contrib/lukemftpd/src/ftpd.conf.5587
-rw-r--r--contrib/lukemftpd/src/ftpusers.5183
-rw-r--r--contrib/lukemftpd/src/logutmp.c111
-rw-r--r--contrib/lukemftpd/src/logwtmp.c65
-rw-r--r--contrib/lukemftpd/src/pathnames.h51
-rw-r--r--contrib/lukemftpd/src/popen.c236
-rw-r--r--contrib/lukemftpd/src/version.h40
-rw-r--r--contrib/lukemftpd/todo17
30 files changed, 15364 insertions, 0 deletions
diff --git a/contrib/lukemftpd/COPYING b/contrib/lukemftpd/COPYING
new file mode 100644
index 0000000..fe7b79b
--- /dev/null
+++ b/contrib/lukemftpd/COPYING
@@ -0,0 +1,47 @@
+Copyright 2001 Luke Mewburn <lukem@netbsd.org>. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by Luke Mewburn.
+4. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+This product also contains software developed by other people, and you
+are advised to read the various source files to read the full details
+of the other licenses. Those licenses also require the following
+acknowledgements:
+
+ This product includes software developed by the NetBSD Foundation,
+ Inc. and its contributors. Those contributors include:
+ - Simon Burge
+ - Luke Mewburn
+ - Christos Zoulas
+
+ This product includes software developed by the University of
+ California, Berkeley and its contributors. Those contributors
+ include:
+ - Michael Fischbein
+ - Guido van Rossum
+ - Institute of Electrical and Electronics Engineers, Inc
+
+ This product includes software developed by Christos Zoulas.
+
diff --git a/contrib/lukemftpd/ChangeLog b/contrib/lukemftpd/ChangeLog
new file mode 100644
index 0000000..76cb9da
--- /dev/null
+++ b/contrib/lukemftpd/ChangeLog
@@ -0,0 +1,176 @@
+Wed May 9 02:04:08 UTC 2001 lukem
+
+ * released 1.1
+
+Sat Apr 28 07:13:57 UTC 2001 lukem
+
+ * released 1.1 beta 1
+
+ * determine if crypt() and getusershell() need declarations
+
+Wed Apr 25 06:27:08 UTC 2001 lukem
+
+ * update to NetBSD-current 2001/04/25:
+ - update copyrights
+ - remove superfluous byte_count update in send_file_list
+ - use own code instead of bothering with glob() to do ~
+ expansion in pathname; there's no need to support glob
+ wildcards in this case when it's not expanded here in the
+ non-~ case
+ - As threatened, handle OOB commands from within ftpcmd.y.
+ 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.
+
+Tue Apr 17 08:20:09 UTC 2001 lukem
+
+ * look for <arpa/nameser.h>
+
+ * pull in <arpa/nameser.h> for INADDRZ, IN6ADDRSZ and INT16SZ,
+ and define if missing
+
+ * don't bother trying to use if_indextoname() in ip6_sa2str()
+ (fixes problems on MacOS X)
+
+ * remove unused sverrno in warnx() and errx()
+
+Fri Apr 13 16:02:40 UTC 2001 lukem
+
+ * improve test for long long support so that it's only enabled
+ if printf supports %ll or %q and they do the right thing.
+ use %q instead of %ll #if HAVE_PRINTF_QD
+
+ * added NEWS file
+
+ * support S/Key with add support for --with-skey
+
+ * pull up changes made in NetBSD in ftpcmd.y revision 1.61:
+ make checkportcmd address family independent, and correct
+ IPv4 case. PR 12558.
+
+Sun Apr 8 03:35:55 UTC 2001 lukem
+
+ * release 1.0
+
+Thu Apr 5 14:08:25 UTC 2001 lukem
+
+ * search for lockf and flock, and use the first found (in that
+ order) to lock the pid files
+
+ * pull up fix to glob.c from rev 1.21 of NetBSD's __glob13.c:
+ - Fix sentinel for the buffer in globtilde. It was off
+ by x 2. Noted by Theo.
+
+Thu Mar 29 16:57:17 EST 2001 lukem
+
+ * release 1.0 beta 4
+
+ * merge ftpd from NetBSD-current (20010329):
+ - don't leak globbed memory.
+
+ * only look for setproctitle in -lutil if fparseln wasn't found in it
+
+ * only REPLACE_FUNC(fparseln) if it wasn't found in -lutil
+
+ * always compile in local glob; it's the best way to ensure that
+ various security issues are fixed
+
+ * update glob(3) to netbsd-current (20010329), adding support for
+ GLOB_LIMIT and fixing various buffer overflows.
+
+ * support --enable-builtinls (default) and --disable-builtinls
+
+Sun Mar 18 10:14:17 UTC 2001 lukem
+
+ * detect if d_namlen exists in struct dirent, and use in
+ fts_open() appropriately
+
+Sun Mar 18 08:30:01 UTC 2001 lukem
+
+ * released 1.0 beta3
+
+ * use inbuilt ls source
+
+ * autoconf improvements:
+ - replace missing fts_open, strmode, user_from_uid
+ - detect if optreset exists, and only use if it does
+ - fix AC_MSG strings (remove comma's from the messages)
+
+ * fixes to inbuilt ls:
+ - revert part of previous
+ - add rcsid
+ - remove stat_flags; flags_to_string is unused (i.e, ignore -o)
+ - conditionally support S_IFWHT
+ - hardcode blocksize to 1K
+ - remove support for nsec comparison in time sorting
+
+Sat Mar 17 12:02:51 UTC 2001 lukem
+
+ * generate cat manpages
+
+ * merge ftpd from NetBSD-current (20010317):
+ - make sure we do not return stray " at the end of stirng,
+ like bla"\0. From: "William C. Allen" <allenwc@home.com>
+ - ensure replydirname() do not truncate the names.
+ From: Paul Janzen <pjanzen@foatdi.harvard.edu>
+ - don't support t(erabyte) as a suffix in strsuftoll()
+ #ifdef NO_LONG_LONG
+ - Use GLOB_LIMIT. Also fix a bug where gl_offs was not
+ initialized and could contain trash.
+ - fix redundant declarations.
+ - comment or delete text after CPP directives.
+ - consistently use syslog priorities
+
+ * improve detection of working glob(), including requiring GLOB_LIMIT.
+ don't bother explicilty looking for glob.h; the test above will
+ detect that.
+
+ * update replacement glob() to support GLOB_LIMIT
+
+ * look for setproctitle in -lutil as well
+
+ * pull in <paths.h> if it exists, but still check each _PATH_xxx and
+ define to something sane if not found; certain platforms have a
+ lobotomised <paths.h>
+
+Fri Mar 16 08:27:09 EST 2001 lukem
+
+ * in getusershell.c, remove __P() and const cruft
+
+ * undef _PATH_FTPUSERS before defining
+
+ * define _PATH_SHELLS if there's no <path.h>
+
+Wed Mar 14 18:49:57 EST 2001 lukem
+
+ * released 1.0 beta2
+
+ * add COPYING INSTALL README THANKS
+
+ * replace missing vsyslog
+
+Sat Mar 10 09:15:46 EST 2001 lukem
+
+ * replace missing getusershell
+
+ * look for vfork and don't use if it doesn't exist
+
+ * note tru64 doesn't have vsyslog (still to fix)
+
+ * prototype getusershell et al if missing
+
+Fri Mar 9 06:27:08 EST 2001 lukem
+
+ * released 1.0 beta1
+
+ * look for libutil.h (FreeBSD) as well as util.h (NetBSD)
+
+ * change the way that glob(3) is checked for 4.4BSD feature
+ compliance so that it's much more robust
+
+ * add strtoll()
+
+Thu Feb 1 12:24:00 EST 2001 lukem
+
+ * released 1.0 alpha
diff --git a/contrib/lukemftpd/INSTALL b/contrib/lukemftpd/INSTALL
new file mode 100644
index 0000000..80fa04b
--- /dev/null
+++ b/contrib/lukemftpd/INSTALL
@@ -0,0 +1,98 @@
+INSTALLATION INTRODUCTION
+-------------------------
+
+This file describes how to compile and install lukemftpd on your
+system.
+
+ ============================================
+ = =
+ = NOTE: You will need an ANSI C compiler. =
+ = =
+ ============================================
+
+
+For most systems, execute the following to compile and install
+lukemftpd:
+ ./configure
+ make
+ make install
+
+Preformatted manual pages for ftpd(8), ftpd.conf(5), and ftpusers(5) are
+also installed. If you wish to install the sources, ensure that your system
+has up-to-date mandoc macros. groff ships with this macro suite,
+but it has bugs. Try:
+ ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/share/tmac/
+for a more recent version.
+
+
+CONFIGURATION OPTIONS
+---------------------
+
+lukemftpd is configured using an `autoconf' generated `configure'
+script. `configure' supports the following options:
+
+* The standard `autoconf configure' options, including:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [/usr/local]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ BSD or GNU make may be required for this to work.
+
+* Specific options:
+ --enable-ipv6 Enable IPv6 support (if your OS supports it)
+ --disable-ipv6 Disable IPv6 support (even if your OS supports it.)
+ [default: enabled].
+ --with-socks Compile with SOCKS firewall traversal support.
+ --with-socks5[=PATH] Compile with SOCKS5 firewall traversal support.
+ --with-socks4[=PATH] Compile with SOCKS4 firewall traversal support.
+ --with-skey Compile with S/Key authentication support.
+
+The following environment variables can be set to override various
+compiler related settings.
+ CC=compiler specify name of the C compiler (default: gcc or cc)
+ CFLAGS=flags specify flags to C compiler (default: -O -g or just -O)
+ LDFLAGS=flags specify flags to linker (default: none)
+
+This can be achieved with:
+ env CC="compiler" CFLAGS="flags" LDFLAGS="flags" ./configure
+
+
+ ============================================
+ = =
+ = NOTE: You will need an ANSI C compiler. =
+ = =
+ ============================================
+
+
+PLATFORM SPECIFIC NOTES
+-----------------------
+
+The following platforms & compilers have been tested:
+
+- Irix 6.5
+ - Compiler: /usr/local/bin/gcc
+ version: egcs-1.1.2
+
+ Configure with:
+ ./configure --disable-builtinls
+ as the in-built ls code doesn't appear to work due to
+ problems in the fts routines.
+
+- Linux 2.4 kernel with glibc prior to 2.2
+ Configure with:
+ ./configure --disable-ipv6
+ as glibc before 2.2 doesn't correctly support sin6_scope_id.
+
+- NetBSD 1.5 (i386)
+ - Compiler: /usr/bin/cc
+ version: egcs-1.1.2
+
+- Solaris 2.6 (sparc)
+ - Compiler: /opt/SUNWspro/bin/cc
+ version: WorkShop Compilers 5.0
+
+- Tru64 5.0
+ - Compiler: /bin/cc
+ version: Compaq C V6.1-011 on Digital UNIX V5.0 (Rev. 910)
+
diff --git a/contrib/lukemftpd/Makefile.in b/contrib/lukemftpd/Makefile.in
new file mode 100644
index 0000000..6b751cb
--- /dev/null
+++ b/contrib/lukemftpd/Makefile.in
@@ -0,0 +1,29 @@
+# $Id: Makefile.in,v 1.1 2000/07/29 13:34:15 lukem Exp $
+#
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+SHELL = /bin/sh
+
+@SET_MAKE@
+
+SUBDIRS = libukem src
+
+all: ftpd
+
+ftpd: @LIBUKEM@
+ ( cd src; ${MAKE} )
+
+libukem.a:
+ ( cd libukem; ${MAKE} )
+
+install clean:
+ @for i in ${SUBDIRS}; do \
+ ( echo "$@ ===> $$i" ; cd $$i ; ${MAKE} $@ ); \
+ done
+
+distclean: clean
+ @for i in ${SUBDIRS}; do \
+ ( echo "$@ ===> $$i" ; cd $$i ; ${MAKE} $@ ); \
+ done
+ rm -f Makefile config.cache config.log config.status config.h
diff --git a/contrib/lukemftpd/NEWS b/contrib/lukemftpd/NEWS
new file mode 100644
index 0000000..b1c0211
--- /dev/null
+++ b/contrib/lukemftpd/NEWS
@@ -0,0 +1,13 @@
+This is a brief description of the new features and fixes added to
+lukemftpd-1.1 since the release of lukemftpd-1.0.
+
+* Fixed checkportcmd for the IPv4 case.
+
+* Added support for S/Key authentication.
+
+* Use method other than glob(3) to do ~ expansion.
+
+* Improve portability.
+
+* Rewrite method of handling out-of-band operations, in order to more
+ easily support RFC2228 security extensions in a future release.
diff --git a/contrib/lukemftpd/README b/contrib/lukemftpd/README
new file mode 100644
index 0000000..60d645f
--- /dev/null
+++ b/contrib/lukemftpd/README
@@ -0,0 +1,102 @@
+WHAT IS LUKEMFTPD?
+------------------
+
+`lukemftpd' is what many users affectionately call the enhanced ftp
+server in NetBSD (http://www.netbsd.org). The `lukem' comes from
+the account name of the NetBSD developer who wrote most of the
+enhancements: Luke Mewburn <lukem@netbsd.org>.
+
+This package is a `port' of the NetBSD ftp server to other systems.
+
+The enhancements over the standard ftp server in 4.4BSD (and derivatives)
+include:
+ * command line options:
+ + allow override of directory used by anonymous ftp (-a)
+ + optional change of directory for configuration files (-c)
+ + check whether a user would be granted access (-C)
+ + specify email address for display messages (-e)
+ + change hostname advertised as (-h, -H)
+ + specify data port to listen on (-P)
+ + keep track of the number of users logged in (-q, -Q)
+ + permanently drop privileges (-r)
+ + specify version advertised (-V)
+ + log wu-ftpd style `xferlog' entries to syslog (-X)
+
+ * % escape sequences in files displayed to users (/etc/motd,
+ /etc/ftpwelcome, ...)
+
+ * IPv6 support (from the KAME project).
+
+ * ftpusers(5) control of who may log in, and optional
+ specification of a "class" to be associated with the
+ specified user or group.
+
+ * ftpd.conf(5) to control various configuration options on
+ a per-class basis. The following options are supported:
+ + address to advertise in PASV and LPSV responses
+ + check the PORT command for validity
+ + specify the directory to chroot(2) to
+ + automatic in-line conversions (e.g, `.tar.gz'
+ retrieval of directories)
+ + display a file the first time a directory is entered
+ + specify the home directory of the session (for "cd ~")
+ + limit the maximum number of concurrent sessions
+ + limit the maximum size of an uploaded file
+ + set the default timeout and restrict the maximum
+ timeout that a user may request
+ + deny user from running the CHMOD, DELE, MKD, RMD, RNFR
+ and UMASK commands
+ + specify the motd(5) file to display upon login
+ + specify a glob(3) pattern of files to notify a user
+ of the existance of once a directory is entered
+ + enable/disable the use of PASV and EPSV connections
+ + limit the ports that PORT and LPRT may bind to
+ + limit the transfer rate of transfers
+ + limit the characters that may be used in an uploaded
+ filename
+ + set the umask
+ + deny user from running APPE, STOR and STOU as well
+ as CHMOD, ...
+
+ * In-built copy of ls(1) to implement LIST (unless disabled
+ out with --disable-builtinls), so that /bin/ls does not need
+ to exist inside the ftp tree.
+
+ * Virtual servers can be supported with a combination of
+ ftpd(8) flags and support in the invoking inetd(8) program
+ (such as that in NetBSD).
+
+ * Optional S/Key authentication (if configued with --with-skey).
+
+
+Features present in NetBSD's ftpd but not yet available in lukemftpd:
+ * logging active sessions to utmp(5) (-u, -U)
+ * logging completed sessions to wtmp(5) (-w, -W)
+
+
+INSTALLATION
+------------
+
+Refer to `INSTALL' for more information on how to compile and install
+lukemftpd.
+
+
+FEEDBACK / BUG REPORTS
+----------------------
+
+Please email feedback back to the maintainer: <lukem@netbsd.org>.
+
+
+COPYRIGHT
+---------
+
+lukemftpd is covered by a BSD-style copyright notice. Please refer to
+the file `COPYING' for more information.
+
+
+AVAILABILITY
+------------
+
+The primary ftp site for lukemftpd is:
+ ftp://ftp.netbsd.org/pub/NetBSD/misc/lukemftp/
+(the same location as lukemftp)
diff --git a/contrib/lukemftpd/THANKS b/contrib/lukemftpd/THANKS
new file mode 100644
index 0000000..b6ce509
--- /dev/null
+++ b/contrib/lukemftpd/THANKS
@@ -0,0 +1,9 @@
+Whilst a lot of the work in lukemftpd (both the original sources in NetBSD
+and this port) was done by me (Luke Mewburn), it would not be as useable
+without the enhancements, fixes, or input from the following people:
+
+Christos Zoulas <christos@netbsd.org>
+Curt Sampson <cjs@netbsd.org>
+Jun-ichiro itojun Hagino <itojun@netbsd.org>
+Matthew R. Green <mrg@eterna.com.au>
+Todd Vierling <tv@netbsd.org>
diff --git a/contrib/lukemftpd/acconfig.h b/contrib/lukemftpd/acconfig.h
new file mode 100644
index 0000000..88caee0
--- /dev/null
+++ b/contrib/lukemftpd/acconfig.h
@@ -0,0 +1,101 @@
+/* $Id: acconfig.h,v 1.9 2001/04/28 07:11:06 lukem Exp $ */
+
+@TOP@
+@BOTTOM@
+
+/* Define if your compiler supports `long long' */
+#undef HAVE_LONG_LONG
+
+/* Define if *printf() uses %qd to print `long long' (otherwise uses %lld) */
+#undef HAVE_PRINTF_QD
+
+/* Define if in_port_t exists */
+#undef HAVE_IN_PORT_T
+
+/* Define if struct sockaddr.sa_len exists (implies sockaddr_in.sin_len, etc) */
+#undef HAVE_SOCKADDR_SA_LEN
+
+/* Define if socklen_t exists */
+#undef HAVE_SOCKLEN_T
+
+/* Define if AF_INET6 exists in <sys/socket.h> */
+#undef HAVE_AF_INET6
+
+/* Define if `struct sockaddr_in6' exists in <netinet/in.h> */
+#undef HAVE_SOCKADDR_IN6
+
+/* Define if `struct addrinfo' exists in <netdb.h> */
+#undef HAVE_ADDRINFO
+
+/*
+ * Define if <netdb.h> contains AI_NUMERICHOST et al.
+ * Systems which only implement RFC2133 will need this.
+ */
+#undef HAVE_RFC2553_NETDB
+
+/* Define if `struct direct' has a d_namlen element */
+#undef HAVE_D_NAMLEN
+
+/* Define if struct passwd.pw_expire exists. */
+#undef HAVE_PW_EXPIRE
+
+/* Define if GLOB_BRACE, gl_path and gl_match exist in <glob.h> */
+#undef HAVE_WORKING_GLOB
+
+/* Define if crypt() is declared in <unistd.h> */
+#undef HAVE_CRYPT_D
+
+/* Define if fclose() is declared in <stdio.h> */
+#undef HAVE_FCLOSE_D
+
+/* Define if optarg is declared in <stdlib.h> or <unistd.h> */
+#undef HAVE_OPTARG_D
+
+/* Define if optind is declared in <stdlib.h> or <unistd.h> */
+#undef HAVE_OPTIND_D
+
+/* Define if optreset exists */
+#undef HAVE_OPTRESET
+
+/* Define if pclose() is declared in <stdio.h> */
+#undef HAVE_PCLOSE_D
+
+/* Define if getusershell() is declared in <unistd.h> */
+#undef HAVE_GETUSERSHELL_D
+
+/* Define if `long long' is supported and sizeof(off_t) >= 8 */
+#undef HAVE_QUAD_SUPPORT
+
+/* Define if not using in-built /bin/ls code */
+#undef NO_INTERNAL_LS
+
+/* Define if using S/Key */
+#undef SKEY
+
+/*
+ * Define this if compiling with SOCKS (the firewall traversal library).
+ * Also, you must define connect, getsockname, bind, accept, listen, and
+ * select to their R-versions.
+ */
+#undef SOCKS
+#undef SOCKS4
+#undef SOCKS5
+#undef connect
+#undef getsockname
+#undef bind
+#undef accept
+#undef listen
+#undef select
+#undef dup
+#undef dup2
+#undef fclose
+#undef gethostbyname
+#undef getpeername
+#undef read
+#undef recv
+#undef recvfrom
+#undef rresvport
+#undef send
+#undef sendto
+#undef shutdown
+#undef write
diff --git a/contrib/lukemftpd/aclocal.m4 b/contrib/lukemftpd/aclocal.m4
new file mode 100644
index 0000000..572f5c5
--- /dev/null
+++ b/contrib/lukemftpd/aclocal.m4
@@ -0,0 +1,257 @@
+dnl $Id: aclocal.m4,v 1.1 2000/07/29 13:34:15 lukem Exp $
+dnl
+
+dnl
+dnl AC_MSG_TRY_COMPILE
+dnl
+dnl Written by Luke Mewburn <lukem@netbsd.org>
+dnl
+dnl Usage:
+dnl AC_MSG_TRY_COMPILE(Message, CacheVar, Includes, Code,
+dnl ActionPass [,ActionFail] )
+dnl
+dnl effectively does:
+dnl AC_CACHE_CHECK(Message, CacheVar,
+dnl AC_TRY_COMPILE(Includes, Code, CacheVar = yes, CacheVar = no)
+dnl if CacheVar == yes
+dnl AC_MESSAGE_RESULT(yes)
+dnl ActionPass
+dnl else
+dnl AC_MESSAGE_RESULT(no)
+dnl ActionFail
+dnl )
+dnl
+AC_DEFUN(AC_MSG_TRY_COMPILE, [
+ AC_CACHE_CHECK($1, $2, [
+ AC_TRY_COMPILE([ $3 ], [ $4; ], [ $2=yes ], [ $2=no ])
+ ])
+ if test "x[$]$2" = "xyes"; then
+ $5
+ else
+ $6
+ :
+ fi
+])
+
+dnl
+dnl AC_MSG_TRY_LINK
+dnl
+dnl Usage:
+dnl AC_MSG_TRY_LINK(Message, CacheVar, Includes, Code,
+dnl ActionPass [,ActionFail] )
+dnl
+dnl as AC_MSG_TRY_COMPILE, but uses AC_TRY_LINK instead of AC_TRY_COMPILE
+dnl
+AC_DEFUN(AC_MSG_TRY_LINK, [
+ AC_CACHE_CHECK($1, $2, [
+ AC_TRY_LINK([ $3 ], [ $4; ], [ $2=yes ], [ $2=no ])
+ ])
+ if test "x[$]$2" = "xyes"; then
+ $5
+ else
+ $6
+ :
+ fi
+])
+
+
+dnl
+dnl AC_LIBRARY_NET: #Id: net.m4,v 1.5 1997/11/09 21:36:54 jhawk Exp #
+dnl
+dnl Written by John Hawkinson <jhawk@mit.edu>. This code is in the Public
+dnl Domain.
+dnl
+dnl This test is for network applications that need socket() and
+dnl gethostbyname() -ish functions. Under Solaris, those applications need to
+dnl link with "-lsocket -lnsl". Under IRIX, they should *not* link with
+dnl "-lsocket" because libsocket.a breaks a number of things (for instance:
+dnl gethostbyname() under IRIX 5.2, and snoop sockets under most versions of
+dnl IRIX).
+dnl
+dnl Unfortunately, many application developers are not aware of this, and
+dnl mistakenly write tests that cause -lsocket to be used under IRIX. It is
+dnl also easy to write tests that cause -lnsl to be used under operating
+dnl systems where neither are necessary (or useful), such as SunOS 4.1.4, which
+dnl uses -lnsl for TLI.
+dnl
+dnl This test exists so that every application developer does not test this in
+dnl a different, and subtly broken fashion.
+dnl
+dnl It has been argued that this test should be broken up into two seperate
+dnl tests, one for the resolver libraries, and one for the libraries necessary
+dnl for using Sockets API. Unfortunately, the two are carefully intertwined and
+dnl allowing the autoconf user to use them independantly potentially results in
+dnl unfortunate ordering dependancies -- as such, such component macros would
+dnl have to carefully use indirection and be aware if the other components were
+dnl executed. Since other autoconf macros do not go to this trouble, and almost
+dnl no applications use sockets without the resolver, this complexity has not
+dnl been implemented.
+dnl
+dnl The check for libresolv is in case you are attempting to link statically
+dnl and happen to have a libresolv.a lying around (and no libnsl.a).
+dnl
+AC_DEFUN(AC_LIBRARY_NET, [
+ # Most operating systems have gethostbyname() in the default searched
+ # libraries (i.e. libc):
+ AC_CHECK_FUNC(gethostbyname, ,
+ # Some OSes (eg. Solaris) place it in libnsl:
+ AC_CHECK_LIB(nsl, gethostbyname, ,
+ # Some strange OSes (SINIX) have it in libsocket:
+ AC_CHECK_LIB(socket, gethostbyname, ,
+ # Unfortunately libsocket sometimes depends on libnsl.
+ # AC_CHECK_LIB's API is essentially broken so the following
+ # ugliness is necessary:
+ AC_CHECK_LIB(socket, gethostbyname,
+ LIBS="-lsocket -lnsl $LIBS",
+ AC_CHECK_LIB(resolv, gethostbyname),
+ -lnsl)
+ )
+ )
+ )
+ AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, ,
+ AC_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", , -lnsl)))
+ ])
+
+
+dnl Checks for SOCKS firewall support.
+dnl
+dnl Written by Matthew R. Green <mrg@eterna.com.au>
+dnl
+AC_DEFUN(AC_LIBRARY_SOCKS, [
+ AC_MSG_CHECKING(whether to support SOCKS)
+ AC_ARG_WITH(socks,
+ [ --with-socks Compile with SOCKS firewall traversal support.],
+ [
+ case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_CHECK_LIB(socks5, SOCKSconnect, [
+ socks=5
+ LIBS="-lsocks5 $LIBS"], [
+ AC_CHECK_LIB(socks, Rconnect, [
+ socks=4
+ LIBS="-lsocks $LIBS"], [
+ AC_MSG_ERROR(Could not find socks library. You must first install socks.) ] ) ] )
+ ;;
+ esac
+ ],
+ AC_MSG_RESULT(no)
+ )
+
+ if test "x$socks" = "x"; then
+ AC_MSG_CHECKING(whether to support SOCKS5)
+ AC_ARG_WITH(socks5,
+ [ --with-socks5[=PATH] Compile with SOCKS5 firewall traversal support.],
+ [
+ case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ socks=5
+ if test "x$withval" = "xyes"; then
+ withval="-lsocks5"
+ else
+ if test -d "$withval"; then
+ if test -d "$withval/include"; then
+ CFLAGS="$CFLAGS -I$withval/include"
+ else
+ CFLAGS="$CFLAGS -I$withval"
+ fi
+ if test -d "$withval/lib"; then
+ withval="-L$withval/lib -lsocks5"
+ else
+ withval="-L$withval -lsocks5"
+ fi
+ fi
+ fi
+ LIBS="$withval $LIBS"
+ # If Socks was compiled with Kerberos support, we will need
+ # to link against kerberos libraries. Temporarily append
+ # to LIBS. This is harmless if there is no kerberos support.
+ TMPLIBS="$LIBS"
+ LIBS="$LIBS $KERBEROS_LIBS"
+ AC_TRY_LINK([],
+ [ SOCKSconnect(); ],
+ [],
+ [ AC_MSG_ERROR(Could not find the $withval library. You must first install socks5.) ])
+ LIBS="$TMPLIBS"
+ ;;
+ esac
+ ],
+ AC_MSG_RESULT(no)
+ )
+ fi
+
+ if test "x$socks" = "x"; then
+ AC_MSG_CHECKING(whether to support SOCKS4)
+ AC_ARG_WITH(socks4,
+ [ --with-socks4[=PATH] Compile with SOCKS4 firewall traversal support.],
+ [
+ case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ socks=4
+ if test "x$withval" = "xyes"; then
+ withval="-lsocks"
+ else
+ if test -d "$withval"; then
+ withval="-L$withval -lsocks"
+ fi
+ fi
+ LIBS="$withval $LIBS"
+ AC_TRY_LINK([],
+ [ Rconnect(); ],
+ [],
+ [ AC_MSG_ERROR(Could not find the $withval library. You must first install socks.) ])
+ ;;
+ esac
+ ],
+ AC_MSG_RESULT(no)
+ )
+ fi
+
+ if test "x$socks" = "x4"; then
+ AC_DEFINE(SOCKS)
+ AC_DEFINE(SOCKS4)
+ AC_DEFINE(connect, Rconnect)
+ AC_DEFINE(getsockname, Rgetsockname)
+ AC_DEFINE(bind, Rbind)
+ AC_DEFINE(accept, Raccept)
+ AC_DEFINE(listen, Rlisten)
+ AC_DEFINE(select, Rselect)
+ fi
+
+ if test "x$socks" = "x5"; then
+ AC_DEFINE(SOCKS)
+ AC_DEFINE(SOCKS5)
+ AC_DEFINE(connect,SOCKSconnect)
+ AC_DEFINE(getsockname,SOCKSgetsockname)
+ AC_DEFINE(getpeername,SOCKSgetpeername)
+ AC_DEFINE(bind,SOCKSbind)
+ AC_DEFINE(accept,SOCKSaccept)
+ AC_DEFINE(listen,SOCKSlisten)
+ AC_DEFINE(select,SOCKSselect)
+ AC_DEFINE(recvfrom,SOCKSrecvfrom)
+ AC_DEFINE(sendto,SOCKSsendto)
+ AC_DEFINE(recv,SOCKSrecv)
+ AC_DEFINE(send,SOCKSsend)
+ AC_DEFINE(read,SOCKSread)
+ AC_DEFINE(write,SOCKSwrite)
+ AC_DEFINE(rresvport,SOCKSrresvport)
+ AC_DEFINE(shutdown,SOCKSshutdown)
+ AC_DEFINE(listen,SOCKSlisten)
+ AC_DEFINE(close,SOCKSclose)
+ AC_DEFINE(dup,SOCKSdup)
+ AC_DEFINE(dup2,SOCKSdup2)
+ AC_DEFINE(fclose,SOCKSfclose)
+ AC_DEFINE(gethostbyname,SOCKSgethostbyname)
+ fi
+])
diff --git a/contrib/lukemftpd/config.h.in b/contrib/lukemftpd/config.h.in
new file mode 100644
index 0000000..b32c4c1
--- /dev/null
+++ b/contrib/lukemftpd/config.h.in
@@ -0,0 +1,274 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+/* $Id: config.h.in,v 1.15 2001/04/28 07:11:46 lukem Exp $ */
+
+
+/* Define if the closedir function returns void instead of int. */
+#undef CLOSEDIR_VOID
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Define if your Fortran 77 compiler doesn't accept -c and -o together. */
+#undef F77_NO_MINUS_C_MINUS_O
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+#undef off_t
+
+/* Define to the type of arg1 for select(). */
+#undef SELECT_TYPE_ARG1
+
+/* Define to the type of args 2, 3 and 4 for select(). */
+#undef SELECT_TYPE_ARG234
+
+/* Define to the type of arg5 for select(). */
+#undef SELECT_TYPE_ARG5
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if the closedir function returns void instead of int. */
+#undef VOID_CLOSEDIR
+
+/* The number of bytes in a off_t. */
+#undef SIZEOF_OFF_T
+
+/* Define if you have the err function. */
+#undef HAVE_ERR
+
+/* Define if you have the fgetln function. */
+#undef HAVE_FGETLN
+
+/* Define if you have the flock function. */
+#undef HAVE_FLOCK
+
+/* Define if you have the fparseln function. */
+#undef HAVE_FPARSELN
+
+/* Define if you have the fts_open function. */
+#undef HAVE_FTS_OPEN
+
+/* Define if you have the getaddrinfo function. */
+#undef HAVE_GETADDRINFO
+
+/* Define if you have the getgrouplist function. */
+#undef HAVE_GETGROUPLIST
+
+/* Define if you have the getnameinfo function. */
+#undef HAVE_GETNAMEINFO
+
+/* Define if you have the getspnam function. */
+#undef HAVE_GETSPNAM
+
+/* Define if you have the getusershell function. */
+#undef HAVE_GETUSERSHELL
+
+/* Define if you have the inet_net_pton function. */
+#undef HAVE_INET_NET_PTON
+
+/* Define if you have the inet_ntop function. */
+#undef HAVE_INET_NTOP
+
+/* Define if you have the inet_pton function. */
+#undef HAVE_INET_PTON
+
+/* Define if you have the lockf function. */
+#undef HAVE_LOCKF
+
+/* Define if you have the mkstemp function. */
+#undef HAVE_MKSTEMP
+
+/* Define if you have the setlogin function. */
+#undef HAVE_SETLOGIN
+
+/* Define if you have the setproctitle function. */
+#undef HAVE_SETPROCTITLE
+
+/* Define if you have the sl_init function. */
+#undef HAVE_SL_INIT
+
+/* Define if you have the snprintf function. */
+#undef HAVE_SNPRINTF
+
+/* Define if you have the strdup function. */
+#undef HAVE_STRDUP
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the strlcat function. */
+#undef HAVE_STRLCAT
+
+/* Define if you have the strlcpy function. */
+#undef HAVE_STRLCPY
+
+/* Define if you have the strmode function. */
+#undef HAVE_STRMODE
+
+/* Define if you have the strsep function. */
+#undef HAVE_STRSEP
+
+/* Define if you have the strtoll function. */
+#undef HAVE_STRTOLL
+
+/* Define if you have the user_from_uid function. */
+#undef HAVE_USER_FROM_UID
+
+/* Define if you have the usleep function. */
+#undef HAVE_USLEEP
+
+/* Define if you have the vfork function. */
+#undef HAVE_VFORK
+
+/* Define if you have the vsyslog function. */
+#undef HAVE_VSYSLOG
+
+/* Define if you have the <arpa/nameser.h> header file. */
+#undef HAVE_ARPA_NAMESER_H
+
+/* Define if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <err.h> header file. */
+#undef HAVE_ERR_H
+
+/* Define if you have the <fts.h> header file. */
+#undef HAVE_FTS_H
+
+/* Define if you have the <libutil.h> header file. */
+#undef HAVE_LIBUTIL_H
+
+/* Define if you have the <ndir.h> header file. */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <paths.h> header file. */
+#undef HAVE_PATHS_H
+
+/* Define if you have the <sys/dir.h> header file. */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file. */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/sysmacros.h> header file. */
+#undef HAVE_SYS_SYSMACROS_H
+
+/* Define if you have the <util.h> header file. */
+#undef HAVE_UTIL_H
+
+/* Define if you have the crypt library (-lcrypt). */
+#undef HAVE_LIBCRYPT
+
+/* Define if you have the nsl library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define if you have the skey library (-lskey). */
+#undef HAVE_LIBSKEY
+
+/* Define if you have the socket library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define if you have the util library (-lutil). */
+#undef HAVE_LIBUTIL
+
+/* Define if your compiler supports `long long' */
+#undef HAVE_LONG_LONG
+
+/* Define if *printf() uses %qd to print `long long' (otherwise uses %lld) */
+#undef HAVE_PRINTF_QD
+
+/* Define if in_port_t exists */
+#undef HAVE_IN_PORT_T
+
+/* Define if struct sockaddr.sa_len exists (implies sockaddr_in.sin_len, etc) */
+#undef HAVE_SOCKADDR_SA_LEN
+
+/* Define if socklen_t exists */
+#undef HAVE_SOCKLEN_T
+
+/* Define if AF_INET6 exists in <sys/socket.h> */
+#undef HAVE_AF_INET6
+
+/* Define if `struct sockaddr_in6' exists in <netinet/in.h> */
+#undef HAVE_SOCKADDR_IN6
+
+/* Define if `struct addrinfo' exists in <netdb.h> */
+#undef HAVE_ADDRINFO
+
+/*
+ * Define if <netdb.h> contains AI_NUMERICHOST et al.
+ * Systems which only implement RFC2133 will need this.
+ */
+#undef HAVE_RFC2553_NETDB
+
+/* Define if `struct direct' has a d_namlen element */
+#undef HAVE_D_NAMLEN
+
+/* Define if struct passwd.pw_expire exists. */
+#undef HAVE_PW_EXPIRE
+
+/* Define if GLOB_BRACE, gl_path and gl_match exist in <glob.h> */
+#undef HAVE_WORKING_GLOB
+
+/* Define if crypt() is declared in <unistd.h> */
+#undef HAVE_CRYPT_D
+
+/* Define if fclose() is declared in <stdio.h> */
+#undef HAVE_FCLOSE_D
+
+/* Define if optarg is declared in <stdlib.h> or <unistd.h> */
+#undef HAVE_OPTARG_D
+
+/* Define if optind is declared in <stdlib.h> or <unistd.h> */
+#undef HAVE_OPTIND_D
+
+/* Define if optreset exists */
+#undef HAVE_OPTRESET
+
+/* Define if pclose() is declared in <stdio.h> */
+#undef HAVE_PCLOSE_D
+
+/* Define if getusershell() is declared in <unistd.h> */
+#undef HAVE_GETUSERSHELL_D
+
+/* Define if `long long' is supported and sizeof(off_t) >= 8 */
+#undef HAVE_QUAD_SUPPORT
+
+/* Define if not using in-built /bin/ls code */
+#undef NO_INTERNAL_LS
+
+/* Define if using S/Key */
+#undef SKEY
+
+/*
+ * Define this if compiling with SOCKS (the firewall traversal library).
+ * Also, you must define connect, getsockname, bind, accept, listen, and
+ * select to their R-versions.
+ */
+#undef SOCKS
+#undef SOCKS4
+#undef SOCKS5
+#undef connect
+#undef getsockname
+#undef bind
+#undef accept
+#undef listen
+#undef select
+#undef dup
+#undef dup2
+#undef fclose
+#undef gethostbyname
+#undef getpeername
+#undef read
+#undef recv
+#undef recvfrom
+#undef rresvport
+#undef send
+#undef sendto
+#undef shutdown
+#undef write
diff --git a/contrib/lukemftpd/configure b/contrib/lukemftpd/configure
new file mode 100755
index 0000000..2a7563d
--- /dev/null
+++ b/contrib/lukemftpd/configure
@@ -0,0 +1,4091 @@
+#! /bin/sh
+
+# From configure.in Revision: 1.16
+
+
+
+
+
+
+
+
+
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+\
+ --enable-ipv6 Enable IPv6 support (if your OS supports it).
+ --disable-ipv6 Disable IPv6 support (even if your OS supports it)
+ [default: enabled]."
+ac_help="$ac_help
+\
+ --enable-builtinls Enable built-in /bin/ls. [default: enabled]
+ --disable-builtinls Disable built-in /bin/ls."
+ac_help="$ac_help
+ --with-socks Compile with SOCKS firewall traversal support."
+ac_help="$ac_help
+ --with-socks5[=PATH] Compile with SOCKS5 firewall traversal support."
+ac_help="$ac_help
+ --with-socks4[=PATH] Compile with SOCKS4 firewall traversal support."
+ac_help="$ac_help
+ --with-skey Compile with S/Key authentication support."
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=lukemftpd.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+# Check whether --enable-ipv6 or --disable-ipv6 was given.
+if test "${enable_ipv6+set}" = set; then
+ enableval="$enable_ipv6"
+ opt_ipv6=$enableval
+else
+ opt_ipv6=yes
+fi
+
+# Check whether --enable-builtinls or --disable-builtinls was given.
+if test "${enable_builtinls+set}" = set; then
+ enableval="$enable_builtinls"
+ opt_builtinls=$enableval
+else
+ opt_builtinls=yes
+fi
+
+
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:574: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:603: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:633: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:684: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:716: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 727 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:732: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:758: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:763: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:772: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:791: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:827: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_AWK="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+ echo "$ac_t""$AWK" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
+done
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:887: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:942: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+for ac_prog in 'bison -y' byacc
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:974: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$YACC"; then
+ ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_YACC="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+YACC="$ac_cv_prog_YACC"
+if test -n "$YACC"; then
+ echo "$ac_t""$YACC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+for ac_prog in ar
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1009: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_AR="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+AR="$ac_cv_prog_AR"
+if test -n "$AR"; then
+ echo "$ac_t""$AR" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AR" && break
+done
+
+
+
+echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6
+echo "configure:1041: checking for crypt in -lcrypt" >&5
+ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lcrypt $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1049 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt();
+
+int main() {
+crypt()
+; return 0; }
+EOF
+if { (eval echo configure:1060: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo crypt | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lcrypt $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for fparseln in -lutil""... $ac_c" 1>&6
+echo "configure:1088: checking for fparseln in -lutil" >&5
+ac_lib_var=`echo util'_'fparseln | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lutil $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1096 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char fparseln();
+
+int main() {
+fparseln()
+; return 0; }
+EOF
+if { (eval echo configure:1107: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo util | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lutil $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test $ac_cv_lib_util_fparseln != yes; then
+ echo $ac_n "checking for setproctitle in -lutil""... $ac_c" 1>&6
+echo "configure:1136: checking for setproctitle in -lutil" >&5
+ac_lib_var=`echo util'_'setproctitle | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lutil $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1144 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setproctitle();
+
+int main() {
+setproctitle()
+; return 0; }
+EOF
+if { (eval echo configure:1155: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo util | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lutil $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+ # Most operating systems have gethostbyname() in the default searched
+ # libraries (i.e. libc):
+ echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
+echo "configure:1187: checking for gethostbyname" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1192 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char gethostbyname(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname)
+choke me
+#else
+gethostbyname();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1215: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_gethostbyname=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_gethostbyname=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+# Some OSes (eg. Solaris) place it in libnsl:
+ echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6
+echo "configure:1234: checking for gethostbyname in -lnsl" >&5
+ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1242 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1253: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lnsl $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+# Some strange OSes (SINIX) have it in libsocket:
+ echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6
+echo "configure:1280: checking for gethostbyname in -lsocket" >&5
+ac_lib_var=`echo socket'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1288 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1299: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsocket $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+# Unfortunately libsocket sometimes depends on libnsl.
+ # AC_CHECK_LIB's API is essentially broken so the following
+ # ugliness is necessary:
+ echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6
+echo "configure:1328: checking for gethostbyname in -lsocket" >&5
+ac_lib_var=`echo socket'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket -lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1336 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1347: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="-lsocket -lnsl $LIBS"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for gethostbyname in -lresolv""... $ac_c" 1>&6
+echo "configure:1366: checking for gethostbyname in -lresolv" >&5
+ac_lib_var=`echo resolv'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lresolv $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1374 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1385: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo resolv | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lresolv $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ echo $ac_n "checking for socket""... $ac_c" 1>&6
+echo "configure:1424: checking for socket" >&5
+if eval "test \"`echo '$''{'ac_cv_func_socket'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1429 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char socket(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_socket) || defined (__stub___socket)
+choke me
+#else
+socket();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1452: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_socket=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_socket=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'socket`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:1470: checking for socket in -lsocket" >&5
+ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1478 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:1489: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsocket $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:1515: checking for socket in -lsocket" >&5
+ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket -lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1523 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:1534: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="-lsocket -lnsl $LIBS"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+fi
+
+
+
+ echo $ac_n "checking whether to support SOCKS""... $ac_c" 1>&6
+echo "configure:1561: checking whether to support SOCKS" >&5
+ # Check whether --with-socks or --without-socks was given.
+if test "${with_socks+set}" = set; then
+ withval="$with_socks"
+
+ case "$withval" in
+ no)
+ echo "$ac_t""no" 1>&6
+ ;;
+ yes)
+ echo "$ac_t""yes" 1>&6
+ echo $ac_n "checking for SOCKSconnect in -lsocks5""... $ac_c" 1>&6
+echo "configure:1573: checking for SOCKSconnect in -lsocks5" >&5
+ac_lib_var=`echo socks5'_'SOCKSconnect | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocks5 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1581 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char SOCKSconnect();
+
+int main() {
+SOCKSconnect()
+; return 0; }
+EOF
+if { (eval echo configure:1592: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+
+ socks=5
+ LIBS="-lsocks5 $LIBS"
+else
+ echo "$ac_t""no" 1>&6
+
+ echo $ac_n "checking for Rconnect in -lsocks""... $ac_c" 1>&6
+echo "configure:1614: checking for Rconnect in -lsocks" >&5
+ac_lib_var=`echo socks'_'Rconnect | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocks $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1622 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char Rconnect();
+
+int main() {
+Rconnect()
+; return 0; }
+EOF
+if { (eval echo configure:1633: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+
+ socks=4
+ LIBS="-lsocks $LIBS"
+else
+ echo "$ac_t""no" 1>&6
+
+ { echo "configure: error: Could not find socks library. You must first install socks." 1>&2; exit 1; }
+fi
+
+fi
+
+ ;;
+ esac
+
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+ if test "x$socks" = "x"; then
+ echo $ac_n "checking whether to support SOCKS5""... $ac_c" 1>&6
+echo "configure:1670: checking whether to support SOCKS5" >&5
+ # Check whether --with-socks5 or --without-socks5 was given.
+if test "${with_socks5+set}" = set; then
+ withval="$with_socks5"
+
+ case "$withval" in
+ no)
+ echo "$ac_t""no" 1>&6
+ ;;
+ *)
+ echo "$ac_t""yes" 1>&6
+ socks=5
+ if test "x$withval" = "xyes"; then
+ withval="-lsocks5"
+ else
+ if test -d "$withval"; then
+ if test -d "$withval/include"; then
+ CFLAGS="$CFLAGS -I$withval/include"
+ else
+ CFLAGS="$CFLAGS -I$withval"
+ fi
+ if test -d "$withval/lib"; then
+ withval="-L$withval/lib -lsocks5"
+ else
+ withval="-L$withval -lsocks5"
+ fi
+ fi
+ fi
+ LIBS="$withval $LIBS"
+ # If Socks was compiled with Kerberos support, we will need
+ # to link against kerberos libraries. Temporarily append
+ # to LIBS. This is harmless if there is no kerberos support.
+ TMPLIBS="$LIBS"
+ LIBS="$LIBS $KERBEROS_LIBS"
+ cat > conftest.$ac_ext <<EOF
+#line 1705 "configure"
+#include "confdefs.h"
+
+int main() {
+ SOCKSconnect();
+; return 0; }
+EOF
+if { (eval echo configure:1712: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Could not find the $withval library. You must first install socks5." 1>&2; exit 1; }
+fi
+rm -f conftest*
+ LIBS="$TMPLIBS"
+ ;;
+ esac
+
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+ fi
+
+ if test "x$socks" = "x"; then
+ echo $ac_n "checking whether to support SOCKS4""... $ac_c" 1>&6
+echo "configure:1734: checking whether to support SOCKS4" >&5
+ # Check whether --with-socks4 or --without-socks4 was given.
+if test "${with_socks4+set}" = set; then
+ withval="$with_socks4"
+
+ case "$withval" in
+ no)
+ echo "$ac_t""no" 1>&6
+ ;;
+ *)
+ echo "$ac_t""yes" 1>&6
+ socks=4
+ if test "x$withval" = "xyes"; then
+ withval="-lsocks"
+ else
+ if test -d "$withval"; then
+ withval="-L$withval -lsocks"
+ fi
+ fi
+ LIBS="$withval $LIBS"
+ cat > conftest.$ac_ext <<EOF
+#line 1755 "configure"
+#include "confdefs.h"
+
+int main() {
+ Rconnect();
+; return 0; }
+EOF
+if { (eval echo configure:1762: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Could not find the $withval library. You must first install socks." 1>&2; exit 1; }
+fi
+rm -f conftest*
+ ;;
+ esac
+
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+ fi
+
+ if test "x$socks" = "x4"; then
+ cat >> confdefs.h <<\EOF
+#define SOCKS 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define SOCKS4 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define connect Rconnect
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define getsockname Rgetsockname
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define bind Rbind
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define accept Raccept
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define listen Rlisten
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define select Rselect
+EOF
+
+ fi
+
+ if test "x$socks" = "x5"; then
+ cat >> confdefs.h <<\EOF
+#define SOCKS 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define SOCKS5 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define connect SOCKSconnect
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define getsockname SOCKSgetsockname
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define getpeername SOCKSgetpeername
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define bind SOCKSbind
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define accept SOCKSaccept
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define listen SOCKSlisten
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define select SOCKSselect
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define recvfrom SOCKSrecvfrom
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define sendto SOCKSsendto
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define recv SOCKSrecv
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define send SOCKSsend
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define read SOCKSread
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define write SOCKSwrite
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define rresvport SOCKSrresvport
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define shutdown SOCKSshutdown
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define listen SOCKSlisten
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define close SOCKSclose
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define dup SOCKSdup
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define dup2 SOCKSdup2
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define fclose SOCKSfclose
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define gethostbyname SOCKSgethostbyname
+EOF
+
+ fi
+
+if test -n "$socks"; then
+ if test $opt_ipv6 = yes; then
+ echo "IPv6 is incompatible with socks, disabling IPv6 support"
+ opt_ipv6=no
+ fi
+fi
+# Check whether --with-skey or --without-skey was given.
+if test "${with_skey+set}" = set; then
+ withval="$with_skey"
+ if test $withval = yes; then
+ echo $ac_n "checking for skey_haskey in -lskey""... $ac_c" 1>&6
+echo "configure:1922: checking for skey_haskey in -lskey" >&5
+ac_lib_var=`echo skey'_'skey_haskey | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lskey $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1930 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char skey_haskey();
+
+int main() {
+skey_haskey()
+; return 0; }
+EOF
+if { (eval echo configure:1941: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo skey | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lskey $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ fi
+fi
+
+echo $ac_n "checking whether to support S/Key""... $ac_c" 1>&6
+echo "configure:1972: checking whether to support S/Key" >&5
+if test x"$ac_cv_lib_skey_skey_haskey" = "xyes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define SKEY 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1990: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1995 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:2003: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:2028: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldir $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2036 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2047: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -ldir"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:2069: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lx $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2077 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2088: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lx"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:2111: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 2126 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2132: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 2143 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2149: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 2160 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2166: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:2191: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2196 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2204: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 2221 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 2239 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2260 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:2271: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in arpa/nameser.h err.h fts.h libutil.h paths.h \
+ sys/sysmacros.h util.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2299: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2304 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2309: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:2338: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2343 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:2352: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:2373: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2378 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_off_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+ cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking size of off_t""... $ac_c" 1>&6
+echo "configure:2406: checking size of off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_sizeof_off_t=0
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2414 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(off_t));
+ exit(0);
+}
+EOF
+if { (eval echo configure:2425: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_sizeof_off_t=`cat conftestval`
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_sizeof_off_t=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_off_t" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_OFF_T $ac_cv_sizeof_off_t
+EOF
+
+
+
+ echo $ac_n "checking for long long""... $ac_c" 1>&6
+echo "configure:2446: checking for long long" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_LONG_LONG'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2452 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+int main() {
+
+long long X = 2, Y = 1, Z;
+Z = X / Y; ;
+; return 0; }
+EOF
+if { (eval echo configure:2462: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ftp_cv_HAVE_LONG_LONG=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_LONG_LONG=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_LONG_LONG" 1>&6
+ if test "x$ftp_cv_HAVE_LONG_LONG" = "xyes"; then
+
+cat >> confdefs.h <<\EOF
+#define HAVE_LONG_LONG 1
+EOF
+
+have_long_long=yes
+ else
+ have_long_long=no
+ :
+ fi
+
+
+
+ echo $ac_n "checking for in_port_t""... $ac_c" 1>&6
+echo "configure:2491: checking for in_port_t" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_IN_PORT_T'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2497 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+int main() {
+ in_port_t X ;
+; return 0; }
+EOF
+if { (eval echo configure:2506: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_IN_PORT_T=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_IN_PORT_T=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_IN_PORT_T" 1>&6
+ if test "x$ftp_cv_HAVE_IN_PORT_T" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_IN_PORT_T 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for sockaddr_in.sin_len""... $ac_c" 1>&6
+echo "configure:2533: checking for sockaddr_in.sin_len" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_SOCKADDR_SA_LEN'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2539 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+int main() {
+
+ struct sockaddr_in sin;
+ int X = sin.sin_len ;
+; return 0; }
+EOF
+if { (eval echo configure:2551: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKADDR_SA_LEN=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKADDR_SA_LEN=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_SOCKADDR_SA_LEN" 1>&6
+ if test "x$ftp_cv_HAVE_SOCKADDR_SA_LEN" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SOCKADDR_SA_LEN 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for socklen_t""... $ac_c" 1>&6
+echo "configure:2578: checking for socklen_t" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_SOCKLEN_T'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2584 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int main() {
+ socklen_t X ;
+; return 0; }
+EOF
+if { (eval echo configure:2593: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKLEN_T=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKLEN_T=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_SOCKLEN_T" 1>&6
+ if test "x$ftp_cv_HAVE_SOCKLEN_T" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SOCKLEN_T 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+if test $opt_ipv6 = yes; then
+
+
+ echo $ac_n "checking for AF_INET6""... $ac_c" 1>&6
+echo "configure:2622: checking for AF_INET6" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_AF_INET6'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2628 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int main() {
+ int X = AF_INET6 ;
+; return 0; }
+EOF
+if { (eval echo configure:2637: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_AF_INET6=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_AF_INET6=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_AF_INET6" 1>&6
+ if test "x$ftp_cv_HAVE_AF_INET6" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_AF_INET6 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for struct sockaddr_in6""... $ac_c" 1>&6
+echo "configure:2664: checking for struct sockaddr_in6" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_SOCKADDR_IN6'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2670 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+int main() {
+ struct sockaddr_in6 X ;
+; return 0; }
+EOF
+if { (eval echo configure:2679: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKADDR_IN6=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKADDR_IN6=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_SOCKADDR_IN6" 1>&6
+ if test "x$ftp_cv_HAVE_SOCKADDR_IN6" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SOCKADDR_IN6 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+fi
+
+
+ echo $ac_n "checking for struct addrinfo""... $ac_c" 1>&6
+echo "configure:2708: checking for struct addrinfo" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_ADDRINFO'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2714 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+int main() {
+ struct addrinfo X ;
+; return 0; }
+EOF
+if { (eval echo configure:2724: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_ADDRINFO=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_ADDRINFO=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_ADDRINFO" 1>&6
+ if test "x$ftp_cv_HAVE_ADDRINFO" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ADDRINFO 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for d_namlen in struct dirent""... $ac_c" 1>&6
+echo "configure:2751: checking for d_namlen in struct dirent" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_D_NAMLEN'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2757 "configure"
+#include "confdefs.h"
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+int main() {
+
+ struct dirent dp;
+ int X = dp.d_namlen; ;
+; return 0; }
+EOF
+if { (eval echo configure:2780: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_D_NAMLEN=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_D_NAMLEN=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_D_NAMLEN" 1>&6
+ if test "x$ftp_cv_HAVE_D_NAMLEN" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_D_NAMLEN 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for struct passwd.pw_expire""... $ac_c" 1>&6
+echo "configure:2807: checking for struct passwd.pw_expire" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_PW_EXPIRE'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2813 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <pwd.h>
+int main() {
+ struct passwd pw;
+ time_t X = pw.pw_expire ;
+; return 0; }
+EOF
+if { (eval echo configure:2823: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_PW_EXPIRE=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_PW_EXPIRE=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_PW_EXPIRE" 1>&6
+ if test "x$ftp_cv_HAVE_PW_EXPIRE" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_PW_EXPIRE 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:2849: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2854 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:2903: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+
+
+for ac_func in err fgetln getaddrinfo getgrouplist getnameinfo \
+ getusershell inet_net_pton inet_ntop inet_pton mkstemp \
+ sl_init snprintf strdup strerror strlcat strlcpy strsep \
+ usleep vsyslog
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2931: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2936 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2959: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+for ac_func in flock lockf getspnam setlogin setproctitle vfork
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2988: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2993 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3016: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+if test $ac_cv_lib_util_fparseln != yes; then
+ for ac_func in fparseln
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3044: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3049 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3072: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+fi
+
+LIBOBJS="$LIBOBJS glob.o"
+
+
+ echo $ac_n "checking for crypt() declaration""... $ac_c" 1>&6
+echo "configure:3104: checking for crypt() declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_CRYPT_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3110 "configure"
+#include "confdefs.h"
+
+#include <unistd.h>
+int main() {
+ char *(*X)() = crypt ;
+; return 0; }
+EOF
+if { (eval echo configure:3118: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_CRYPT_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_CRYPT_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_CRYPT_D" 1>&6
+ if test "x$ftp_cv_HAVE_CRYPT_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_CRYPT_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for fclose() declaration""... $ac_c" 1>&6
+echo "configure:3145: checking for fclose() declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_FCLOSE_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3151 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+int main() {
+ int (*X)() = fclose ;
+; return 0; }
+EOF
+if { (eval echo configure:3159: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_FCLOSE_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_FCLOSE_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_FCLOSE_D" 1>&6
+ if test "x$ftp_cv_HAVE_FCLOSE_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_FCLOSE_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for optarg declaration""... $ac_c" 1>&6
+echo "configure:3186: checking for optarg declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_OPTARG_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3192 "configure"
+#include "confdefs.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+int main() {
+ char *X = optarg ;
+; return 0; }
+EOF
+if { (eval echo configure:3201: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_OPTARG_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_OPTARG_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_OPTARG_D" 1>&6
+ if test "x$ftp_cv_HAVE_OPTARG_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_OPTARG_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for optind declaration""... $ac_c" 1>&6
+echo "configure:3228: checking for optind declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_OPTIND_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3234 "configure"
+#include "confdefs.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+int main() {
+ int X = optind ;
+; return 0; }
+EOF
+if { (eval echo configure:3243: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_OPTIND_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_OPTIND_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_OPTIND_D" 1>&6
+ if test "x$ftp_cv_HAVE_OPTIND_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_OPTIND_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for optreset""... $ac_c" 1>&6
+echo "configure:3270: checking for optreset" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_OPTRESET'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3276 "configure"
+#include "confdefs.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+int main() {
+ int X = optreset ;
+; return 0; }
+EOF
+if { (eval echo configure:3285: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ftp_cv_HAVE_OPTRESET=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_OPTRESET=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_OPTRESET" 1>&6
+ if test "x$ftp_cv_HAVE_OPTRESET" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_OPTRESET 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for pclose() declaration""... $ac_c" 1>&6
+echo "configure:3312: checking for pclose() declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_PCLOSE_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3318 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+int main() {
+ int (*X)() = pclose ;
+; return 0; }
+EOF
+if { (eval echo configure:3326: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_PCLOSE_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_PCLOSE_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_PCLOSE_D" 1>&6
+ if test "x$ftp_cv_HAVE_PCLOSE_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_PCLOSE_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+if test $ac_cv_func_getusershell = yes; then
+
+ echo $ac_n "checking for getusershell() declaration""... $ac_c" 1>&6
+echo "configure:3354: checking for getusershell() declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_GETUSERSHELL_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3360 "configure"
+#include "confdefs.h"
+
+ #include <unistd.h>
+int main() {
+ char *(*X)() = getusershell ;
+; return 0; }
+EOF
+if { (eval echo configure:3368: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_GETUSERSHELL_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_GETUSERSHELL_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_GETUSERSHELL_D" 1>&6
+ if test "x$ftp_cv_HAVE_GETUSERSHELL_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_GETUSERSHELL_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+fi
+
+
+if test $have_long_long = yes -a $ac_cv_sizeof_off_t -ge 8; then
+
+
+ echo $ac_n "checking *printf() support for %lld""... $ac_c" 1>&6
+echo "configure:3399: checking *printf() support for %lld" >&5
+ can_printf_longlong=no
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3405 "configure"
+#include "confdefs.h"
+
+ #include <stdio.h>
+ int main() {
+ char buf[100];
+ sprintf(buf, "%lld", 4294967300LL);
+ return (strcmp(buf, "4294967300"));
+ }
+
+EOF
+if { (eval echo configure:3416: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+
+ echo "$ac_t""yes" 1>&6
+ can_printf_longlong=yes
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+
+ echo "$ac_t""no" 1>&6
+
+fi
+rm -fr conftest*
+fi
+
+
+ if test $can_printf_longlong != yes; then
+ echo $ac_n "checking *printf() support for %qd""... $ac_c" 1>&6
+echo "configure:3436: checking *printf() support for %qd" >&5
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3441 "configure"
+#include "confdefs.h"
+
+ #include <stdio.h>
+ int main() {
+ char buf[100];
+ sprintf(buf, "%qd", 4294967300LL);
+ return (strcmp(buf, "4294967300"));
+ }
+
+EOF
+if { (eval echo configure:3452: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+
+ echo "$ac_t""yes" 1>&6
+ can_printf_longlong=yes
+ cat >> confdefs.h <<\EOF
+#define HAVE_PRINTF_QD 1
+EOF
+
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+
+ echo "$ac_t""no" 1>&6
+
+fi
+rm -fr conftest*
+fi
+
+ fi
+
+ if test $can_printf_longlong = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_QUAD_SUPPORT 1
+EOF
+
+ for ac_func in strtoll
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3483: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3488 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3511: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+ fi
+
+fi
+
+
+have_rfc2553_netdb=no
+if test $ac_cv_func_getaddrinfo = yes -a ! -n "$socks"; then
+
+ echo $ac_n "checking for AI_NUMERICHOST""... $ac_c" 1>&6
+echo "configure:3546: checking for AI_NUMERICHOST" >&5
+if eval "test \"`echo '$''{'ftp_cv_have_ai_numerichost'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3552 "configure"
+#include "confdefs.h"
+
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netdb.h>
+int main() {
+ int X = AI_NUMERICHOST ;
+; return 0; }
+EOF
+if { (eval echo configure:3562: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_have_ai_numerichost=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_have_ai_numerichost=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_have_ai_numerichost" 1>&6
+ if test "x$ftp_cv_have_ai_numerichost" = "xyes"; then
+ have_rfc2553_netdb=yes
+ else
+
+ :
+ fi
+
+fi
+echo $ac_n "checking for working getaddrinfo()""... $ac_c" 1>&6
+echo "configure:3585: checking for working getaddrinfo()" >&5
+if test $have_rfc2553_netdb = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_RFC2553_NETDB 1
+EOF
+
+ echo "$ac_t""yes" 1>&6
+else
+ if test $ac_cv_func_getaddrinfo = yes; then
+ LIBOBJS="$LIBOBJS getaddrinfo.o"
+ echo "$ac_t""no - using local version" 1>&6
+ else
+ echo "$ac_t""using local version" 1>&6
+ fi
+fi
+
+if test $ac_cv_func_sl_init = yes; then
+
+ echo $ac_n "checking if sl_add() returns int""... $ac_c" 1>&6
+echo "configure:3604: checking if sl_add() returns int" >&5
+if eval "test \"`echo '$''{'ftp_cv_INT_SL_ADD'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3610 "configure"
+#include "confdefs.h"
+
+ #include <stringlist.h>
+int main() {
+ int f = sl_add((StringList *)0, "foo") ;
+; return 0; }
+EOF
+if { (eval echo configure:3618: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_INT_SL_ADD=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_INT_SL_ADD=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_INT_SL_ADD" 1>&6
+ if test "x$ftp_cv_INT_SL_ADD" = "xyes"; then
+ :
+ else
+ LIBOBJS="$LIBOBJS sl_init.o"
+ :
+ fi
+
+fi
+
+
+
+if test $opt_builtinls = yes; then
+ for ac_func in fts_open strmode user_from_uid
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3647: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3652 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3675: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+ LSOBJS="cmp.o ls.o print.o util.o"
+else
+ cat >> confdefs.h <<\EOF
+#define NO_INTERNAL_LS 1
+EOF
+
+fi
+
+
+
+if test -n "$LIBOBJS"; then
+ INCLUDES="$INCLUDES -I\${srcdir}/../libukem"
+ LDFLAGS="$LDFLAGS -L../libukem"
+ LIBS="$LIBS -lukem"
+ LIBUKEM=libukem.a
+ LIBDEPENDS="$LIBDEPENDS ../libukem/libukem.a"
+fi
+
+
+
+
+
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile libukem/Makefile src/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@AWK@%$AWK%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@RANLIB@%$RANLIB%g
+s%@YACC@%$YACC%g
+s%@AR@%$AR%g
+s%@CPP@%$CPP%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@INCLUDES@%$INCLUDES%g
+s%@LIBUKEM@%$LIBUKEM%g
+s%@LIBDEPENDS@%$LIBDEPENDS%g
+s%@LSOBJS@%$LSOBJS%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile libukem/Makefile src/Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/contrib/lukemftpd/configure.in b/contrib/lukemftpd/configure.in
new file mode 100644
index 0000000..87331d0
--- /dev/null
+++ b/contrib/lukemftpd/configure.in
@@ -0,0 +1,300 @@
+dnl $Id: configure.in,v 1.16 2001/04/28 07:11:06 lukem Exp $
+dnl
+dnl configure.in --
+dnl process this file with autoconf to produce a configure script.
+dnl
+
+AC_REVISION($Revision: 1.16 $)dnl
+
+AC_INIT(lukemftpd.h)
+
+
+dnl Arguments for which features are included
+dnl
+AC_ARG_ENABLE(ipv6, [\
+ --enable-ipv6 Enable IPv6 support (if your OS supports it).
+ --disable-ipv6 Disable IPv6 support (even if your OS supports it)
+ [default: enabled].],
+ opt_ipv6=$enableval,
+ opt_ipv6=yes)
+AC_ARG_ENABLE(builtinls, [\
+ --enable-builtinls Enable built-in /bin/ls. [default: enabled]
+ --disable-builtinls Disable built-in /bin/ls.],
+ opt_builtinls=$enableval,
+ opt_builtinls=yes)
+
+
+dnl Checks for programs.
+dnl
+AC_PROG_MAKE_SET
+AC_PROG_CC
+AC_PROG_AWK
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AC_PROG_YACC
+AC_CHECK_PROGS(AR, ar)
+
+
+dnl Checks for libraries.
+dnl
+AC_CHECK_LIB(crypt, crypt)
+AC_CHECK_LIB(util, fparseln)
+if test $ac_cv_lib_util_fparseln != yes; then
+ AC_CHECK_LIB(util, setproctitle)
+fi
+AC_LIBRARY_NET
+AC_LIBRARY_SOCKS
+if test -n "$socks"; then
+ if test $opt_ipv6 = yes; then
+ echo "IPv6 is incompatible with socks, disabling IPv6 support"
+ opt_ipv6=no
+ fi
+fi
+AC_ARG_WITH(skey,
+[ --with-skey Compile with S/Key authentication support.],
+[ if test $withval = yes; then
+ AC_CHECK_LIB(skey, skey_haskey)
+ fi ] )
+AC_MSG_CHECKING(whether to support S/Key)
+if test x"$ac_cv_lib_skey_skey_haskey" = "xyes"; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(SKEY, 1)
+else
+ AC_MSG_RESULT(no)
+fi
+
+
+dnl Checks for header files.
+dnl
+AC_CONFIG_HEADER(config.h)
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(arpa/nameser.h err.h fts.h libutil.h paths.h \
+ sys/sysmacros.h util.h)
+
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+dnl
+AC_HEADER_TIME
+AC_TYPE_OFF_T
+AC_CHECK_SIZEOF(off_t, 0)
+AC_MSG_TRY_LINK(for long long, ftp_cv_HAVE_LONG_LONG, [
+#include <sys/types.h>] , [
+long long X = 2, Y = 1, Z;
+Z = X / Y; ], [
+AC_DEFINE(HAVE_LONG_LONG, 1)
+have_long_long=yes], [have_long_long=no])
+
+AC_MSG_TRY_COMPILE(for in_port_t, ftp_cv_HAVE_IN_PORT_T, [
+#include <sys/types.h>
+#include <netinet/in.h> ], [ in_port_t X ], [AC_DEFINE(HAVE_IN_PORT_T, 1)])
+
+AC_MSG_TRY_COMPILE(for sockaddr_in.sin_len, ftp_cv_HAVE_SOCKADDR_SA_LEN, [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> ], [
+ struct sockaddr_in sin;
+ int X = sin.sin_len ], [AC_DEFINE(HAVE_SOCKADDR_SA_LEN, 1)])
+
+AC_MSG_TRY_COMPILE(for socklen_t, ftp_cv_HAVE_SOCKLEN_T, [
+#include <sys/types.h>
+#include <sys/socket.h> ], [ socklen_t X ], [AC_DEFINE(HAVE_SOCKLEN_T, 1)])
+
+if test $opt_ipv6 = yes; then
+
+ AC_MSG_TRY_COMPILE(for AF_INET6, ftp_cv_HAVE_AF_INET6, [
+#include <sys/types.h>
+#include <sys/socket.h> ],
+ [ int X = AF_INET6 ], [AC_DEFINE(HAVE_AF_INET6, 1)])
+
+ AC_MSG_TRY_COMPILE(for struct sockaddr_in6, ftp_cv_HAVE_SOCKADDR_IN6, [
+#include <sys/types.h>
+#include <netinet/in.h> ],
+ [ struct sockaddr_in6 X ], [AC_DEFINE(HAVE_SOCKADDR_IN6, 1)])
+
+fi
+
+AC_MSG_TRY_COMPILE(for struct addrinfo, ftp_cv_HAVE_ADDRINFO, [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h> ],
+ [ struct addrinfo X ], [AC_DEFINE(HAVE_ADDRINFO, 1)])
+
+AC_MSG_TRY_COMPILE(for d_namlen in struct dirent, ftp_cv_HAVE_D_NAMLEN, [
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif ], [
+ struct dirent dp;
+ int X = dp.d_namlen; ], [AC_DEFINE(HAVE_D_NAMLEN, 1)])
+
+AC_MSG_TRY_COMPILE(for struct passwd.pw_expire, ftp_cv_HAVE_PW_EXPIRE, [
+#include <sys/types.h>
+#include <pwd.h> ],
+ [ struct passwd pw;
+ time_t X = pw.pw_expire ], [AC_DEFINE(HAVE_PW_EXPIRE, 1)])
+
+AC_C_CONST
+
+
+dnl Checks for library functions.
+dnl
+AC_REPLACE_FUNCS(err fgetln getaddrinfo getgrouplist getnameinfo \
+ getusershell inet_net_pton inet_ntop inet_pton mkstemp \
+ sl_init snprintf strdup strerror strlcat strlcpy strsep \
+ usleep vsyslog)
+AC_CHECK_FUNCS(flock lockf getspnam setlogin setproctitle vfork)
+if test $ac_cv_lib_util_fparseln != yes; then
+ AC_REPLACE_FUNCS(fparseln)
+fi
+
+LIBOBJS="$LIBOBJS glob.o"
+
+AC_MSG_TRY_COMPILE(for crypt() declaration, ftp_cv_HAVE_CRYPT_D, [
+#include <unistd.h> ], [ char *(*X)() = crypt ], [AC_DEFINE(HAVE_CRYPT_D, 1)])
+
+AC_MSG_TRY_COMPILE(for fclose() declaration, ftp_cv_HAVE_FCLOSE_D, [
+#include <stdio.h> ], [ int (*X)() = fclose ], [AC_DEFINE(HAVE_FCLOSE_D, 1)])
+
+AC_MSG_TRY_COMPILE(for optarg declaration, ftp_cv_HAVE_OPTARG_D, [
+#include <stdlib.h>
+#include <unistd.h> ], [ char *X = optarg ], [AC_DEFINE(HAVE_OPTARG_D, 1)])
+
+AC_MSG_TRY_COMPILE(for optind declaration, ftp_cv_HAVE_OPTIND_D, [
+#include <stdlib.h>
+#include <unistd.h> ], [ int X = optind ], [AC_DEFINE(HAVE_OPTIND_D, 1)])
+
+AC_MSG_TRY_LINK(for optreset, ftp_cv_HAVE_OPTRESET, [
+#include <stdlib.h>
+#include <unistd.h> ], [ int X = optreset ], [AC_DEFINE(HAVE_OPTRESET, 1)])
+
+AC_MSG_TRY_COMPILE(for pclose() declaration, ftp_cv_HAVE_PCLOSE_D, [
+#include <stdio.h> ], [ int (*X)() = pclose ], [AC_DEFINE(HAVE_PCLOSE_D, 1)])
+
+if test $ac_cv_func_getusershell = yes; then
+ AC_MSG_TRY_COMPILE(for getusershell() declaration,
+ ftp_cv_HAVE_GETUSERSHELL_D, [
+ #include <unistd.h> ], [ char *(*X)() = getusershell ],
+ [AC_DEFINE(HAVE_GETUSERSHELL_D, 1)])
+fi
+
+
+if test $have_long_long = yes -a $ac_cv_sizeof_off_t -ge 8; then
+
+dnl We assume that if sprintf() supports %lld or %qd,
+dnl then all of *printf() does. If not, disable long long
+dnl support because we don't know how to display it.
+
+ AC_MSG_CHECKING(*printf() support for %lld)
+ can_printf_longlong=no
+ AC_TRY_RUN([
+ #include <stdio.h>
+ int main() {
+ char buf[100];
+ sprintf(buf, "%lld", 4294967300LL);
+ return (strcmp(buf, "4294967300"));
+ }
+ ], [
+ AC_MSG_RESULT(yes)
+ can_printf_longlong=yes
+ ], [
+ AC_MSG_RESULT(no)
+ ], [ : ])
+
+ if test $can_printf_longlong != yes; then
+ AC_MSG_CHECKING(*printf() support for %qd)
+ AC_TRY_RUN([
+ #include <stdio.h>
+ int main() {
+ char buf[100];
+ sprintf(buf, "%qd", 4294967300LL);
+ return (strcmp(buf, "4294967300"));
+ }
+ ], [
+ AC_MSG_RESULT(yes)
+ can_printf_longlong=yes
+ AC_DEFINE(HAVE_PRINTF_QD, 1)
+ ], [
+ AC_MSG_RESULT(no)
+ ], [ : ])
+ fi
+
+ if test $can_printf_longlong = yes; then
+ AC_DEFINE(HAVE_QUAD_SUPPORT, 1)
+ AC_REPLACE_FUNCS(strtoll)
+ fi
+
+fi
+
+
+have_rfc2553_netdb=no
+if test $ac_cv_func_getaddrinfo = yes -a ! -n "$socks"; then
+ AC_MSG_TRY_COMPILE(for AI_NUMERICHOST,
+ ftp_cv_have_ai_numerichost, [
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netdb.h> ],
+ [ int X = AI_NUMERICHOST ], [ have_rfc2553_netdb=yes ])
+fi
+AC_MSG_CHECKING(for working getaddrinfo())
+if test $have_rfc2553_netdb = yes; then
+ AC_DEFINE(HAVE_RFC2553_NETDB, 1)
+ AC_MSG_RESULT(yes)
+else
+ if test $ac_cv_func_getaddrinfo = yes; then
+ LIBOBJS="$LIBOBJS getaddrinfo.o"
+ AC_MSG_RESULT(no - using local version)
+ else
+ AC_MSG_RESULT(using local version)
+ fi
+fi
+
+if test $ac_cv_func_sl_init = yes; then
+ AC_MSG_TRY_COMPILE(if sl_add() returns int, ftp_cv_INT_SL_ADD, [
+ #include <stringlist.h> ], [ int f = sl_add((StringList *)0, "foo") ],
+ [:] , [LIBOBJS="$LIBOBJS sl_init.o"])
+fi
+
+
+dnl Tests for stuff for inbuilt ls
+dnl
+
+if test $opt_builtinls = yes; then
+ AC_REPLACE_FUNCS(fts_open strmode user_from_uid)
+ LSOBJS="cmp.o ls.o print.o util.o"
+else
+ AC_DEFINE(NO_INTERNAL_LS,1)
+fi
+
+
+dnl Build libukem if necessary
+dnl
+
+if test -n "$LIBOBJS"; then
+ INCLUDES="$INCLUDES -I\${srcdir}/../libukem"
+ LDFLAGS="$LDFLAGS -L../libukem"
+ LIBS="$LIBS -lukem"
+ LIBUKEM=libukem.a
+ LIBDEPENDS="$LIBDEPENDS ../libukem/libukem.a"
+fi
+
+
+dnl Create the Makefiles
+dnl
+
+AC_SUBST(INCLUDES)
+AC_SUBST(LIBUKEM)
+AC_SUBST(LIBDEPENDS)
+AC_SUBST(LSOBJS)
+
+AC_OUTPUT(Makefile libukem/Makefile src/Makefile)
diff --git a/contrib/lukemftpd/install-sh b/contrib/lukemftpd/install-sh
new file mode 100755
index 0000000..e9de238
--- /dev/null
+++ b/contrib/lukemftpd/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/contrib/lukemftpd/lukemftpd.h b/contrib/lukemftpd/lukemftpd.h
new file mode 100644
index 0000000..c697701
--- /dev/null
+++ b/contrib/lukemftpd/lukemftpd.h
@@ -0,0 +1,396 @@
+/* $Id: lukemftpd.h,v 1.16 2001/05/09 02:04:53 lukem Exp $ */
+
+#define FTPD_VERSION "lukemftpd 1.1"
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#if HAVE_SYS_SYSMACROS_H
+# include <sys/sysmacros.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#if HAVE_FTP_NAMES
+# include <arpa/ftp.h>
+#else
+# include "arpaftp.h"
+#endif
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <grp.h>
+#include <limits.h>
+#include <locale.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <termios.h>
+#include <unistd.h>
+#include <utmp.h>
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if HAVE_ERR_H
+# include <err.h>
+#endif
+
+#if HAVE_WORKING_GLOB
+# include <glob.h>
+#else
+# include "ftpglob.h"
+#endif
+
+#if HAVE_PATHS_H
+# include <paths.h>
+#endif
+#ifndef _PATH_BSHELL
+#define _PATH_BSHELL "/bin/sh"
+#endif
+#ifndef _PATH_CSHELL
+#define _PATH_CSHELL "/bin/csh"
+#endif
+#ifndef _PATH_SHELLS
+#define _PATH_SHELLS "/etc/shells"
+#endif
+#ifndef _PATH_DEVNULL
+#define _PATH_DEVNULL "/dev/null"
+#endif
+#ifndef _PATH_NOLOGIN
+#define _PATH_NOLOGIN "/etc/nologin"
+#endif
+
+#ifndef FTPD_LOGTYPE
+# ifdef LOG_FTP
+# define FTPD_LOGTYPE LOG_FTP
+# else
+# define FTPD_LOGTYPE LOG_DAEMON
+# endif
+#endif
+
+#ifndef LOG_AUTHPRIV
+# ifdef LOG_AUTH
+# define LOG_AUTHPRIV LOG_AUTH
+# else
+# define LOG_AUTHPRIV LOG_DAEMON
+# endif
+#endif
+
+typedef struct _stringlist {
+ char **sl_str;
+ size_t sl_max;
+ size_t sl_cur;
+} StringList;
+
+StringList *sl_init(void);
+int sl_add(StringList *, char *);
+void sl_free(StringList *, int);
+char *sl_find(StringList *, char *);
+
+#if HAVE_FTS_H
+# include <fts.h>
+#else
+# include "ftpfts.h"
+#endif
+
+#if HAVE_UTIL_H
+# include <util.h>
+#endif
+
+#if HAVE_LIBUTIL_H
+# include <libutil.h>
+#endif
+
+#if ! HAVE_IN_PORT_T
+typedef unsigned short in_port_t;
+#endif
+
+#if ! HAVE_SOCKLEN_T
+typedef unsigned int socklen_t;
+#endif
+
+#if HAVE_AF_INET6 && HAVE_SOCKADDR_IN6
+# define INET6
+#endif
+
+
+#if ! HAVE_RFC2553_NETDB
+
+ /* RFC 2553 */
+#undef EAI_ADDRFAMILY
+#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */
+#undef EAI_AGAIN
+#define EAI_AGAIN 2 /* temporary failure in name resolution */
+#undef EAI_BADFLAGS
+#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
+#undef EAI_FAIL
+#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
+#undef EAI_FAMILY
+#define EAI_FAMILY 5 /* ai_family not supported */
+#undef EAI_MEMORY
+#define EAI_MEMORY 6 /* memory allocation failure */
+#undef EAI_NODATA
+#define EAI_NODATA 7 /* no address associated with hostname */
+#undef EAI_NONAME
+#define EAI_NONAME 8 /* hostname nor servname provided, or not known */
+#undef EAI_SERVICE
+#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
+#undef EAI_SOCKTYPE
+#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
+#undef EAI_SYSTEM
+#define EAI_SYSTEM 11 /* system error returned in errno */
+
+ /* KAME extensions? */
+#undef EAI_BADHINTS
+#define EAI_BADHINTS 12
+#undef EAI_PROTOCOL
+#define EAI_PROTOCOL 13
+#undef EAI_MAX
+#define EAI_MAX 14
+
+ /* RFC 2553 */
+#undef NI_MAXHOST
+#define NI_MAXHOST 1025
+#undef NI_MAXSERV
+#define NI_MAXSERV 32
+
+#undef NI_NOFQDN
+#define NI_NOFQDN 0x00000001
+#undef NI_NUMERICHOST
+#define NI_NUMERICHOST 0x00000002
+#undef NI_NAMEREQD
+#define NI_NAMEREQD 0x00000004
+#undef NI_NUMERICSERV
+#define NI_NUMERICSERV 0x00000008
+#undef NI_DGRAM
+#define NI_DGRAM 0x00000010
+
+ /* RFC 2553 */
+#undef AI_PASSIVE
+#define AI_PASSIVE 0x00000001 /* get address to use bind() */
+#undef AI_CANONNAME
+#define AI_CANONNAME 0x00000002 /* fill ai_canonname */
+
+ /* KAME extensions ? */
+#undef AI_NUMERICHOST
+#define AI_NUMERICHOST 0x00000004 /* prevent name resolution */
+#undef AI_MASK
+#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
+
+ /* RFC 2553 */
+#undef AI_ALL
+#define AI_ALL 0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */
+#undef AI_V4MAPPED_CFG
+#define AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */
+#undef AI_ADDRCONFIG
+#define AI_ADDRCONFIG 0x00000400 /* only if any address is assigned */
+#undef AI_V4MAPPED
+#define AI_V4MAPPED 0x00000800 /* accept IPv4-mapped IPv6 address */
+
+#endif /* ! HAVE_RFC2553_NETDB */
+
+
+#if ! HAVE_RFC2553_NETDB && ! HAVE_ADDRINFO
+
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+
+int getaddrinfo(const char *, const char *,
+ const struct addrinfo *, struct addrinfo **);
+int getnameinfo(const struct sockaddr *, socklen_t, char *,
+ size_t, char *, size_t, int);
+void freeaddrinfo(struct addrinfo *);
+char *gai_strerror(int);
+
+#endif /* ! HAVE_RFC2553_NETDB && ! HAVE_ADDRINFO */
+
+
+#if ! HAVE_D_NAMLEN
+# define DIRENT_MISSING_D_NAMLEN
+#endif
+
+#if ! HAVE_CRYPT_D
+char *crypt(const char *, const char *);
+#endif
+
+#if ! HAVE_FCLOSE_D
+int fclose(FILE *);
+#endif
+
+#if ! HAVE_OPTARG_D
+extern char *optarg;
+#endif
+
+#if ! HAVE_OPTIND_D
+extern int optind;
+#endif
+
+#if ! HAVE_PCLOSE_D
+int pclose(FILE *);
+#endif
+
+#if ! HAVE_ERR
+void err(int, const char *, ...);
+void errx(int, const char *, ...);
+void warn(const char *, ...);
+void warnx(const char *, ...);
+#endif
+
+#if ! HAVE_FGETLN
+char *fgetln(FILE *, size_t *);
+#endif
+
+#if ! HAVE_FPARSELN
+# define FPARSELN_UNESCESC 0x01
+# define FPARSELN_UNESCCONT 0x02
+# define FPARSELN_UNESCCOMM 0x04
+# define FPARSELN_UNESCREST 0x08
+# define FPARSELN_UNESCALL 0x0f
+char *fparseln(FILE *, size_t *, size_t *, const char[3], int);
+#endif
+
+#if ! HAVE_GETUSERSHELL || ! HAVE_GETUSERSHELL_D
+char *getusershell(void);
+void setusershell(void);
+void endusershell(void);
+#endif
+
+#if ! HAVE_INET_NTOP
+const char *inet_ntop(int, const void *, char *, size_t);
+#endif
+
+#if ! HAVE_INET_PTON
+int inet_pton(int, const char *, void *);
+#endif
+
+#if ! HAVE_MKSTEMP
+int mkstemp(const char *);
+#endif
+
+#if ! HAVE_SNPRINTF
+int snprintf(char *, size_t, const char *, ...);
+#endif
+
+#if ! HAVE_STRDUP
+char *strdup(const char *);
+#endif
+
+#if ! HAVE_STRERROR
+char *strerror(int);
+#endif
+
+#if HAVE_QUAD_SUPPORT
+# if ! HAVE_STRTOLL && HAVE_LONG_LONG
+long long strtoll(const char *, char **, int);
+# if ! defined(QUAD_MIN)
+# define QUAD_MIN (-0x7fffffffffffffffL-1)
+# endif
+# if ! defined(QUAD_MAX)
+# define QUAD_MAX (0x7fffffffffffffffL)
+# endif
+# endif
+#else /* ! HAVE_QUAD_SUPPORT */
+# define NO_LONG_LONG 1
+#endif /* ! HAVE_QUAD_SUPPORT */
+
+#if ! HAVE_STRLCAT
+size_t strlcat(char *, const char *, size_t);
+#endif
+
+#if ! HAVE_STRLCPY
+size_t strlcpy(char *, const char *, size_t);
+#endif
+
+#if ! HAVE_STRMODE
+void strmode(mode_t, char *);
+#endif
+
+#if ! HAVE_STRSEP
+char *strsep(char **, const char *);
+#endif
+
+#if ! HAVE_USER_FROM_UID
+const char *user_from_uid(uid_t, int);
+const char *group_from_gid(gid_t, int);
+#endif
+
+#if ! HAVE_VSYSLOG
+void vsyslog(int level, const char *, va_list);
+#endif
+
+
+#if ! defined(MIN)
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#if ! defined(MAX)
+# define MAX(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+#if ! defined(timersub)
+# define timersub(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif
+
+#if ! defined(S_ISLNK)
+# define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
+#endif
+
+#define DAYSPERNYEAR 365
+#define SECSPERDAY 86400
+#define TM_YEAR_BASE 1900
diff --git a/contrib/lukemftpd/src/Makefile.in b/contrib/lukemftpd/src/Makefile.in
new file mode 100644
index 0000000..e4fe6c6
--- /dev/null
+++ b/contrib/lukemftpd/src/Makefile.in
@@ -0,0 +1,61 @@
+# $Id: Makefile.in,v 1.5 2001/03/29 05:29:07 lukem Exp $
+#
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+SHELL = /bin/sh
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+mandir = @mandir@
+sbindir = @sbindir@
+
+mandircat5 = ${mandir}/cat5
+mandircat8 = ${mandir}/cat8
+
+CC = @CC@
+CFLAGS = -I${srcdir} -I${srcdir}/.. -I. -I.. @INCLUDES@ @CFLAGS@
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+
+INSTALL = @INSTALL@
+
+PROG = ftpd
+OBJS = cmds.o conf.o ftpd.o ftpcmd.o popen.o @LSOBJS@
+# removed: logutmp.o logwtmp.o
+
+all: ${PROG}
+
+cmp.o: ${srcdir}/../ls/cmp.c
+ ${CC} ${CFLAGS} -c -o cmp.o ${srcdir}/../ls/cmp.c
+
+ls.o: ${srcdir}/../ls/ls.c
+ ${CC} ${CFLAGS} -c -o ls.o ${srcdir}/../ls/ls.c
+
+print.o: ${srcdir}/../ls/print.c
+ ${CC} ${CFLAGS} -c -o print.o ${srcdir}/../ls/print.c
+
+stat_flags.o: ${srcdir}/../ls/stat_flags.c
+ ${CC} ${CFLAGS} -c -o stat_flags.o ${srcdir}/../ls/stat_flags.c
+
+util.o: ${srcdir}/../ls/util.c
+ ${CC} ${CFLAGS} -c -o util.o ${srcdir}/../ls/util.c
+
+install: all
+ -mkdir -p ${sbindir}
+ ${INSTALL} -m 555 ${PROG} ${sbindir}
+ -mkdir -p ${mandircat5}
+ ${INSTALL} -m 444 ${srcdir}/ftpd.conf.cat5 ${mandircat5}/ftpd.conf.5
+ ${INSTALL} -m 444 ${srcdir}/ftpusers.cat5 ${mandircat5}/ftpusers.5
+ -mkdir -p ${mandircat8}
+ ${INSTALL} -m 444 ${srcdir}/${PROG}.cat8 ${mandircat8}/${PROG}.8
+
+${PROG}: ${OBJS} @LIBDEPENDS@
+ ${CC} ${CFLAGS} ${LDFLAGS} -o ${PROG} ${OBJS} ${LIBS}
+
+clean:
+ rm -f core ${PROG} ${OBJS}
+
+distclean: clean
+ rm -f Makefile
diff --git a/contrib/lukemftpd/src/arpaftp.h b/contrib/lukemftpd/src/arpaftp.h
new file mode 100644
index 0000000..52be7c1
--- /dev/null
+++ b/contrib/lukemftpd/src/arpaftp.h
@@ -0,0 +1,111 @@
+/* $NetBSD: ftp.h,v 1.5 1998/02/10 00:32:50 perry Exp $ */
+
+/*
+ * Copyright (c) 1983, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ftp.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _ARPA_FTP_H_
+#define _ARPA_FTP_H_
+
+/* Definitions for FTP; see RFC-765. */
+
+/*
+ * Reply codes.
+ */
+#define PRELIM 1 /* positive preliminary */
+#define COMPLETE 2 /* positive completion */
+#define CONTINUE 3 /* positive intermediate */
+#define TRANSIENT 4 /* transient negative completion */
+#define ERROR 5 /* permanent negative completion */
+
+/*
+ * Type codes
+ */
+#define TYPE_A 1 /* ASCII */
+#define TYPE_E 2 /* EBCDIC */
+#define TYPE_I 3 /* image */
+#define TYPE_L 4 /* local byte size */
+
+#ifdef FTP_NAMES
+char *typenames[] = {"0", "ASCII", "EBCDIC", "Image", "Local" };
+#endif
+
+/*
+ * Form codes
+ */
+#define FORM_N 1 /* non-print */
+#define FORM_T 2 /* telnet format effectors */
+#define FORM_C 3 /* carriage control (ASA) */
+#ifdef FTP_NAMES
+char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" };
+#endif
+
+/*
+ * Structure codes
+ */
+#define STRU_F 1 /* file (no record structure) */
+#define STRU_R 2 /* record structure */
+#define STRU_P 3 /* page structure */
+#ifdef FTP_NAMES
+char *strunames[] = {"0", "File", "Record", "Page" };
+#endif
+
+/*
+ * Mode types
+ */
+#define MODE_S 1 /* stream */
+#define MODE_B 2 /* block */
+#define MODE_C 3 /* compressed */
+#ifdef FTP_NAMES
+char *modenames[] = {"0", "Stream", "Block", "Compressed" };
+#endif
+
+/*
+ * Record Tokens
+ */
+#define REC_ESC '\377' /* Record-mode Escape */
+#define REC_EOR '\001' /* Record-mode End-of-Record */
+#define REC_EOF '\002' /* Record-mode End-of-File */
+
+/*
+ * Block Header
+ */
+#define BLK_EOR 0x80 /* Block is End-of-Record */
+#define BLK_EOF 0x40 /* Block is End-of-File */
+#define BLK_ERRORS 0x20 /* Block is suspected of containing errors */
+#define BLK_RESTART 0x10 /* Block is Restart Marker */
+
+#define BLK_BYTECOUNT 2 /* Bytes in this block */
+
+#endif /* _ARPA_FTP_H_ */
diff --git a/contrib/lukemftpd/src/cmds.c b/contrib/lukemftpd/src/cmds.c
new file mode 100644
index 0000000..51efbb8
--- /dev/null
+++ b/contrib/lukemftpd/src/cmds.c
@@ -0,0 +1,791 @@
+/* $NetBSD: cmds.c,v 1.13 2001/04/25 01:46:25 lukem Exp $ */
+
+/*
+ * Copyright (c) 1999-2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (C) 1997 and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "lukemftpd.h"
+
+#include "extern.h"
+
+typedef struct {
+ const char *path; /* full pathname */
+ const char *display; /* name to display */
+ struct stat *stat; /* stat of path */
+ struct stat *pdirstat; /* stat of path's parent dir */
+ int iscurdir; /* nonzero if name is the current dir */
+} factelem;
+
+static void ack(const char *);
+static void base64_encode(const char *, size_t, char *, int);
+static void fact_type(const char *, FILE *, factelem *);
+static void fact_size(const char *, FILE *, factelem *);
+static void fact_modify(const char *, FILE *, factelem *);
+static void fact_perm(const char *, FILE *, factelem *);
+static void fact_unique(const char *, FILE *, factelem *);
+static int matchgroup(gid_t);
+static void mlsname(FILE *, factelem *);
+static void replydirname(const char *, const char *);
+
+struct ftpfact {
+ const char *name; /* name of fact */
+ int enabled; /* if fact is enabled */
+ void (*display)(const char *, FILE *, factelem *);
+ /* function to display fact */
+};
+
+struct ftpfact facttab[] = {
+ { "Type", 1, fact_type },
+#define FACT_TYPE 0
+ { "Size", 1, fact_size },
+ { "Modify", 1, fact_modify },
+ { "Perm", 1, fact_perm },
+ { "Unique", 1, fact_unique },
+ /* "Create" */
+ /* "Lang" */
+ /* "Media-Type" */
+ /* "CharSet" */
+};
+
+#define FACTTABSIZE (sizeof(facttab) / sizeof(struct ftpfact))
+
+
+void
+cwd(const char *path)
+{
+
+ if (chdir(path) < 0)
+ perror_reply(550, path);
+ else {
+ show_chdir_messages(250);
+ ack("CWD");
+ }
+}
+
+void
+delete(const char *name)
+{
+ char *p = NULL;
+
+ if (remove(name) < 0) {
+ p = strerror(errno);
+ perror_reply(550, name);
+ } else
+ ack("DELE");
+ logxfer("delete", -1, name, NULL, NULL, p);
+}
+
+void
+feat(void)
+{
+ int i;
+
+ reply(-211, "Features supported");
+ cprintf(stdout, " MDTM\r\n");
+ cprintf(stdout, " MLST ");
+ for (i = 0; i < FACTTABSIZE; i++)
+ cprintf(stdout, "%s%s;", facttab[i].name,
+ facttab[i].enabled ? "*" : "");
+ cprintf(stdout, "\r\n");
+ cprintf(stdout, " REST STREAM\r\n");
+ cprintf(stdout, " SIZE\r\n");
+ cprintf(stdout, " TVFS\r\n");
+ reply(211, "End");
+}
+
+void
+makedir(const char *name)
+{
+ char *p = NULL;
+
+ if (mkdir(name, 0777) < 0) {
+ p = strerror(errno);
+ perror_reply(550, name);
+ } else
+ replydirname(name, "directory created.");
+ logxfer("mkdir", -1, name, NULL, NULL, p);
+}
+
+void
+mlsd(const char *path)
+{
+ struct dirent *dp;
+ struct stat sb, pdirstat;
+ factelem f;
+ FILE *dout;
+ DIR *dirp;
+ char name[MAXPATHLEN];
+ int hastypefact;
+
+ hastypefact = facttab[FACT_TYPE].enabled;
+ if (path == NULL)
+ path = ".";
+ if (stat(path, &pdirstat) == -1) {
+ mlsdperror:
+ perror_reply(550, path);
+ return;
+ }
+ if (! S_ISDIR(pdirstat.st_mode)) {
+ errno = ENOTDIR;
+ perror_reply(501, path);
+ return;
+ }
+ dout = dataconn("MLSD", (off_t)-1, "w");
+ if (dout == NULL)
+ return;
+
+ if ((dirp = opendir(path)) == NULL)
+ goto mlsdperror;
+ f.stat = &sb;
+ while ((dp = readdir(dirp)) != NULL) {
+ snprintf(name, sizeof(name), "%s/%s", path, dp->d_name);
+ if (ISDOTDIR(dp->d_name)) { /* special case curdir: */
+ if (! hastypefact)
+ continue;
+ f.pdirstat = NULL; /* require stat of parent */
+ f.display = path; /* set name to real name */
+ f.iscurdir = 1; /* flag name is curdir */
+ } else {
+ if (ISDOTDOTDIR(dp->d_name)) {
+ if (! hastypefact)
+ continue;
+ f.pdirstat = NULL;
+ } else
+ f.pdirstat = &pdirstat; /* cache parent stat */
+ f.display = dp->d_name;
+ f.iscurdir = 0;
+ }
+ if (stat(name, &sb) == -1)
+ continue;
+ f.path = name;
+ mlsname(dout, &f);
+ }
+ (void)closedir(dirp);
+
+ if (ferror(dout) != 0)
+ perror_reply(550, "Data connection");
+ else
+ reply(226, "MLSD complete.");
+ closedataconn(dout);
+ total_xfers_out++;
+ total_xfers++;
+}
+
+void
+mlst(const char *path)
+{
+ struct stat sb;
+ factelem f;
+
+ if (path == NULL)
+ path = ".";
+ if (stat(path, &sb) == -1) {
+ perror_reply(550, path);
+ return;
+ }
+ reply(-250, "MLST %s", path);
+ f.path = path;
+ f.display = path;
+ f.stat = &sb;
+ f.pdirstat = NULL;
+ f.iscurdir = 0;
+ CPUTC(' ', stdout);
+ mlsname(stdout, &f);
+ reply(250, "End");
+}
+
+
+void
+opts(const char *command)
+{
+ struct tab *c;
+ char *ep;
+
+ if ((ep = strchr(command, ' ')) != NULL)
+ *ep++ = '\0';
+ c = lookup(cmdtab, command);
+ if (c == NULL) {
+ reply(502, "Unknown command %s.", command);
+ return;
+ }
+ if (! CMD_IMPLEMENTED(c)) {
+ reply(501, "%s command not implemented.", c->name);
+ return;
+ }
+ if (! CMD_HAS_OPTIONS(c)) {
+ reply(501, "%s command does not support persistent options.",
+ c->name);
+ return;
+ }
+
+ /* special case: MLST */
+ if (strcasecmp(command, "MLST") == 0) {
+ int enabled[FACTTABSIZE];
+ int i, onedone;
+ size_t len;
+ char *p;
+
+ for (i = 0; i < sizeof(enabled) / sizeof(int); i++)
+ enabled[i] = 0;
+ if (ep == NULL || *ep == '\0')
+ goto displaymlstopts;
+
+ /* don't like spaces, and need trailing ; */
+ len = strlen(ep);
+ if (strchr(ep, ' ') != NULL || ep[len - 1] != ';') {
+ badmlstopt:
+ reply(501, "Invalid MLST options");
+ return;
+ }
+ ep[len - 1] = '\0';
+ while ((p = strsep(&ep, ";")) != NULL) {
+ if (*p == '\0')
+ goto badmlstopt;
+ for (i = 0; i < FACTTABSIZE; i++)
+ if (strcasecmp(p, facttab[i].name) == 0) {
+ enabled[i] = 1;
+ break;
+ }
+ }
+
+ displaymlstopts:
+ for (i = 0; i < FACTTABSIZE; i++)
+ facttab[i].enabled = enabled[i];
+ cprintf(stdout, "200 MLST OPTS");
+ for (i = onedone = 0; i < FACTTABSIZE; i++) {
+ if (facttab[i].enabled) {
+ cprintf(stdout, "%s%s;", onedone ? "" : " ",
+ facttab[i].name);
+ onedone++;
+ }
+ }
+ cprintf(stdout, "\r\n");
+ fflush(stdout);
+ return;
+ }
+
+ /* default cases */
+ if (ep != NULL && *ep != '\0')
+ REASSIGN(c->options, xstrdup(ep));
+ if (c->options != NULL)
+ reply(200, "Options for %s are '%s'.", c->name,
+ c->options);
+ else
+ reply(200, "No options defined for %s.", c->name);
+}
+
+void
+pwd(void)
+{
+ char path[MAXPATHLEN];
+
+ if (getcwd(path, sizeof(path) - 1) == NULL)
+ reply(550, "Can't get the current directory: %s.",
+ strerror(errno));
+ else
+ replydirname(path, "is the current directory.");
+}
+
+void
+removedir(const char *name)
+{
+ char *p = NULL;
+
+ if (rmdir(name) < 0) {
+ p = strerror(errno);
+ perror_reply(550, name);
+ } else
+ ack("RMD");
+ logxfer("rmdir", -1, name, NULL, NULL, p);
+}
+
+char *
+renamefrom(const char *name)
+{
+ struct stat st;
+
+ if (stat(name, &st) < 0) {
+ perror_reply(550, name);
+ return (NULL);
+ }
+ reply(350, "File exists, ready for destination name");
+ return (xstrdup(name));
+}
+
+void
+renamecmd(const char *from, const char *to)
+{
+ char *p = NULL;
+
+ if (rename(from, to) < 0) {
+ p = strerror(errno);
+ perror_reply(550, "rename");
+ } else
+ ack("RNTO");
+ logxfer("rename", -1, from, to, NULL, p);
+}
+
+void
+sizecmd(const char *filename)
+{
+ switch (type) {
+ case TYPE_L:
+ case TYPE_I:
+ {
+ struct stat stbuf;
+ if (stat(filename, &stbuf) < 0 || !S_ISREG(stbuf.st_mode))
+ reply(550, "%s: not a plain file.", filename);
+ else
+ reply(213, ULLF, (ULLT)stbuf.st_size);
+ break;
+ }
+ case TYPE_A:
+ {
+ FILE *fin;
+ int c;
+ off_t count;
+ struct stat stbuf;
+ fin = fopen(filename, "r");
+ if (fin == NULL) {
+ perror_reply(550, filename);
+ return;
+ }
+ if (fstat(fileno(fin), &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) {
+ reply(550, "%s: not a plain file.", filename);
+ (void) fclose(fin);
+ return;
+ }
+
+ count = 0;
+ while((c=getc(fin)) != EOF) {
+ if (c == '\n') /* will get expanded to \r\n */
+ count++;
+ count++;
+ }
+ (void) fclose(fin);
+
+ reply(213, LLF, (LLT)count);
+ break;
+ }
+ default:
+ reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
+ }
+}
+
+void
+statfilecmd(const char *filename)
+{
+ FILE *fin;
+ int c;
+ 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? */
+ while ((c = getc(fin)) != EOF) {
+ if (c == '\n') {
+ if (ferror(stdout)){
+ perror_reply(421, "control connection");
+ (void) ftpd_pclose(fin);
+ dologout(1);
+ /* NOTREACHED */
+ }
+ if (ferror(fin)) {
+ perror_reply(551, filename);
+ (void) ftpd_pclose(fin);
+ return;
+ }
+ CPUTC('\r', stdout);
+ }
+ CPUTC(c, stdout);
+ }
+ (void) ftpd_pclose(fin);
+ reply(211, "End of Status");
+}
+
+/* -- */
+
+static void
+ack(const char *s)
+{
+
+ reply(250, "%s command successful.", s);
+}
+
+/*
+ * Encode len bytes starting at clear using base64 encoding into encoded,
+ * which should be at least ((len + 2) * 4 / 3 + 1) in size.
+ * If nulterm is non-zero, terminate with \0 otherwise pad to 3 byte boundary
+ * with `='.
+ */
+static void
+base64_encode(const char *clear, size_t len, char *encoded, int nulterm)
+{
+ static const char base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ const char *c;
+ char *e, termchar;
+ int i;
+
+ /* determine whether to pad with '=' or NUL terminate */
+ termchar = nulterm ? '\0' : '=';
+ c = clear;
+ e = encoded;
+ /* convert all but last 2 bytes */
+ for (i = len; i > 2; i -= 3, c += 3) {
+ *e++ = base64[(c[0] >> 2) & 0x3f];
+ *e++ = base64[((c[0] << 4) & 0x30) | ((c[1] >> 4) & 0x0f)];
+ *e++ = base64[((c[1] << 2) & 0x3c) | ((c[2] >> 6) & 0x03)];
+ *e++ = base64[(c[2]) & 0x3f];
+ }
+ /* handle slop at end */
+ if (i > 0) {
+ *e++ = base64[(c[0] >> 2) & 0x3f];
+ *e++ = base64[((c[0] << 4) & 0x30) |
+ (i > 1 ? ((c[1] >> 4) & 0x0f) : 0)];
+ *e++ = (i > 1) ? base64[(c[1] << 2) & 0x3c] : termchar;
+ *e++ = termchar;
+ }
+ *e = '\0';
+}
+
+static void
+fact_modify(const char *fact, FILE *fd, factelem *fe)
+{
+ struct tm *t;
+
+ t = gmtime(&(fe->stat->st_mtime));
+ cprintf(fd, "%s=%04d%02d%02d%02d%02d%02d;", fact,
+ TM_YEAR_BASE + t->tm_year,
+ t->tm_mon+1, t->tm_mday,
+ t->tm_hour, t->tm_min, t->tm_sec);
+}
+
+static void
+fact_perm(const char *fact, FILE *fd, factelem *fe)
+{
+ int rok, wok, xok, pdirwok;
+ struct stat *pdir;
+
+ if (fe->stat->st_uid == geteuid()) {
+ rok = ((fe->stat->st_mode & S_IRUSR) != 0);
+ wok = ((fe->stat->st_mode & S_IWUSR) != 0);
+ xok = ((fe->stat->st_mode & S_IXUSR) != 0);
+ } else if (matchgroup(fe->stat->st_gid)) {
+ rok = ((fe->stat->st_mode & S_IRGRP) != 0);
+ wok = ((fe->stat->st_mode & S_IWGRP) != 0);
+ xok = ((fe->stat->st_mode & S_IXGRP) != 0);
+ } else {
+ rok = ((fe->stat->st_mode & S_IROTH) != 0);
+ wok = ((fe->stat->st_mode & S_IWOTH) != 0);
+ xok = ((fe->stat->st_mode & S_IXOTH) != 0);
+ }
+
+ cprintf(fd, "%s=", fact);
+
+ /*
+ * if parent info not provided, look it up, but
+ * only if the current class has modify rights,
+ * since we only need this info in such a case.
+ */
+ pdir = fe->pdirstat;
+ if (pdir == NULL && CURCLASS_FLAGS_ISSET(modify)) {
+ size_t len;
+ char realdir[MAXPATHLEN], *p;
+ struct stat dir;
+
+ len = strlcpy(realdir, fe->path, sizeof(realdir));
+ if (len < sizeof(realdir) - 4) {
+ if (S_ISDIR(fe->stat->st_mode))
+ strlcat(realdir, "/..", sizeof(realdir));
+ else {
+ /* if has a /, move back to it */
+ /* otherwise use '..' */
+ if ((p = strrchr(realdir, '/')) != NULL) {
+ if (p == realdir)
+ p++;
+ *p = '\0';
+ } else
+ strlcpy(realdir, "..", sizeof(realdir));
+ }
+ if (stat(realdir, &dir) == 0)
+ pdir = &dir;
+ }
+ }
+ pdirwok = 0;
+ if (pdir != NULL) {
+ if (pdir->st_uid == geteuid())
+ pdirwok = ((pdir->st_mode & S_IWUSR) != 0);
+ else if (matchgroup(pdir->st_gid))
+ pdirwok = ((pdir->st_mode & S_IWGRP) != 0);
+ else
+ pdirwok = ((pdir->st_mode & S_IWOTH) != 0);
+ }
+
+ /* 'a': can APPE to file */
+ if (wok && CURCLASS_FLAGS_ISSET(upload) && S_ISREG(fe->stat->st_mode))
+ CPUTC('a', fd);
+
+ /* 'c': can create or append to files in directory */
+ if (wok && CURCLASS_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
+ CPUTC('c', fd);
+
+ /* 'd': can delete file or directory */
+ if (pdirwok && CURCLASS_FLAGS_ISSET(modify)) {
+ int candel;
+
+ candel = 1;
+ if (S_ISDIR(fe->stat->st_mode)) {
+ DIR *dirp;
+ struct dirent *dp;
+
+ if ((dirp = opendir(fe->display)) == NULL)
+ candel = 0;
+ else {
+ while ((dp = readdir(dirp)) != NULL) {
+ if (ISDOTDIR(dp->d_name) ||
+ ISDOTDOTDIR(dp->d_name))
+ continue;
+ candel = 0;
+ break;
+ }
+ closedir(dirp);
+ }
+ }
+ if (candel)
+ CPUTC('d', fd);
+ }
+
+ /* 'e': can enter directory */
+ if (xok && S_ISDIR(fe->stat->st_mode))
+ CPUTC('e', fd);
+
+ /* 'f': can rename file or directory */
+ if (pdirwok && CURCLASS_FLAGS_ISSET(modify))
+ CPUTC('f', fd);
+
+ /* 'l': can list directory */
+ if (rok && xok && S_ISDIR(fe->stat->st_mode))
+ CPUTC('l', fd);
+
+ /* 'm': can create directory */
+ if (wok && CURCLASS_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
+ CPUTC('m', fd);
+
+ /* 'p': can remove files in directory */
+ if (wok && CURCLASS_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
+ CPUTC('p', fd);
+
+ /* 'r': can RETR file */
+ if (rok && S_ISREG(fe->stat->st_mode))
+ CPUTC('r', fd);
+
+ /* 'w': can STOR file */
+ if (wok && CURCLASS_FLAGS_ISSET(upload) && S_ISREG(fe->stat->st_mode))
+ CPUTC('w', fd);
+
+ CPUTC(';', fd);
+}
+
+static void
+fact_size(const char *fact, FILE *fd, factelem *fe)
+{
+
+ if (S_ISREG(fe->stat->st_mode))
+ cprintf(fd, "%s=" LLF ";", fact, (LLT)fe->stat->st_size);
+}
+
+static void
+fact_type(const char *fact, FILE *fd, factelem *fe)
+{
+
+ cprintf(fd, "%s=", fact);
+ switch (fe->stat->st_mode & S_IFMT) {
+ case S_IFDIR:
+ if (fe->iscurdir || ISDOTDIR(fe->display))
+ cprintf(fd, "cdir");
+ else if (ISDOTDOTDIR(fe->display))
+ cprintf(fd, "pdir");
+ else
+ cprintf(fd, "dir");
+ break;
+ case S_IFREG:
+ cprintf(fd, "file");
+ break;
+ case S_IFIFO:
+ cprintf(fd, "OS.unix=fifo");
+ break;
+ case S_IFLNK: /* XXX: probably a NO-OP with stat() */
+ cprintf(fd, "OS.unix=slink");
+ break;
+ case S_IFSOCK:
+ cprintf(fd, "OS.unix=socket");
+ break;
+ case S_IFBLK:
+ case S_IFCHR:
+ cprintf(fd, "OS.unix=%s-%d/%d",
+ S_ISBLK(fe->stat->st_mode) ? "blk" : "chr",
+ major(fe->stat->st_rdev), minor(fe->stat->st_rdev));
+ break;
+ default:
+ cprintf(fd, "OS.unix=UNKNOWN(0%o)", fe->stat->st_mode & S_IFMT);
+ break;
+ }
+ CPUTC(';', fd);
+}
+
+static void
+fact_unique(const char *fact, FILE *fd, factelem *fe)
+{
+ char obuf[(sizeof(dev_t) + sizeof(ino_t) + 2) * 4 / 3 + 2];
+ char tbuf[sizeof(dev_t) + sizeof(ino_t)];
+
+ memcpy(tbuf,
+ (char *)&(fe->stat->st_dev), sizeof(dev_t));
+ memcpy(tbuf + sizeof(dev_t),
+ (char *)&(fe->stat->st_ino), sizeof(ino_t));
+ base64_encode(tbuf, sizeof(dev_t) + sizeof(ino_t), obuf, 1);
+ cprintf(fd, "%s=%s;", fact, obuf);
+}
+
+static int
+matchgroup(gid_t gid)
+{
+ int i;
+
+ for (i = 0; i < gidcount; i++)
+ if (gid == gidlist[i])
+ return(1);
+ return (0);
+}
+
+static void
+mlsname(FILE *fp, factelem *fe)
+{
+ int i;
+
+ for (i = 0; i < FACTTABSIZE; i++) {
+ if (facttab[i].enabled)
+ (facttab[i].display)(facttab[i].name, fp, fe);
+ }
+ cprintf(fp, " %s\r\n", fe->display);
+}
+
+static void
+replydirname(const char *name, const char *message)
+{
+ char *p, *ep;
+ char npath[MAXPATHLEN * 2];
+
+ p = npath;
+ ep = &npath[sizeof(npath) - 1];
+ while (*name) {
+ if (*name == '"') {
+ if (ep - p < 2)
+ break;
+ *p++ = *name++;
+ *p++ = '"';
+ } else {
+ if (ep - p < 1)
+ break;
+ *p++ = *name++;
+ }
+ }
+ *p = '\0';
+ reply(257, "\"%s\" %s", npath, message);
+}
diff --git a/contrib/lukemftpd/src/conf.c b/contrib/lukemftpd/src/conf.c
new file mode 100644
index 0000000..19b9283
--- /dev/null
+++ b/contrib/lukemftpd/src/conf.c
@@ -0,0 +1,1007 @@
+/* $NetBSD: conf.c,v 1.41 2001/04/25 01:46:25 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Simon Burge and Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "lukemftpd.h"
+
+#include "extern.h"
+#include "pathnames.h"
+
+static char *strend(const char *, char *);
+static int filetypematch(char *, int);
+
+
+ /* class defaults */
+#define DEFAULT_LIMIT -1 /* unlimited connections */
+#define DEFAULT_MAXFILESIZE -1 /* unlimited file size */
+#define DEFAULT_MAXTIMEOUT 7200 /* 2 hours */
+#define DEFAULT_TIMEOUT 900 /* 15 minutes */
+#define DEFAULT_UMASK 027 /* 15 minutes */
+
+/*
+ * Initialise curclass to an `empty' state
+ */
+void
+init_curclass(void)
+{
+ struct ftpconv *conv, *cnext;
+
+ for (conv = curclass.conversions; conv != NULL; conv = cnext) {
+ REASSIGN(conv->suffix, NULL);
+ REASSIGN(conv->types, NULL);
+ REASSIGN(conv->disable, NULL);
+ REASSIGN(conv->command, NULL);
+ cnext = conv->next;
+ free(conv);
+ }
+
+ memset((char *)&curclass.advertise, 0, sizeof(curclass.advertise));
+ curclass.advertise.su_len = 0; /* `not used' */
+ REASSIGN(curclass.chroot, NULL);
+ REASSIGN(curclass.classname, NULL);
+ curclass.conversions = NULL;
+ REASSIGN(curclass.display, NULL);
+ REASSIGN(curclass.homedir, NULL);
+ curclass.limit = DEFAULT_LIMIT;
+ REASSIGN(curclass.limitfile, NULL);
+ curclass.maxfilesize = DEFAULT_MAXFILESIZE;
+ curclass.maxrateget = 0;
+ curclass.maxrateput = 0;
+ curclass.maxtimeout = DEFAULT_MAXTIMEOUT;
+ REASSIGN(curclass.motd, xstrdup(_PATH_FTPLOGINMESG));
+ REASSIGN(curclass.notify, NULL);
+ curclass.portmin = 0;
+ curclass.portmax = 0;
+ curclass.rateget = 0;
+ curclass.rateput = 0;
+ curclass.timeout = DEFAULT_TIMEOUT;
+ /* curclass.type is set elsewhere */
+ curclass.umask = DEFAULT_UMASK;
+
+ CURCLASS_FLAGS_SET(checkportcmd);
+ CURCLASS_FLAGS_SET(modify);
+ CURCLASS_FLAGS_SET(passive);
+ CURCLASS_FLAGS_CLR(sanenames);
+ CURCLASS_FLAGS_SET(upload);
+}
+
+/*
+ * Parse the configuration file, looking for the named class, and
+ * define curclass to contain the appropriate settings.
+ */
+void
+parse_conf(const char *findclass)
+{
+ FILE *f;
+ char *buf, *p;
+ size_t len;
+ LLT llval;
+ int none, match;
+ char *endp;
+ char *class, *word, *arg, *template;
+ const char *infile;
+ size_t line;
+ unsigned int timeout;
+ struct ftpconv *conv, *cnext;
+
+ init_curclass();
+ REASSIGN(curclass.classname, xstrdup(findclass));
+ /* set more guest defaults */
+ if (strcasecmp(findclass, "guest") == 0) {
+ CURCLASS_FLAGS_CLR(modify);
+ curclass.umask = 0707;
+ }
+
+ infile = conffilename(_PATH_FTPDCONF);
+ if ((f = fopen(infile, "r")) == NULL)
+ return;
+
+ line = 0;
+ template = NULL;
+ for (;
+ (buf = fparseln(f, &len, &line, NULL, FPARSELN_UNESCCOMM |
+ FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL;
+ free(buf)) {
+ none = match = 0;
+ p = buf;
+ if (len < 1)
+ continue;
+ if (p[len - 1] == '\n')
+ p[--len] = '\0';
+ if (EMPTYSTR(p))
+ continue;
+
+ NEXTWORD(p, word);
+ NEXTWORD(p, class);
+ NEXTWORD(p, arg);
+ if (EMPTYSTR(word) || EMPTYSTR(class))
+ continue;
+ if (strcasecmp(class, "none") == 0)
+ none = 1;
+ if (! (strcasecmp(class, findclass) == 0 ||
+ (template != NULL && strcasecmp(class, template) == 0) ||
+ none ||
+ 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); \
+ } while (0)
+
+#define CONF_STRING(x) \
+ do { \
+ if (none || EMPTYSTR(arg)) \
+ arg = NULL; \
+ else \
+ arg = xstrdup(arg); \
+ REASSIGN(curclass.x, arg); \
+ } while (0)
+
+
+ if (0) {
+ /* no-op */
+
+ } else if (strcasecmp(word, "advertise") == 0) {
+ struct addrinfo hints, *res;
+ int error;
+
+ memset((char *)&curclass.advertise, 0,
+ sizeof(curclass.advertise));
+ curclass.advertise.su_len = 0;
+ if (none || EMPTYSTR(arg))
+ continue;
+ res = NULL;
+ memset(&hints, 0, sizeof(hints));
+ /*
+ * only get addresses of the family
+ * that we're listening on
+ */
+ hints.ai_family = ctrl_addr.su_family;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(arg, "0", &hints, &res);
+ if (error) {
+ syslog(LOG_WARNING, "%s line %d: %s",
+ infile, (int)line, gai_strerror(error));
+ advertiseparsefail:
+ if (res)
+ freeaddrinfo(res);
+ continue;
+ }
+ if (res->ai_next) {
+ syslog(LOG_WARNING,
+ "%s line %d: multiple addresses returned for `%s'; please be more specific",
+ infile, (int)line, arg);
+ goto advertiseparsefail;
+ }
+ if (sizeof(curclass.advertise) < res->ai_addrlen || (
+#ifdef INET6
+ res->ai_family != AF_INET6 &&
+#endif
+ res->ai_family != AF_INET)) {
+ syslog(LOG_WARNING,
+ "%s line %d: unsupported protocol %d for `%s'",
+ infile, (int)line, res->ai_family, arg);
+ goto advertiseparsefail;
+ }
+ memcpy(&curclass.advertise, res->ai_addr,
+ res->ai_addrlen);
+ curclass.advertise.su_len = res->ai_addrlen;
+ freeaddrinfo(res);
+
+ } else if (strcasecmp(word, "checkportcmd") == 0) {
+ CONF_FLAG(checkportcmd);
+
+ } else if (strcasecmp(word, "chroot") == 0) {
+ CONF_STRING(chroot);
+
+ } else if (strcasecmp(word, "classtype") == 0) {
+ if (!none && !EMPTYSTR(arg)) {
+ if (strcasecmp(arg, "GUEST") == 0)
+ curclass.type = CLASS_GUEST;
+ else if (strcasecmp(arg, "CHROOT") == 0)
+ curclass.type = CLASS_CHROOT;
+ else if (strcasecmp(arg, "REAL") == 0)
+ curclass.type = CLASS_REAL;
+ else {
+ syslog(LOG_WARNING,
+ "%s line %d: unknown class type `%s'",
+ infile, (int)line, arg);
+ continue;
+ }
+ }
+
+ } else if (strcasecmp(word, "conversion") == 0) {
+ char *suffix, *types, *disable, *convcmd;
+
+ if (EMPTYSTR(arg)) {
+ syslog(LOG_WARNING,
+ "%s line %d: %s requires a suffix",
+ infile, (int)line, word);
+ continue; /* need a suffix */
+ }
+ NEXTWORD(p, types);
+ NEXTWORD(p, disable);
+ convcmd = p;
+ if (convcmd)
+ convcmd += strspn(convcmd, " \t");
+ suffix = xstrdup(arg);
+ if (none || EMPTYSTR(types) ||
+ EMPTYSTR(disable) || EMPTYSTR(convcmd)) {
+ types = NULL;
+ disable = NULL;
+ convcmd = NULL;
+ } else {
+ types = xstrdup(types);
+ disable = xstrdup(disable);
+ convcmd = xstrdup(convcmd);
+ }
+ for (conv = curclass.conversions; conv != NULL;
+ conv = conv->next) {
+ if (strcmp(conv->suffix, suffix) == 0)
+ break;
+ }
+ if (conv == NULL) {
+ conv = (struct ftpconv *)
+ calloc(1, sizeof(struct ftpconv));
+ if (conv == NULL) {
+ syslog(LOG_WARNING, "can't malloc");
+ continue;
+ }
+ conv->next = NULL;
+ for (cnext = curclass.conversions;
+ cnext != NULL; cnext = cnext->next)
+ if (cnext->next == NULL)
+ break;
+ if (cnext != NULL)
+ cnext->next = conv;
+ else
+ curclass.conversions = conv;
+ }
+ REASSIGN(conv->suffix, suffix);
+ REASSIGN(conv->types, types);
+ REASSIGN(conv->disable, disable);
+ REASSIGN(conv->command, convcmd);
+
+ } else if (strcasecmp(word, "display") == 0) {
+ CONF_STRING(display);
+
+ } else if (strcasecmp(word, "homedir") == 0) {
+ 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;
+ 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;
+
+ } 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;
+
+ } else if (strcasecmp(word, "modify") == 0) {
+ CONF_FLAG(modify);
+
+ } else if (strcasecmp(word, "motd") == 0) {
+ CONF_STRING(motd);
+
+ } else if (strcasecmp(word, "notify") == 0) {
+ CONF_STRING(notify);
+
+ } else if (strcasecmp(word, "passive") == 0) {
+ CONF_FLAG(passive);
+
+ } else if (strcasecmp(word, "portrange") == 0) {
+ int minport, maxport;
+ char *min, *max;
+
+ curclass.portmin = 0;
+ curclass.portmax = 0;
+ if (none || EMPTYSTR(arg))
+ continue;
+ min = arg;
+ NEXTWORD(p, max);
+ if (EMPTYSTR(max)) {
+ 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);
+ 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);
+ continue;
+ }
+ if (minport >= maxport) {
+ syslog(LOG_WARNING,
+ "%s line %d: minport %d >= maxport %d",
+ infile, (int)line, minport, maxport);
+ continue;
+ }
+ curclass.portmin = minport;
+ curclass.portmax = maxport;
+
+ } 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;
+
+ } 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;
+
+ } 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;
+
+ } else if (strcasecmp(word, "template") == 0) {
+ if (none)
+ continue;
+ REASSIGN(template, EMPTYSTR(arg) ? NULL : xstrdup(arg));
+
+ } else if (strcasecmp(word, "umask") == 0) {
+ mode_t umask;
+
+ curclass.umask = DEFAULT_UMASK;
+ if (none || EMPTYSTR(arg))
+ continue;
+ umask = (mode_t)strtoul(arg, &endp, 8);
+ if (*endp != 0 || umask > 0777) {
+ syslog(LOG_WARNING,
+ "%s line %d: invalid umask %s",
+ infile, (int)line, arg);
+ continue;
+ }
+ curclass.umask = umask;
+
+ } else if (strcasecmp(word, "upload") == 0) {
+ CONF_FLAG(upload);
+ if (! CURCLASS_FLAGS_ISSET(upload))
+ CURCLASS_FLAGS_CLR(modify);
+
+ } else {
+ syslog(LOG_WARNING,
+ "%s line %d: unknown directive '%s'",
+ infile, (int)line, word);
+ continue;
+ }
+ }
+ REASSIGN(template, NULL);
+ fclose(f);
+}
+
+/*
+ * Show file listed in curclass.display first time in, and list all the
+ * files named in curclass.notify in the current directory.
+ * Send back responses with the prefix `code' + "-".
+ * If code == -1, flush the internal cache of directory names and return.
+ */
+void
+show_chdir_messages(int code)
+{
+ static StringList *slist = NULL;
+
+ struct stat st;
+ struct tm *t;
+ glob_t gl;
+ time_t now, then;
+ int age;
+ char cwd[MAXPATHLEN];
+ char *cp, **rlist;
+
+ if (code == -1) {
+ if (slist != NULL)
+ sl_free(slist, 1);
+ slist = NULL;
+ return;
+ }
+
+ if (quietmessages)
+ return;
+
+ /* Setup list for directory cache */
+ if (slist == NULL)
+ slist = sl_init();
+ if (slist == NULL) {
+ syslog(LOG_WARNING, "can't allocate memory for stringlist");
+ return;
+ }
+
+ /* Check if this directory has already been visited */
+ if (getcwd(cwd, sizeof(cwd) - 1) == NULL) {
+ syslog(LOG_WARNING, "can't getcwd: %s", strerror(errno));
+ return;
+ }
+ if (sl_find(slist, cwd) != NULL)
+ return;
+
+ cp = xstrdup(cwd);
+ if (sl_add(slist, cp) == -1)
+ syslog(LOG_WARNING, "can't add `%s' to stringlist", cp);
+
+ /* First check for a display file */
+ (void)display_file(curclass.display, code);
+
+ /* Now see if there are any notify files */
+ if (EMPTYSTR(curclass.notify))
+ return;
+
+ gl.gl_offs = 0;
+ if (glob(curclass.notify, GLOB_LIMIT, NULL, &gl) != 0
+ || gl.gl_matchc == 0) {
+ globfree(&gl);
+ return;
+ }
+ time(&now);
+ for (rlist = gl.gl_pathv; *rlist != NULL; rlist++) {
+ if (stat(*rlist, &st) != 0)
+ continue;
+ if (!S_ISREG(st.st_mode))
+ continue;
+ then = st.st_mtime;
+ if (code != 0) {
+ reply(-code, "%s", "");
+ code = 0;
+ }
+ reply(-code, "Please read the file %s", *rlist);
+ t = localtime(&now);
+ age = 365 * t->tm_year + t->tm_yday;
+ t = localtime(&then);
+ age -= 365 * t->tm_year + t->tm_yday;
+ reply(-code, " it was last modified on %.24s - %d day%s ago",
+ ctime(&then), age, PLURAL(age));
+ }
+ globfree(&gl);
+}
+
+int
+display_file(const char *file, int code)
+{
+ FILE *f;
+ char *buf, *p, *cwd;
+ size_t len;
+ off_t lastnum;
+ time_t now;
+
+ lastnum = 0;
+ if (quietmessages)
+ return (0);
+
+ if (EMPTYSTR(file))
+ return(0);
+ if ((f = fopen(file, "r")) == NULL)
+ return (0);
+ reply(-code, "%s", "");
+
+ for (;
+ (buf = fparseln(f, &len, NULL, "\0\0\0", 0)) != NULL; free(buf)) {
+ if (len > 0)
+ if (buf[len - 1] == '\n')
+ buf[--len] = '\0';
+ cprintf(stdout, " ");
+
+ for (p = buf; *p; p++) {
+ if (*p == '%') {
+ p++;
+ switch (*p) {
+
+ case 'c':
+ cprintf(stdout, "%s",
+ curclass.classname ?
+ curclass.classname : "<unknown>");
+ break;
+
+ case 'C':
+ if (getcwd(cwd, sizeof(cwd)-1) == NULL){
+ syslog(LOG_WARNING,
+ "can't getcwd: %s",
+ strerror(errno));
+ continue;
+ }
+ cprintf(stdout, "%s", cwd);
+ break;
+
+ case 'E':
+ if (! EMPTYSTR(emailaddr))
+ cprintf(stdout, "%s",
+ emailaddr);
+ break;
+
+ case 'L':
+ cprintf(stdout, "%s", hostname);
+ break;
+
+ case 'M':
+ if (curclass.limit == -1) {
+ cprintf(stdout, "unlimited");
+ lastnum = 0;
+ } else {
+ cprintf(stdout, "%d",
+ curclass.limit);
+ lastnum = curclass.limit;
+ }
+ break;
+
+ case 'N':
+ cprintf(stdout, "%d", connections);
+ lastnum = connections;
+ break;
+
+ case 'R':
+ cprintf(stdout, "%s", remotehost);
+ break;
+
+ case 's':
+ if (lastnum != 1)
+ cprintf(stdout, "s");
+ break;
+
+ case 'S':
+ if (lastnum != 1)
+ cprintf(stdout, "S");
+ break;
+
+ case 'T':
+ now = time(NULL);
+ cprintf(stdout, "%.24s", ctime(&now));
+ break;
+
+ case 'U':
+ cprintf(stdout, "%s",
+ pw ? pw->pw_name : "<unknown>");
+ break;
+
+ case '%':
+ CPUTC('%', stdout);
+ break;
+
+ }
+ } else
+ CPUTC(*p, stdout);
+ }
+ cprintf(stdout, "\r\n");
+ }
+
+ (void)fflush(stdout);
+ (void)fclose(f);
+ return (1);
+}
+
+/*
+ * Parse src, expanding '%' escapes, into dst (which must be at least
+ * MAXPATHLEN long).
+ */
+void
+format_path(char *dst, const char *src)
+{
+ size_t len;
+ const char *p;
+
+ dst[0] = '\0';
+ len = 0;
+ if (src == NULL)
+ return;
+ for (p = src; *p && len < MAXPATHLEN; p++) {
+ if (*p == '%') {
+ p++;
+ switch (*p) {
+
+ case 'c':
+ len += strlcpy(dst + len, curclass.classname,
+ MAXPATHLEN - len);
+ break;
+
+ case 'd':
+ len += strlcpy(dst + len, pw->pw_dir,
+ MAXPATHLEN - len);
+ break;
+
+ case 'u':
+ len += strlcpy(dst + len, pw->pw_name,
+ MAXPATHLEN - len);
+ break;
+
+ case '%':
+ dst[len++] = '%';
+ break;
+
+ }
+ } else
+ dst[len++] = *p;
+ }
+ if (len < MAXPATHLEN)
+ dst[len] = '\0';
+ dst[MAXPATHLEN - 1] = '\0';
+}
+
+/*
+ * Find s2 at the end of s1. If found, return a string up to (but
+ * not including) s2, otherwise returns NULL.
+ */
+static char *
+strend(const char *s1, char *s2)
+{
+ static char buf[MAXPATHLEN];
+
+ char *start;
+ size_t l1, l2;
+
+ l1 = strlen(s1);
+ l2 = strlen(s2);
+
+ if (l2 >= l1)
+ return(NULL);
+
+ strlcpy(buf, s1, sizeof(buf));
+ start = buf + (l1 - l2);
+
+ if (strcmp(start, s2) == 0) {
+ *start = '\0';
+ return(buf);
+ } else
+ return(NULL);
+}
+
+static int
+filetypematch(char *types, int mode)
+{
+ for ( ; types[0] != '\0'; types++)
+ switch (*types) {
+ case 'd':
+ if (S_ISDIR(mode))
+ return(1);
+ break;
+ case 'f':
+ if (S_ISREG(mode))
+ return(1);
+ break;
+ }
+ return(0);
+}
+
+/*
+ * Look for a conversion. If we succeed, return a pointer to the
+ * command to execute for the conversion.
+ *
+ * The command is stored in a static array so there's no memory
+ * leak problems, and not too much to change in ftpd.c. This
+ * routine doesn't need to be re-entrant unless we start using a
+ * multi-threaded ftpd, and that's not likely for a while...
+ */
+char **
+do_conversion(const char *fname)
+{
+ struct ftpconv *cp;
+ struct stat st;
+ int o_errno;
+ char *base = NULL;
+ char *cmd, *p, *lp, **argv;
+ StringList *sl;
+
+ o_errno = errno;
+ sl = NULL;
+ cmd = NULL;
+ for (cp = curclass.conversions; cp != NULL; cp = cp->next) {
+ if (cp->suffix == NULL) {
+ syslog(LOG_WARNING,
+ "cp->suffix==NULL in conv list; SHOULDN'T HAPPEN!");
+ continue;
+ }
+ if ((base = strend(fname, cp->suffix)) == NULL)
+ continue;
+ if (cp->types == NULL || cp->disable == NULL ||
+ cp->command == NULL)
+ continue;
+ /* Is it enabled? */
+ if (strcmp(cp->disable, ".") != 0 &&
+ stat(cp->disable, &st) == 0)
+ continue;
+ /* Does the base exist? */
+ if (stat(base, &st) < 0)
+ continue;
+ /* Is the file type ok */
+ if (!filetypematch(cp->types, st.st_mode))
+ continue;
+ break; /* "We have a winner!" */
+ }
+
+ /* If we got through the list, no conversion */
+ if (cp == NULL)
+ goto cleanup_do_conv;
+
+ /* Split up command into an argv */
+ if ((sl = sl_init()) == NULL)
+ goto cleanup_do_conv;
+ cmd = xstrdup(cp->command);
+ p = cmd;
+ while (p) {
+ NEXTWORD(p, lp);
+ if (strcmp(lp, "%s") == 0)
+ lp = base;
+ if (sl_add(sl, xstrdup(lp)) == -1)
+ goto cleanup_do_conv;
+ }
+
+ if (sl_add(sl, NULL) == -1)
+ goto cleanup_do_conv;
+ argv = sl->sl_str;
+ free(cmd);
+ free(sl);
+ return(argv);
+
+ cleanup_do_conv:
+ if (sl)
+ sl_free(sl, 1);
+ free(cmd);
+ errno = o_errno;
+ return(NULL);
+}
+
+/*
+ * Convert the string `arg' to a long long, which may have an optional SI suffix
+ * (`b', `k', `m', `g', `t'). Returns the number for success, -1 otherwise.
+ */
+LLT
+strsuftoll(const char *arg)
+{
+ char *cp;
+ LLT val;
+
+ if (!isdigit((unsigned char)arg[0]))
+ return (-1);
+
+ val = STRTOLL(arg, &cp, 10);
+ if (cp != NULL) {
+ if (cp[0] != '\0' && cp[1] != '\0')
+ return (-1);
+ switch (tolower((unsigned char)cp[0])) {
+ case '\0':
+ case 'b':
+ break;
+ case 'k':
+ val <<= 10;
+ break;
+ case 'm':
+ val <<= 20;
+ break;
+ case 'g':
+ val <<= 30;
+ break;
+#ifndef NO_LONG_LONG
+ case 't':
+ val <<= 40;
+ break;
+#endif
+ default:
+ return (-1);
+ }
+ }
+ if (val < 0)
+ return (-1);
+
+ return (val);
+}
+
+/*
+ * Count the number of current connections, reading from
+ * /var/run/ftpd.pids-<class>
+ * Does a kill -0 on each pid in that file, and only counts
+ * processes that exist (or frees the slot if it doesn't).
+ * Adds getpid() to the first free slot. Truncates the file
+ * if possible.
+ */
+void
+count_users(void)
+{
+ char fn[MAXPATHLEN];
+ int fd, i, last;
+ size_t count;
+ pid_t *pids, mypid;
+ struct stat sb;
+
+ (void)strlcpy(fn, _PATH_CLASSPIDS, sizeof(fn));
+ (void)strlcat(fn, curclass.classname, sizeof(fn));
+ pids = NULL;
+ connections = 1;
+
+ 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)
+ goto cleanup_count;
+ count = read(fd, pids, sb.st_size);
+ if (count < 0 || count != sb.st_size)
+ goto cleanup_count;
+ count /= sizeof(pid_t);
+ mypid = getpid();
+ last = 0;
+ for (i = 0; i < count; i++) {
+ if (pids[i] == 0)
+ continue;
+ if (kill(pids[i], 0) == -1 && errno != EPERM) {
+ if (mypid != 0) {
+ pids[i] = mypid;
+ mypid = 0;
+ last = i;
+ }
+ } else {
+ connections++;
+ last = i;
+ }
+ }
+ if (mypid != 0) {
+ if (pids[last] != 0)
+ last++;
+ pids[last] = mypid;
+ }
+ count = (last + 1) * sizeof(pid_t);
+ if (lseek(fd, 0, SEEK_SET) == -1)
+ goto cleanup_count;
+ if (write(fd, pids, count) == -1)
+ goto cleanup_count;
+ (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
new file mode 100644
index 0000000..15cf939
--- /dev/null
+++ b/contrib/lukemftpd/src/extern.h
@@ -0,0 +1,372 @@
+/* $NetBSD: extern.h,v 1.41 2001/04/25 01:46:25 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.2 (Berkeley) 4/4/94
+ */
+
+/*-
+ * Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (C) 1997 and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef NO_LONG_LONG
+# define LLF "%ld"
+# define LLFP(x) "%" x "ld"
+# define LLT long
+# define ULLF "%lu"
+# 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)
+#else
+# define LLF "%lld"
+# define LLFP(x) "%" x "lld"
+# define LLT long long
+# define ULLF "%llu"
+# define ULLFP(x) "%" x "llu"
+# define ULLT unsigned long long
+# define STRTOLL(x,y,z) strtoll(x,y,z)
+#endif
+#endif
+
+#define FTP_BUFLEN 512
+
+void abor(void);
+void blkfree(char **);
+void closedataconn(FILE *);
+char *conffilename(const char *);
+char **copyblk(char **);
+void count_users(void);
+void cprintf(FILE *, const char *, ...)
+ ;
+void cwd(const char *);
+FILE *dataconn(const char *, off_t, const char *);
+void delete(const char *);
+int display_file(const char *, int);
+char **do_conversion(const char *);
+void dologout(int);
+void fatal(const char *);
+void feat(void);
+void format_path(char *, const char *);
+int ftpd_pclose(FILE *);
+FILE *ftpd_popen(char *[], const char *, int);
+char *getline(char *, int, FILE *);
+void init_curclass(void);
+void logxfer(const char *, off_t, const char *, const char *,
+ const struct timeval *, const char *);
+#if 0
+void logwtmp(const char *, const char *, const char *);
+#endif
+struct tab *lookup(struct tab *, const char *);
+void makedir(const char *);
+void mlsd(const char *);
+void mlst(const char *);
+void opts(const char *);
+void parse_conf(const char *);
+void pass(const char *);
+void passive(void);
+int lpsvproto2af(int);
+int af2lpsvproto(int);
+int epsvproto2af(int);
+int af2epsvproto(int);
+void long_passive(char *, int);
+int extended_port(const char *);
+void epsv_protounsupp(const char *);
+void perror_reply(int, const char *);
+void pwd(void);
+void removedir(const char *);
+void renamecmd(const char *, const char *);
+char *renamefrom(const char *);
+void reply(int, const char *, ...)
+ ;
+void retrieve(char *[], const char *);
+void send_file_list(const char *);
+void show_chdir_messages(int);
+void sizecmd(const char *);
+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 *);
+
+#include <netinet/in.h>
+
+#ifdef BSD4_4
+# define HAVE_SETPROCTITLE 1
+# define HAVE_SOCKADDR_SA_LEN 1
+#endif
+
+struct sockinet {
+ union sockunion {
+ struct sockaddr_in su_sin;
+#ifdef INET6
+ struct sockaddr_in6 su_sin6;
+#endif
+ } si_su;
+#if !HAVE_SOCKADDR_SA_LEN
+ int si_len;
+#endif
+};
+
+#if !HAVE_SOCKADDR_SA_LEN
+# define su_len si_len
+#else
+# define su_len si_su.su_sin.sin_len
+#endif
+#define su_addr si_su.su_sin.sin_addr
+#define su_family si_su.su_sin.sin_family
+#define su_port si_su.su_sin.sin_port
+#ifdef INET6
+# define su_6addr si_su.su_sin6.sin6_addr
+# define su_scope_id si_su.su_sin6.sin6_scope_id
+#endif
+
+struct tab {
+ char *name;
+ short token;
+ short state;
+ short flags; /* 1 if command implemented, 2 if has options,
+ 4 if can occur OOB */
+ char *help;
+ char *options;
+};
+
+struct ftpconv {
+ struct ftpconv *next;
+ char *suffix; /* Suffix of requested name */
+ char *types; /* Valid file types */
+ char *disable; /* File to disable conversions */
+ char *command; /* Command to do the conversion */
+};
+
+typedef enum {
+ CLASS_GUEST,
+ CLASS_CHROOT,
+ CLASS_REAL
+} class_ft;
+
+typedef enum {
+ FLAG_checkportcmd = 1<<0, /* Check port commands */
+ FLAG_modify = 1<<1, /* Allow CHMOD, DELE, MKD, RMD, RNFR,
+ UMASK */
+ FLAG_passive = 1<<2, /* Allow PASV mode */
+ FLAG_sanenames = 1<<3, /* Restrict names of uploaded files */
+ FLAG_upload = 1<<4 /* As per modify, but also allow
+ APPE, STOR, STOU */
+} classflag_t;
+
+#define CURCLASS_FLAGS_SET(x) (curclass.flags |= (FLAG_ ## x))
+#define CURCLASS_FLAGS_CLR(x) (curclass.flags &= ~(FLAG_ ## x))
+#define CURCLASS_FLAGS_ISSET(x) (curclass.flags & (FLAG_ ## x))
+
+struct ftpclass {
+ struct sockinet advertise; /* PASV address to advertise as */
+ char *chroot; /* Directory to chroot(2) to at login */
+ char *classname; /* Current class */
+ struct ftpconv *conversions; /* List of conversions */
+ 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) */
+ 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 */
+ 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 rateget; /* Get (RETR) transfer rate throttle */
+ LLT rateput; /* Put (STOR) transfer rate throttle */
+ unsigned int timeout; /* Default timeout */
+ class_ft type; /* Class type */
+ mode_t umask; /* Umask to use */
+};
+
+extern void ftp_loop(void) __attribute__ ((noreturn));
+extern void ftp_handle_line(char *);
+
+#ifndef GLOBAL
+#define GLOBAL extern
+#endif
+
+
+GLOBAL struct sockinet ctrl_addr;
+GLOBAL struct sockinet data_dest;
+GLOBAL struct sockinet data_source;
+GLOBAL struct sockinet his_addr;
+GLOBAL struct sockinet pasv_addr;
+GLOBAL int connections;
+GLOBAL struct ftpclass curclass;
+GLOBAL int debug;
+GLOBAL jmp_buf errcatch;
+GLOBAL char *emailaddr;
+GLOBAL int form;
+GLOBAL int gidcount; /* number of entries in gidlist[] */
+GLOBAL gid_t gidlist[NGROUPS_MAX];
+GLOBAL int hasyyerrored;
+GLOBAL char hostname[MAXHOSTNAMELEN+1];
+GLOBAL char homedir[MAXPATHLEN];
+#ifdef KERBEROS5
+GLOBAL krb5_context kcontext;
+#endif
+GLOBAL int logged_in;
+GLOBAL int logging;
+GLOBAL int pdata; /* for passive mode */
+#if HAVE_SETPROCTITLE
+GLOBAL char proctitle[BUFSIZ]; /* initial part of title */
+#endif
+GLOBAL struct passwd *pw;
+GLOBAL int quietmessages;
+GLOBAL char remotehost[MAXHOSTNAMELEN+1];
+GLOBAL off_t restart_point;
+GLOBAL char tmpline[FTP_BUFLEN];
+GLOBAL sig_atomic_t transflag;
+GLOBAL int type;
+GLOBAL int usedefault; /* for data transfers */
+GLOBAL const char *version;
+GLOBAL int is_oob;
+
+ /* total file data bytes */
+GLOBAL off_t total_data_in, total_data_out, total_data;
+ /* total number of data files */
+GLOBAL off_t total_files_in, total_files_out, total_files;
+ /* total bytes */
+GLOBAL off_t total_bytes_in, total_bytes_out, total_bytes;
+ /* total number of xfers */
+GLOBAL off_t total_xfers_in, total_xfers_out, total_xfers;
+
+extern struct tab cmdtab[];
+
+#define INTERNAL_LS "/bin/ls"
+
+
+#define CMD_IMPLEMENTED(x) ((x)->flags != 0)
+#define CMD_HAS_OPTIONS(x) ((x)->flags & 0x2)
+#define CMD_OOB(x) ((x)->flags & 0x4)
+
+#define CPUTC(c, f) do { \
+ putc(c, f); total_bytes++; total_bytes_out++; \
+ } while (0);
+
+#define CURCLASSTYPE curclass.type == CLASS_GUEST ? "GUEST" : \
+ curclass.type == CLASS_CHROOT ? "CHROOT" : \
+ curclass.type == CLASS_REAL ? "REAL" : \
+ "<unknown>"
+
+#define ISDOTDIR(x) (x[0] == '.' && x[1] == '\0')
+#define ISDOTDOTDIR(x) (x[0] == '.' && x[1] == '.' && x[2] == '\0')
+
+#define EMPTYSTR(p) ((p) == NULL || *(p) == '\0')
+#define NEXTWORD(P, W) do { \
+ (W) = strsep(&(P), " \t"); \
+ } while ((W) != NULL && *(W) == '\0')
+#define PLURAL(s) ((s) == 1 ? "" : "s")
+#define REASSIGN(X,Y) do { if (X) free(X); (X)=(Y); } while (/*CONSTCOND*/0)
+
+#ifndef IPPORT_ANONMAX
+# define IPPORT_ANONMAX 65535
+#endif
diff --git a/contrib/lukemftpd/src/ftpcmd.y b/contrib/lukemftpd/src/ftpcmd.y
new file mode 100644
index 0000000..aeea190
--- /dev/null
+++ b/contrib/lukemftpd/src/ftpcmd.y
@@ -0,0 +1,1808 @@
+/* $NetBSD: ftpcmd.y,v 1.65 2001/04/25 01:46:25 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1985, 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ftpcmd.y 8.3 (Berkeley) 4/6/94
+ */
+
+/*
+ * Grammar for FTP commands.
+ * See RFC 959.
+ */
+
+%{
+#include "lukemftpd.h"
+
+#include "extern.h"
+#include "version.h"
+
+static int cmd_type;
+static int cmd_form;
+static int cmd_bytesz;
+
+char cbuf[FTP_BUFLEN];
+char *cmdp;
+char *fromname;
+
+%}
+
+%union {
+ int i;
+ char *s;
+}
+
+%token
+ A B C E F I
+ L N P R S T
+
+ SP CRLF COMMA
+
+ USER PASS ACCT CWD CDUP SMNT
+ QUIT REIN PORT PASV TYPE STRU
+ MODE RETR STOR STOU APPE ALLO
+ REST RNFR RNTO ABOR DELE RMD
+ MKD PWD LIST NLST SITE SYST
+ STAT HELP NOOP
+
+ AUTH ADAT PROT PBSZ CCC MIC
+ CONF ENC
+
+ FEAT OPTS
+
+ SIZE MDTM MLST MLSD
+
+ LPRT LPSV EPRT EPSV
+
+ MAIL MLFL MRCP MRSQ MSAM MSND
+ MSOM
+
+ CHMOD IDLE RATEGET RATEPUT UMASK
+
+ LEXERR
+
+%token <s> STRING
+%token <s> ALL
+%token <i> NUMBER
+
+%type <i> check_login octal_number byte_size
+%type <i> struct_code mode_code type_code form_code decimal_integer
+%type <s> pathstring pathname password username
+%type <s> mechanism_name base64data prot_code
+
+%start cmd_sel
+
+%%
+
+cmd_sel
+ : cmd
+ {
+ fromname = NULL;
+ restart_point = (off_t) 0;
+ }
+
+ | rcmd
+
+ ;
+
+cmd
+ /* RFC 959 */
+ : USER SP username CRLF
+ {
+ user($3);
+ free($3);
+ }
+
+ | PASS SP password CRLF
+ {
+ pass($3);
+ memset($3, 0, strlen($3));
+ free($3);
+ }
+
+ | CWD check_login CRLF
+ {
+ if ($2)
+ cwd(homedir);
+ }
+
+ | CWD check_login SP pathname CRLF
+ {
+ if ($2 && $4 != NULL)
+ cwd($4);
+ if ($4 != NULL)
+ free($4);
+ }
+
+ | CDUP check_login CRLF
+ {
+ if ($2)
+ cwd("..");
+ }
+
+ | QUIT CRLF
+ {
+ if (logged_in) {
+ reply(-221, "%s", "");
+ reply(0,
+ "Data traffic for this session was " LLF " byte%s in " LLF " file%s.",
+ (LLT)total_data, PLURAL(total_data),
+ (LLT)total_files, PLURAL(total_files));
+ reply(0,
+ "Total traffic for this session was " LLF " byte%s in " LLF " transfer%s.",
+ (LLT)total_bytes, PLURAL(total_bytes),
+ (LLT)total_xfers, PLURAL(total_xfers));
+ }
+ reply(221,
+ "Thank you for using the FTP service on %s.",
+ hostname);
+ if (logged_in && logging) {
+ syslog(LOG_INFO,
+ "Data traffic: " LLF " byte%s in " LLF " file%s",
+ (LLT)total_data, PLURAL(total_data),
+ (LLT)total_files, PLURAL(total_files));
+ syslog(LOG_INFO,
+ "Total traffic: " LLF " byte%s in " LLF " transfer%s",
+ (LLT)total_bytes, PLURAL(total_bytes),
+ (LLT)total_xfers, PLURAL(total_xfers));
+ }
+
+ dologout(0);
+ }
+
+ | PORT check_login SP host_port CRLF
+ {
+ if ($2)
+ port_check("PORT", AF_INET);
+ }
+
+ | LPRT check_login SP host_long_port4 CRLF
+ {
+ if ($2)
+ port_check("LPRT", AF_INET);
+ }
+
+ | LPRT check_login SP host_long_port6 CRLF
+ {
+#ifdef INET6
+ if ($2)
+ port_check("LPRT", AF_INET6);
+#else
+ reply(500, "IPv6 support not available.");
+#endif
+ }
+
+ | EPRT check_login SP STRING CRLF
+ {
+ if ($2) {
+ if (extended_port($4) == 0)
+ port_check("EPRT", -1);
+ }
+ free($4);
+ }
+
+ | PASV check_login CRLF
+ {
+ if ($2) {
+ if (CURCLASS_FLAGS_ISSET(passive))
+ passive();
+ else
+ reply(500, "PASV mode not available.");
+ }
+ }
+
+ | LPSV check_login CRLF
+ {
+ if ($2) {
+ if (epsvall)
+ reply(501,
+ "LPSV disallowed after EPSV ALL");
+ else
+ long_passive("LPSV", PF_UNSPEC);
+ }
+ }
+
+ | EPSV check_login SP NUMBER CRLF
+ {
+ if ($2)
+ long_passive("EPSV", epsvproto2af($4));
+ }
+
+ | EPSV check_login SP ALL CRLF
+ {
+ if ($2) {
+ reply(200, "EPSV ALL command successful.");
+ epsvall++;
+ }
+ }
+
+ | EPSV check_login CRLF
+ {
+ if ($2)
+ long_passive("EPSV", PF_UNSPEC);
+ }
+
+ | TYPE check_login SP type_code CRLF
+ {
+ if ($2) {
+
+ switch (cmd_type) {
+
+ case TYPE_A:
+ if (cmd_form == FORM_N) {
+ reply(200, "Type set to A.");
+ type = cmd_type;
+ form = cmd_form;
+ } else
+ reply(504, "Form must be N.");
+ break;
+
+ case TYPE_E:
+ reply(504, "Type E not implemented.");
+ break;
+
+ case TYPE_I:
+ reply(200, "Type set to I.");
+ type = cmd_type;
+ break;
+
+ case TYPE_L:
+#if NBBY == 8
+ if (cmd_bytesz == 8) {
+ reply(200,
+ "Type set to L (byte size 8).");
+ type = cmd_type;
+ } else
+ reply(504, "Byte size must be 8.");
+#else /* NBBY == 8 */
+ UNIMPLEMENTED for NBBY != 8
+#endif /* NBBY == 8 */
+ }
+
+ }
+ }
+
+ | STRU check_login SP struct_code CRLF
+ {
+ if ($2) {
+ switch ($4) {
+
+ case STRU_F:
+ reply(200, "STRU F ok.");
+ break;
+
+ default:
+ reply(504, "Unimplemented STRU type.");
+ }
+ }
+ }
+
+ | MODE check_login SP mode_code CRLF
+ {
+ if ($2) {
+ switch ($4) {
+
+ case MODE_S:
+ reply(200, "MODE S ok.");
+ break;
+
+ default:
+ reply(502, "Unimplemented MODE type.");
+ }
+ }
+ }
+
+ | RETR check_login SP pathname CRLF
+ {
+ if ($2 && $4 != NULL)
+ retrieve(NULL, $4);
+ if ($4 != NULL)
+ free($4);
+ }
+
+ | STOR SP pathname CRLF
+ {
+ if (check_write($3, 1))
+ store($3, "w", 0);
+ if ($3 != NULL)
+ free($3);
+ }
+
+ | STOU SP pathname CRLF
+ {
+ if (check_write($3, 1))
+ store($3, "w", 1);
+ if ($3 != NULL)
+ free($3);
+ }
+
+ | APPE SP pathname CRLF
+ {
+ if (check_write($3, 1))
+ store($3, "a", 0);
+ if ($3 != NULL)
+ free($3);
+ }
+
+ | ALLO check_login SP NUMBER CRLF
+ {
+ if ($2)
+ reply(202, "ALLO command ignored.");
+ }
+
+ | ALLO check_login SP NUMBER SP R SP NUMBER CRLF
+ {
+ if ($2)
+ reply(202, "ALLO command ignored.");
+ }
+
+ | RNTO SP pathname CRLF
+ {
+ if (check_write($3, 0)) {
+ if (fromname) {
+ renamecmd(fromname, $3);
+ free(fromname);
+ fromname = NULL;
+ } else {
+ reply(503, "Bad sequence of commands.");
+ }
+ }
+ if ($3 != NULL)
+ free($3);
+ }
+
+ | ABOR check_login CRLF
+ {
+ if (is_oob)
+ abor();
+ else if ($2)
+ reply(225, "ABOR command successful.");
+ }
+
+ | DELE SP pathname CRLF
+ {
+ if (check_write($3, 0))
+ delete($3);
+ if ($3 != NULL)
+ free($3);
+ }
+
+ | RMD SP pathname CRLF
+ {
+ if (check_write($3, 0))
+ removedir($3);
+ if ($3 != NULL)
+ free($3);
+ }
+
+ | MKD SP pathname CRLF
+ {
+ if (check_write($3, 0))
+ makedir($3);
+ if ($3 != NULL)
+ free($3);
+ }
+
+ | PWD check_login CRLF
+ {
+ if ($2)
+ pwd();
+ }
+
+ | LIST check_login CRLF
+ {
+ char *argv[] = { INTERNAL_LS, "-lgA", NULL };
+
+ if ($2)
+ retrieve(argv, "");
+ }
+
+ | LIST check_login SP pathname CRLF
+ {
+ char *argv[] = { INTERNAL_LS, "-lgA", NULL, NULL };
+
+ if ($2 && $4 != NULL) {
+ argv[2] = $4;
+ retrieve(argv, $4);
+ }
+ if ($4 != NULL)
+ free($4);
+ }
+
+ | NLST check_login CRLF
+ {
+ if ($2)
+ send_file_list(".");
+ }
+
+ | NLST check_login SP pathname CRLF
+ {
+ if ($2)
+ send_file_list($4);
+ free($4);
+ }
+
+ | SITE SP HELP CRLF
+ {
+ help(sitetab, NULL);
+ }
+
+ | SITE SP CHMOD SP octal_number SP pathname CRLF
+ {
+ if (check_write($7, 0)) {
+ if ($5 > 0777)
+ reply(501,
+ "CHMOD: Mode value must be between 0 and 0777");
+ else if (chmod($7, $5) < 0)
+ perror_reply(550, $7);
+ else
+ reply(200, "CHMOD command successful.");
+ }
+ if ($7 != NULL)
+ free($7);
+ }
+
+ | SITE SP HELP SP STRING CRLF
+ {
+ help(sitetab, $5);
+ free($5);
+ }
+
+ | SITE SP IDLE check_login CRLF
+ {
+ if ($4) {
+ reply(200,
+ "Current IDLE time limit is %d seconds; max %d",
+ curclass.timeout, curclass.maxtimeout);
+ }
+ }
+
+ | SITE SP IDLE check_login SP NUMBER CRLF
+ {
+ if ($4) {
+ if ($6 < 30 || $6 > curclass.maxtimeout) {
+ reply(501,
+ "IDLE time limit must be between 30 and %d seconds",
+ curclass.maxtimeout);
+ } else {
+ curclass.timeout = $6;
+ (void) alarm(curclass.timeout);
+ reply(200,
+ "IDLE time limit set to %d seconds",
+ curclass.timeout);
+ }
+ }
+ }
+
+ | SITE SP RATEGET check_login CRLF
+ {
+ if ($4) {
+ reply(200,
+ "Current RATEGET is " LLF " bytes/sec",
+ (LLT)curclass.rateget);
+ }
+ }
+
+ | SITE SP RATEGET check_login SP STRING CRLF
+ {
+ 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);
+ else {
+ curclass.rateget = rate;
+ reply(200,
+ "RATEGET set to " LLF " bytes/sec",
+ (LLT)curclass.rateget);
+ }
+ }
+ free($6);
+ }
+
+ | SITE SP RATEPUT check_login CRLF
+ {
+ if ($4) {
+ reply(200,
+ "Current RATEPUT is " LLF " bytes/sec",
+ (LLT)curclass.rateput);
+ }
+ }
+
+ | SITE SP RATEPUT check_login SP STRING CRLF
+ {
+ 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);
+ else {
+ curclass.rateput = rate;
+ reply(200,
+ "RATEPUT set to " LLF " bytes/sec",
+ (LLT)curclass.rateput);
+ }
+ }
+ free($6);
+ }
+
+ | SITE SP UMASK check_login CRLF
+ {
+ int oldmask;
+
+ if ($4) {
+ oldmask = umask(0);
+ (void) umask(oldmask);
+ reply(200, "Current UMASK is %03o", oldmask);
+ }
+ }
+
+ | SITE SP UMASK check_login SP octal_number CRLF
+ {
+ int oldmask;
+
+ if ($4 && CURCLASS_FLAGS_ISSET(modify)) {
+ if (($6 == -1) || ($6 > 0777)) {
+ reply(501, "Bad UMASK value");
+ } else {
+ oldmask = umask($6);
+ reply(200,
+ "UMASK set to %03o (was %03o)",
+ $6, oldmask);
+ }
+ }
+ }
+
+ | SYST CRLF
+ {
+ if (EMPTYSTR(version))
+ reply(215, "UNIX Type: L%d", NBBY);
+ else
+ reply(215, "UNIX Type: L%d Version: %s", NBBY,
+ version);
+ }
+
+ | STAT check_login SP pathname CRLF
+ {
+ if ($2 && $4 != NULL)
+ statfilecmd($4);
+ if ($4 != NULL)
+ free($4);
+ }
+
+ | STAT CRLF
+ {
+ if (is_oob)
+ statxfer();
+ else
+ statcmd();
+ }
+
+ | HELP CRLF
+ {
+ help(cmdtab, NULL);
+ }
+
+ | HELP SP STRING CRLF
+ {
+ char *cp = $3;
+
+ if (strncasecmp(cp, "SITE", 4) == 0) {
+ cp = $3 + 4;
+ if (*cp == ' ')
+ cp++;
+ if (*cp)
+ help(sitetab, cp);
+ else
+ help(sitetab, NULL);
+ } else
+ help(cmdtab, $3);
+ free($3);
+ }
+
+ | NOOP CRLF
+ {
+ reply(200, "NOOP command successful.");
+ }
+
+ /* RFC 2228 */
+ | AUTH SP mechanism_name CRLF
+ {
+ reply(502, "RFC 2228 authentication not implemented.");
+ free($3);
+ }
+
+ | ADAT SP base64data CRLF
+ {
+ reply(503,
+ "Please set authentication state with AUTH.");
+ free($3);
+ }
+
+ | PROT SP prot_code CRLF
+ {
+ reply(503,
+ "Please set protection buffer size with PBSZ.");
+ free($3);
+ }
+
+ | PBSZ SP decimal_integer CRLF
+ {
+ reply(503,
+ "Please set authentication state with AUTH.");
+ }
+
+ | CCC CRLF
+ {
+ reply(533, "No protection enabled.");
+ }
+
+ | MIC SP base64data CRLF
+ {
+ reply(502, "RFC 2228 authentication not implemented.");
+ free($3);
+ }
+
+ | CONF SP base64data CRLF
+ {
+ reply(502, "RFC 2228 authentication not implemented.");
+ free($3);
+ }
+
+ | ENC SP base64data CRLF
+ {
+ reply(502, "RFC 2228 authentication not implemented.");
+ free($3);
+ }
+
+ /* RFC 2389 */
+ | FEAT CRLF
+ {
+
+ feat();
+ }
+
+ | OPTS SP STRING CRLF
+ {
+
+ opts($3);
+ free($3);
+ }
+
+
+ /* extensions from draft-ietf-ftpext-mlst-11 */
+
+ /*
+ * Return size of file in a format suitable for
+ * using with RESTART (we just count bytes).
+ */
+ | SIZE check_login SP pathname CRLF
+ {
+ if ($2 && $4 != NULL)
+ sizecmd($4);
+ if ($4 != NULL)
+ free($4);
+ }
+
+ /*
+ * Return modification time of file as an ISO 3307
+ * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx
+ * where xxx is the fractional second (of any precision,
+ * not necessarily 3 digits)
+ */
+ | MDTM check_login SP pathname CRLF
+ {
+ if ($2 && $4 != NULL) {
+ struct stat stbuf;
+ if (stat($4, &stbuf) < 0)
+ perror_reply(550, $4);
+ else if (!S_ISREG(stbuf.st_mode)) {
+ reply(550, "%s: not a plain file.", $4);
+ } else {
+ struct tm *t;
+
+ t = gmtime(&stbuf.st_mtime);
+ reply(213,
+ "%04d%02d%02d%02d%02d%02d",
+ TM_YEAR_BASE + t->tm_year,
+ t->tm_mon+1, t->tm_mday,
+ t->tm_hour, t->tm_min, t->tm_sec);
+ }
+ }
+ if ($4 != NULL)
+ free($4);
+ }
+
+ | MLST check_login SP pathname CRLF
+ {
+ if ($2 && $4 != NULL)
+ mlst($4);
+ if ($4 != NULL)
+ free($4);
+ }
+
+ | MLST check_login CRLF
+ {
+ mlst(NULL);
+ }
+
+ | MLSD check_login SP pathname CRLF
+ {
+ if ($2 && $4 != NULL)
+ mlsd($4);
+ if ($4 != NULL)
+ free($4);
+ }
+
+ | MLSD check_login CRLF
+ {
+ mlsd(NULL);
+ }
+
+ | error CRLF
+ {
+ yyerrok;
+ }
+ ;
+
+rcmd
+ : REST check_login SP byte_size CRLF
+ {
+ if ($2) {
+ fromname = NULL;
+ restart_point = $4; /* XXX: $4 is only "int" */
+ reply(350,
+ "Restarting at " LLF ". Send STORE or RETRIEVE to initiate transfer.",
+ (LLT)restart_point);
+ }
+ }
+
+ | RNFR SP pathname CRLF
+ {
+ restart_point = (off_t) 0;
+ if (check_write($3, 0))
+ fromname = renamefrom($3);
+ if ($3 != NULL)
+ free($3);
+ }
+ ;
+
+username
+ : STRING
+ ;
+
+password
+ : /* empty */
+ {
+ $$ = (char *)calloc(1, sizeof(char));
+ }
+
+ | STRING
+ ;
+
+byte_size
+ : NUMBER
+ ;
+
+host_port
+ : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER
+ {
+ char *a, *p;
+
+ memset(&data_dest, 0, sizeof(data_dest));
+ 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;
+ a = (char *)&data_dest.su_addr;
+ a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
+ }
+ ;
+
+host_long_port4
+ : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER
+ {
+ char *a, *p;
+
+ memset(&data_dest, 0, sizeof(data_dest));
+ 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;
+ a = (char *)&data_dest.su_addr;
+ a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11;
+
+ /* reject invalid LPRT command */
+ if ($1 != 4 || $3 != 4 || $13 != 2)
+ memset(&data_dest, 0, sizeof(data_dest));
+ }
+ ;
+
+host_long_port6
+ : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER
+ {
+#ifdef INET6
+ char *a, *p;
+
+ memset(&data_dest, 0, sizeof(data_dest));
+ 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;
+ 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;
+ if (his_addr.su_family == AF_INET6) {
+ /* XXX: more sanity checks! */
+ data_dest.su_scope_id = his_addr.su_scope_id;
+ }
+#else
+ memset(&data_dest, 0, sizeof(data_dest));
+#endif /* INET6 */
+ /* reject invalid LPRT command */
+ if ($1 != 6 || $3 != 16 || $37 != 2)
+ memset(&data_dest, 0, sizeof(data_dest));
+ }
+ ;
+
+form_code
+ : N
+ {
+ $$ = FORM_N;
+ }
+
+ | T
+ {
+ $$ = FORM_T;
+ }
+
+ | C
+ {
+ $$ = FORM_C;
+ }
+ ;
+
+type_code
+ : A
+ {
+ cmd_type = TYPE_A;
+ cmd_form = FORM_N;
+ }
+
+ | A SP form_code
+ {
+ cmd_type = TYPE_A;
+ cmd_form = $3;
+ }
+
+ | E
+ {
+ cmd_type = TYPE_E;
+ cmd_form = FORM_N;
+ }
+
+ | E SP form_code
+ {
+ cmd_type = TYPE_E;
+ cmd_form = $3;
+ }
+
+ | I
+ {
+ cmd_type = TYPE_I;
+ }
+
+ | L
+ {
+ cmd_type = TYPE_L;
+ cmd_bytesz = NBBY;
+ }
+
+ | L SP byte_size
+ {
+ cmd_type = TYPE_L;
+ cmd_bytesz = $3;
+ }
+
+ /* this is for a bug in the BBN ftp */
+ | L byte_size
+ {
+ cmd_type = TYPE_L;
+ cmd_bytesz = $2;
+ }
+ ;
+
+struct_code
+ : F
+ {
+ $$ = STRU_F;
+ }
+
+ | R
+ {
+ $$ = STRU_R;
+ }
+
+ | P
+ {
+ $$ = STRU_P;
+ }
+ ;
+
+mode_code
+ : S
+ {
+ $$ = MODE_S;
+ }
+
+ | B
+ {
+ $$ = MODE_B;
+ }
+
+ | C
+ {
+ $$ = MODE_C;
+ }
+ ;
+
+pathname
+ : pathstring
+ {
+ /*
+ * Problem: this production is used for all pathname
+ * processing, but only gives a 550 error reply.
+ * This is a valid reply in some cases but not in
+ * others.
+ */
+ if (logged_in && $1 && *$1 == '~') {
+ char *path, *home, *result;
+ size_t len;
+
+ path = strchr($1 + 1, '/');
+ if (path != NULL)
+ *path++ = '\0';
+ if ($1[1] == '\0')
+ home = homedir;
+ else {
+ struct passwd *pw;
+
+ if ((pw = getpwnam($1 + 1)) != NULL)
+ home = pw->pw_dir;
+ else
+ home = $1;
+ }
+ len = strlen(home) + 1;
+ if (path != NULL)
+ len += strlen(path) + 1;
+ if ((result = malloc(len)) == NULL)
+ fatal("Local resource failure: malloc");
+ strlcpy(result, home, len);
+ if (path != NULL) {
+ strlcat(result, "/", len);
+ strlcat(result, path, len);
+ }
+ $$ = result;
+ free($1);
+ } else
+ $$ = $1;
+ }
+ ;
+
+pathstring
+ : STRING
+ ;
+
+octal_number
+ : NUMBER
+ {
+ int ret, dec, multby, digit;
+
+ /*
+ * Convert a number that was read as decimal number
+ * to what it would be if it had been read as octal.
+ */
+ dec = $1;
+ multby = 1;
+ ret = 0;
+ while (dec) {
+ digit = dec%10;
+ if (digit > 7) {
+ ret = -1;
+ break;
+ }
+ ret += digit * multby;
+ multby *= 8;
+ dec /= 10;
+ }
+ $$ = ret;
+ }
+ ;
+
+mechanism_name
+ : STRING
+ ;
+
+base64data
+ : STRING
+ ;
+
+prot_code
+ : STRING
+ ;
+
+decimal_integer
+ : NUMBER
+ ;
+
+check_login
+ : /* empty */
+ {
+ if (logged_in)
+ $$ = 1;
+ else {
+ reply(530, "Please login with USER and PASS.");
+ $$ = 0;
+ hasyyerrored = 1;
+ }
+ }
+ ;
+
+%%
+
+#define CMD 0 /* beginning of command */
+#define ARGS 1 /* expect miscellaneous arguments */
+#define STR1 2 /* expect SP followed by STRING */
+#define STR2 3 /* expect STRING */
+#define OSTR 4 /* optional SP then STRING */
+#define ZSTR1 5 /* SP then optional STRING */
+#define ZSTR2 6 /* optional STRING after SP */
+#define SITECMD 7 /* SITE command */
+#define NSTR 8 /* Number followed by a string */
+#define NOARGS 9 /* No arguments allowed */
+#define EOLN 10 /* End of line */
+
+struct tab cmdtab[] = {
+ /* From RFC 959, in order defined (5.3.1) */
+ { "USER", USER, STR1, 1, "<sp> username" },
+ { "PASS", PASS, ZSTR1, 1, "<sp> password" },
+ { "ACCT", ACCT, STR1, 0, "(specify account)" },
+ { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" },
+ { "CDUP", CDUP, NOARGS, 1, "(change to parent directory)" },
+ { "SMNT", SMNT, ARGS, 0, "(structure mount)" },
+ { "QUIT", QUIT, NOARGS, 1, "(terminate service)" },
+ { "REIN", REIN, NOARGS, 0, "(reinitialize server state)" },
+ { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" },
+ { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." },
+ { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" },
+ { "PASV", PASV, NOARGS, 1, "(set server in passive mode)" },
+ { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" },
+ { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" },
+ { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" },
+ { "STRU", STRU, ARGS, 1, "(specify file structure)" },
+ { "MODE", MODE, ARGS, 1, "(specify transfer mode)" },
+ { "RETR", RETR, STR1, 1, "<sp> file-name" },
+ { "STOR", STOR, STR1, 1, "<sp> file-name" },
+ { "STOU", STOU, STR1, 1, "<sp> file-name" },
+ { "APPE", APPE, STR1, 1, "<sp> file-name" },
+ { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" },
+ { "REST", REST, ARGS, 1, "<sp> offset (restart command)" },
+ { "RNFR", RNFR, STR1, 1, "<sp> file-name" },
+ { "RNTO", RNTO, STR1, 1, "<sp> file-name" },
+ { "ABOR", ABOR, NOARGS, 4, "(abort operation)" },
+ { "DELE", DELE, STR1, 1, "<sp> file-name" },
+ { "RMD", RMD, STR1, 1, "<sp> path-name" },
+ { "MKD", MKD, STR1, 1, "<sp> path-name" },
+ { "PWD", PWD, NOARGS, 1, "(return current directory)" },
+ { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" },
+ { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" },
+ { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" },
+ { "SYST", SYST, NOARGS, 1, "(get type of operating system)" },
+ { "STAT", STAT, OSTR, 4, "[ <sp> path-name ]" },
+ { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
+ { "NOOP", NOOP, NOARGS, 2, "" },
+
+ /* From RFC 2228, in order defined */
+ { "AUTH", AUTH, STR1, 1, "<sp> mechanism-name" },
+ { "ADAT", ADAT, STR1, 1, "<sp> base-64-data" },
+ { "PROT", PROT, STR1, 1, "<sp> prot-code" },
+ { "PBSZ", PBSZ, ARGS, 1, "<sp> decimal-integer" },
+ { "CCC", CCC, NOARGS, 1, "(Disable data protection)" },
+ { "MIC", MIC, STR1, 4, "<sp> base64data" },
+ { "CONF", CONF, STR1, 4, "<sp> base64data" },
+ { "ENC", ENC, STR1, 4, "<sp> base64data" },
+
+ /* From RFC 2389, in order defined */
+ { "FEAT", FEAT, NOARGS, 1, "(display extended features)" },
+ { "OPTS", OPTS, STR1, 1, "<sp> command [ <sp> options ]" },
+
+ /* from draft-ietf-ftpext-mlst-11 */
+ { "MDTM", MDTM, OSTR, 1, "<sp> path-name" },
+ { "SIZE", SIZE, OSTR, 1, "<sp> path-name" },
+ { "MLST", MLST, OSTR, 2, "[ <sp> path-name ]" },
+ { "MLSD", MLSD, OSTR, 1, "[ <sp> directory-name ]" },
+
+ /* obsolete commands */
+ { "MAIL", MAIL, OSTR, 0, "(mail to user)" },
+ { "MLFL", MLFL, OSTR, 0, "(mail file)" },
+ { "MRCP", MRCP, STR1, 0, "(mail recipient)" },
+ { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" },
+ { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" },
+ { "MSND", MSND, OSTR, 0, "(mail send to terminal)" },
+ { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" },
+ { "XCUP", CDUP, NOARGS, 1, "(change to parent directory)" },
+ { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" },
+ { "XMKD", MKD, STR1, 1, "<sp> path-name" },
+ { "XPWD", PWD, NOARGS, 1, "(return current directory)" },
+ { "XRMD", RMD, STR1, 1, "<sp> path-name" },
+
+ { NULL, 0, 0, 0, 0 }
+};
+
+struct tab sitetab[] = {
+ { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" },
+ { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
+ { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" },
+ { "RATEGET", RATEGET,OSTR, 1, "[ <sp> get-throttle-rate ]" },
+ { "RATEPUT", RATEPUT,OSTR, 1, "[ <sp> put-throttle-rate ]" },
+ { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" },
+ { NULL, 0, 0, 0, NULL }
+};
+
+static int check_write(const char *, int);
+static void help(struct tab *, const char *);
+static void port_check(const char *, int);
+static void toolong(int);
+static int yylex(void);
+
+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'.
+ */
+static int
+check_write(const char *file, int isupload)
+{
+ if (file == NULL)
+ return (0);
+ if (! logged_in) {
+ reply(530, "Please login with USER and PASS.");
+ return (0);
+ }
+ /* checking modify */
+ if (! isupload && ! CURCLASS_FLAGS_ISSET(modify)) {
+ reply(502, "No permission to use this command.");
+ return (0);
+ }
+ /* checking upload */
+ if (isupload && ! CURCLASS_FLAGS_ISSET(upload)) {
+ reply(502, "No permission to use this command.");
+ return (0);
+ }
+ /* checking sanenames */
+ if (CURCLASS_FLAGS_ISSET(sanenames)) {
+ const char *p;
+
+ if (file[0] == '.')
+ goto insane_name;
+ for (p = file; *p; p++) {
+ if (isalnum(*p) || *p == '-' || *p == '+' ||
+ *p == ',' || *p == '.' || *p == '_')
+ continue;
+ insane_name:
+ reply(553, "File name `%s' not allowed.", file);
+ return (0);
+ }
+ }
+ return (1);
+}
+
+struct tab *
+lookup(struct tab *p, const char *cmd)
+{
+
+ for (; p->name != NULL; p++)
+ if (strcasecmp(cmd, p->name) == 0)
+ return (p);
+ return (0);
+}
+
+#include <arpa/telnet.h>
+
+/*
+ * getline - a hacked up version of fgets to ignore TELNET escape codes.
+ */
+char *
+getline(char *s, int n, FILE *iop)
+{
+ int c;
+ char *cs;
+
+ cs = s;
+/* tmpline may contain saved command from urgent mode interruption */
+ for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) {
+ *cs++ = tmpline[c];
+ if (tmpline[c] == '\n') {
+ *cs++ = '\0';
+ if (debug)
+ syslog(LOG_DEBUG, "command: %s", s);
+ tmpline[0] = '\0';
+ return(s);
+ }
+ if (c == 0)
+ tmpline[0] = '\0';
+ }
+ while ((c = getc(iop)) != EOF) {
+ total_bytes++;
+ total_bytes_in++;
+ c &= 0377;
+ if (c == IAC) {
+ if ((c = getc(iop)) != EOF) {
+ total_bytes++;
+ total_bytes_in++;
+ c &= 0377;
+ switch (c) {
+ case WILL:
+ case WONT:
+ c = getc(iop);
+ total_bytes++;
+ total_bytes_in++;
+ cprintf(stdout, "%c%c%c", IAC, DONT, 0377&c);
+ (void) fflush(stdout);
+ continue;
+ case DO:
+ case DONT:
+ c = getc(iop);
+ total_bytes++;
+ total_bytes_in++;
+ cprintf(stdout, "%c%c%c", IAC, WONT, 0377&c);
+ (void) fflush(stdout);
+ continue;
+ case IAC:
+ break;
+ default:
+ continue; /* ignore command */
+ }
+ }
+ }
+ *cs++ = c;
+ if (--n <= 0 || c == '\n')
+ break;
+ }
+ if (c == EOF && cs == s)
+ return (NULL);
+ *cs++ = '\0';
+ if (debug) {
+ if ((curclass.type != CLASS_GUEST &&
+ strncasecmp(s, "PASS ", 5) == 0) ||
+ strncasecmp(s, "ACCT ", 5) == 0) {
+ /* Don't syslog passwords */
+ syslog(LOG_DEBUG, "command: %.4s ???", s);
+ } else {
+ char *cp;
+ int len;
+
+ /* Don't syslog trailing CR-LF */
+ len = strlen(s);
+ cp = s + len - 1;
+ while (cp >= s && (*cp == '\n' || *cp == '\r')) {
+ --cp;
+ --len;
+ }
+ syslog(LOG_DEBUG, "command: %.*s", len, s);
+ }
+ }
+ return (s);
+}
+
+static void
+toolong(int signo)
+{
+
+ reply(421,
+ "Timeout (%d seconds): closing control connection.",
+ curclass.timeout);
+ if (logging)
+ syslog(LOG_INFO, "User %s timed out after %d seconds",
+ (pw ? pw->pw_name : "unknown"), curclass.timeout);
+ dologout(1);
+}
+
+void
+ftp_handle_line(char *cp)
+{
+
+ cmdp = cp;
+ yyparse();
+}
+
+void
+ftp_loop(void)
+{
+
+ while (1) {
+ (void) signal(SIGALRM, toolong);
+ (void) alarm(curclass.timeout);
+ if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
+ reply(221, "You could at least say goodbye.");
+ dologout(0);
+ }
+ (void) alarm(0);
+ ftp_handle_line(cbuf);
+ }
+ /*NOTREACHED*/
+}
+
+static int
+yylex(void)
+{
+ static int cpos, state;
+ char *cp, *cp2;
+ struct tab *p;
+ int n;
+ char c;
+
+ switch (state) {
+
+ case CMD:
+ hasyyerrored = 0;
+ if ((cp = strchr(cmdp, '\r'))) {
+ *cp = '\0';
+#if HAVE_SETPROCTITLE
+ if (strncasecmp(cmdp, "PASS", 4) != 0 &&
+ strncasecmp(cmdp, "ACCT", 4) != 0)
+ setproctitle("%s: %s", proctitle, cmdp);
+#endif /* HAVE_SETPROCTITLE */
+ *cp++ = '\n';
+ *cp = '\0';
+ }
+ if ((cp = strpbrk(cmdp, " \n")))
+ cpos = cp - cmdp;
+ if (cpos == 0)
+ cpos = 4;
+ c = cmdp[cpos];
+ cmdp[cpos] = '\0';
+ p = lookup(cmdtab, cmdp);
+ cmdp[cpos] = c;
+ if (p != NULL) {
+ if (is_oob && ! CMD_OOB(p)) {
+ /* command will be handled in-band */
+ return (0);
+ } else if (! CMD_IMPLEMENTED(p)) {
+ reply(502, "%s command not implemented.",
+ p->name);
+ hasyyerrored = 1;
+ break;
+ }
+ state = p->state;
+ yylval.s = p->name;
+ return (p->token);
+ }
+ break;
+
+ case SITECMD:
+ if (cmdp[cpos] == ' ') {
+ cpos++;
+ return (SP);
+ }
+ cp = &cmdp[cpos];
+ if ((cp2 = strpbrk(cp, " \n")))
+ cpos = cp2 - cmdp;
+ c = cmdp[cpos];
+ cmdp[cpos] = '\0';
+ p = lookup(sitetab, cp);
+ cmdp[cpos] = c;
+ if (p != NULL) {
+ if (!CMD_IMPLEMENTED(p)) {
+ reply(502, "SITE %s command not implemented.",
+ p->name);
+ hasyyerrored = 1;
+ break;
+ }
+ state = p->state;
+ yylval.s = p->name;
+ return (p->token);
+ }
+ break;
+
+ case OSTR:
+ if (cmdp[cpos] == '\n') {
+ state = EOLN;
+ return (CRLF);
+ }
+ /* FALLTHROUGH */
+
+ case STR1:
+ case ZSTR1:
+ dostr1:
+ if (cmdp[cpos] == ' ') {
+ cpos++;
+ state = state == OSTR ? STR2 : state+1;
+ return (SP);
+ }
+ break;
+
+ case ZSTR2:
+ if (cmdp[cpos] == '\n') {
+ state = EOLN;
+ return (CRLF);
+ }
+ /* FALLTHROUGH */
+
+ case STR2:
+ cp = &cmdp[cpos];
+ n = strlen(cp);
+ cpos += n - 1;
+ /*
+ * Make sure the string is nonempty and \n terminated.
+ */
+ if (n > 1 && cmdp[cpos] == '\n') {
+ cmdp[cpos] = '\0';
+ yylval.s = xstrdup(cp);
+ cmdp[cpos] = '\n';
+ state = ARGS;
+ return (STRING);
+ }
+ break;
+
+ case NSTR:
+ if (cmdp[cpos] == ' ') {
+ cpos++;
+ return (SP);
+ }
+ if (isdigit(cmdp[cpos])) {
+ cp = &cmdp[cpos];
+ while (isdigit(cmdp[++cpos]))
+ ;
+ c = cmdp[cpos];
+ cmdp[cpos] = '\0';
+ yylval.i = atoi(cp);
+ cmdp[cpos] = c;
+ state = STR1;
+ return (NUMBER);
+ }
+ state = STR1;
+ goto dostr1;
+
+ case ARGS:
+ if (isdigit(cmdp[cpos])) {
+ cp = &cmdp[cpos];
+ while (isdigit(cmdp[++cpos]))
+ ;
+ c = cmdp[cpos];
+ cmdp[cpos] = '\0';
+ yylval.i = atoi(cp);
+ cmdp[cpos] = c;
+ return (NUMBER);
+ }
+ if (strncasecmp(&cmdp[cpos], "ALL", 3) == 0
+ && !isalnum(cmdp[cpos + 3])) {
+ yylval.s = xstrdup("ALL");
+ cpos += 3;
+ return ALL;
+ }
+ switch (cmdp[cpos++]) {
+
+ case '\n':
+ state = EOLN;
+ return (CRLF);
+
+ case ' ':
+ return (SP);
+
+ case ',':
+ return (COMMA);
+
+ case 'A':
+ case 'a':
+ return (A);
+
+ case 'B':
+ case 'b':
+ return (B);
+
+ case 'C':
+ case 'c':
+ return (C);
+
+ case 'E':
+ case 'e':
+ return (E);
+
+ case 'F':
+ case 'f':
+ return (F);
+
+ case 'I':
+ case 'i':
+ return (I);
+
+ case 'L':
+ case 'l':
+ return (L);
+
+ case 'N':
+ case 'n':
+ return (N);
+
+ case 'P':
+ case 'p':
+ return (P);
+
+ case 'R':
+ case 'r':
+ return (R);
+
+ case 'S':
+ case 's':
+ return (S);
+
+ case 'T':
+ case 't':
+ return (T);
+
+ }
+ break;
+
+ case NOARGS:
+ if (cmdp[cpos] == '\n') {
+ state = EOLN;
+ return (CRLF);
+ }
+ c = cmdp[cpos];
+ cmdp[cpos] = '\0';
+ reply(501, "'%s' command does not take any arguments.", cmdp);
+ hasyyerrored = 1;
+ cmdp[cpos] = c;
+ break;
+
+ case EOLN:
+ state = CMD;
+ return (0);
+
+ default:
+ fatal("Unknown state in scanner.");
+ }
+ yyerror(NULL);
+ state = CMD;
+ is_oob = 0;
+ longjmp(errcatch, 0);
+ /* NOTREACHED */
+}
+
+/* ARGSUSED */
+void
+yyerror(char *s)
+{
+ char *cp;
+
+ if (hasyyerrored || is_oob)
+ return;
+ if ((cp = strchr(cmdp,'\n')) != NULL)
+ *cp = '\0';
+ reply(500, "'%s': command not understood.", cmdp);
+ hasyyerrored = 1;
+}
+
+static void
+help(struct tab *ctab, const char *s)
+{
+ struct tab *c;
+ int width, NCMDS;
+ char *type;
+
+ if (ctab == sitetab)
+ type = "SITE ";
+ else
+ type = "";
+ width = 0, NCMDS = 0;
+ for (c = ctab; c->name != NULL; c++) {
+ int len = strlen(c->name);
+
+ if (len > width)
+ width = len;
+ NCMDS++;
+ }
+ width = (width + 8) &~ 7;
+ if (s == 0) {
+ int i, j, w;
+ int columns, lines;
+
+ reply(-214, "%s", "");
+ reply(0, "The following %scommands are recognized.", type);
+ reply(0, "(`-' = not implemented, `+' = supports options)");
+ columns = 76 / width;
+ if (columns == 0)
+ columns = 1;
+ lines = (NCMDS + columns - 1) / columns;
+ for (i = 0; i < lines; i++) {
+ cprintf(stdout, " ");
+ for (j = 0; j < columns; j++) {
+ c = ctab + j * lines + i;
+ cprintf(stdout, "%s", c->name);
+ w = strlen(c->name);
+ if (! CMD_IMPLEMENTED(c)) {
+ CPUTC('-', stdout);
+ w++;
+ }
+ if (CMD_HAS_OPTIONS(c)) {
+ CPUTC('+', stdout);
+ w++;
+ }
+ if (c + lines >= &ctab[NCMDS])
+ break;
+ while (w < width) {
+ CPUTC(' ', stdout);
+ w++;
+ }
+ }
+ cprintf(stdout, "\r\n");
+ }
+ (void) fflush(stdout);
+ reply(214, "Direct comments to ftp-bugs@%s.", hostname);
+ return;
+ }
+ c = lookup(ctab, s);
+ if (c == (struct tab *)0) {
+ reply(502, "Unknown command %s.", s);
+ return;
+ }
+ if (CMD_IMPLEMENTED(c))
+ reply(214, "Syntax: %s%s %s", type, c->name, c->help);
+ else
+ reply(214, "%s%-*s\t%s; not implemented.", type, width,
+ c->name, c->help);
+}
+
+/*
+ * Check that the structures used for a PORT, LPRT or EPRT command are
+ * valid (data_dest, his_addr), and if necessary, detect ftp bounce attacks.
+ * If family != -1 check that his_addr.su_family == family.
+ */
+static void
+port_check(const char *cmd, int family)
+{
+ char h1[NI_MAXHOST], h2[NI_MAXHOST];
+ char s1[NI_MAXHOST], s2[NI_MAXHOST];
+#ifdef NI_WITHSCOPEID
+ const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
+#else
+ const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
+#endif
+
+ if (epsvall) {
+ reply(501, "%s disallowed after EPSV ALL", cmd);
+ return;
+ }
+
+ if (family != -1 && his_addr.su_family != family) {
+ port_check_fail:
+ reply(500, "Illegal %s command rejected", cmd);
+ return;
+ }
+
+ if (data_dest.su_family != his_addr.su_family)
+ goto port_check_fail;
+
+ /* be paranoid, if told so */
+ if (CURCLASS_FLAGS_ISSET(checkportcmd)) {
+#ifdef INET6
+ /*
+ * be paranoid, there are getnameinfo implementation that does
+ * not present scopeid portion
+ */
+ if (data_dest.su_family == AF_INET6 &&
+ data_dest.su_scope_id != his_addr.su_scope_id)
+ goto port_check_fail;
+#endif
+
+ if (getnameinfo((struct sockaddr *)&data_dest, data_dest.su_len,
+ h1, sizeof(h1), s1, sizeof(s1), niflags))
+ goto port_check_fail;
+ if (getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
+ h2, sizeof(h2), s2, sizeof(s2), niflags))
+ goto port_check_fail;
+
+ if (atoi(s1) < IPPORT_RESERVED || strcmp(h1, h2) != 0)
+ goto port_check_fail;
+ }
+
+ usedefault = 0;
+ if (pdata >= 0) {
+ (void) close(pdata);
+ pdata = -1;
+ }
+ reply(200, "%s command successful.", cmd);
+}
diff --git a/contrib/lukemftpd/src/ftpd.8 b/contrib/lukemftpd/src/ftpd.8
new file mode 100644
index 0000000..65f993a
--- /dev/null
+++ b/contrib/lukemftpd/src/ftpd.8
@@ -0,0 +1,833 @@
+.\" $NetBSD: ftpd.8,v 1.63 2000/12/18 02:32:51 lukem Exp $
+.\"
+.\" Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\" contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Copyright (c) 1985, 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
+.\"
+.Dd December 18, 2000
+.Dt FTPD 8
+.Os
+.Sh NAME
+.Nm ftpd
+.Nd
+Internet File Transfer Protocol server
+.Sh SYNOPSIS
+.Nm
+.Op Fl dHlqQrsuUwWX
+.Op Fl a Ar anondir
+.Op Fl c Ar confdir
+.Op Fl C Ar user
+.Op Fl e Ar emailaddr
+.Op Fl h Ar hostname
+.Op Fl P Ar dataport
+.Op Fl V Ar version
+.Sh DESCRIPTION
+.Nm
+is the Internet File Transfer Protocol server process.
+The server uses the
+.Tn TCP
+protocol and listens at the port specified in the
+.Dq ftp
+service specification; see
+.Xr services 5 .
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl a Ar anondir
+Define
+.Ar anondir
+as the directory to
+.Xr chroot 2
+into for anonymous logins.
+Default is the home directory for the ftp user.
+This can also be specified with the
+.Xr ftpd.conf 5
+.Sy chroot
+directive.
+.It Fl c Ar confdir
+Change the root directory of the configuration files from
+.Dq Pa /etc
+to
+.Ar confdir .
+This changes the directory for the following files:
+.Pa /etc/ftpchroot ,
+.Pa /etc/ftpusers ,
+.Pa /etc/ftpwelcome ,
+.Pa /etc/motd ,
+and the file specified by the
+.Xr ftpd.conf 5
+.Sy limit
+directive.
+.It Fl C Ar user
+Check whether
+.Ar user
+would be granted access under
+the restrictions given in
+.Xr ftpusers 5
+and exit without attempting a connection.
+.Nm
+exits with an exit code of 0 if access would be granted, or 1 otherwise.
+This can be useful for testing configurations.
+.It Fl d
+Debugging information is written to the syslog using a facility of
+.Dv LOG_FTP .
+.It Fl e Ar emailaddr
+Use
+.Ar emailaddr
+for the
+.Dq "\&%E"
+escape sequence (see
+.Sx Display file escape sequences )
+.It Fl h Ar hostname
+Explicitly set the hostname to advertise as to
+.Ar hostname .
+The default is the hostname associated with the IP address that
+.Nm
+is listening on.
+This ability (with or without
+.Fl h ) ,
+in conjunction with
+.Fl c Ar confdir ,
+is useful when configuring
+.Sq virtual
+.Tn FTP
+servers, each listening on separate addresses as separate names.
+Refer to
+.Xr inetd.conf 5
+for more information on starting services to listen on specific IP addresses.
+.It Fl H
+Equivalent to
+.Do
+-h
+`hostname`
+.Dc .
+.It Fl l
+Each successful and failed
+.Tn FTP
+session is logged using syslog with a facility of
+.Dv LOG_FTP .
+If this option is specified more than once, the retrieve (get), store (put),
+append, delete, make directory, remove directory and rename operations and
+their file name arguments are also logged.
+.It Fl P Ar dataport
+Use
+.Ar dataport
+as the data port, overriding the default of using the port one less
+that the port
+.Nm
+is listening on.
+.It Fl q
+Enable the use of pid files for keeping track of the number of logged-in
+users per class.
+This is the default.
+.It Fl Q
+Disable the use of pid files for keeping track of the number of logged-in
+users per class.
+This may reduce the load on heavily loaded
+.Tn FTP
+servers.
+.It Fl r
+Permanently drop root privileges once the user is logged in.
+The use of this option may result in the server using a port other
+than the (listening-port - 1) for
+.Sy PORT
+style commands, which is contrary to the
+.Cm RFC 959
+specification, but in practice very few clients rely upon this behaviour.
+See
+.Sx SECURITY CONSIDERATIONS
+below for more details.
+.It Fl s
+Require a secure authentication mechanism like Kerberos or S/Key to be used.
+.It Fl u
+Log each concurrent
+.Tn FTP
+session to
+.Pa /var/run/utmp ,
+making them visible to commands such as
+.Xr who 1 .
+.It Fl U
+Don't log each concurrent
+.Tn FTP
+session to
+.Pa /var/run/utmp .
+This is the default.
+.It Fl V Ar version
+Use
+.Ar version
+as the version to advertise in the login banner and in the output of
+.Sy STAT
+and
+.Sy SYST
+instead of the default version information.
+If
+.Ar version
+is empty or
+.Sq -
+then don't display any version information.
+.It Fl w
+Log each
+.Tn FTP
+session to
+.Pa /var/log/wtmp ,
+making them visible to commands such as
+.Xr last 1 .
+This is the default.
+.It Fl W
+Don't log each
+.Tn FTP
+session to
+.Pa /var/log/wtmp .
+.It Fl X
+Log
+.Tn wu-ftpd
+style
+.Sq xferlog
+entries to the syslog, prefixed with
+.Dq "xferlog:\ " ,
+using a facility of
+.Dv LOG_FTP .
+These syslog entries can be converted to a
+.Tn wu-ftpd
+style
+.Pa xferlog
+file suitable for input into a third-party log analysis tool with a command
+similar to:
+.Dl "grep 'xferlog: ' /var/log/xferlog | \e"
+.Dl "\ \ \ sed -e 's/^.*xferlog: //' > wuxferlog"
+.El
+.Pp
+The file
+.Pa /etc/nologin
+can be used to disable
+.Tn FTP
+access.
+If the file exists,
+.Nm
+displays it and exits.
+If the file
+.Pa /etc/ftpwelcome
+exists,
+.Nm
+prints it before issuing the
+.Dq ready
+message.
+If the file
+.Pa /etc/motd
+exists (under the chroot directory if applicable),
+.Nm
+prints it after a successful login.
+This may be changed with the
+.Xr ftpd.conf 5
+directive
+.Sy motd .
+.Pp
+The
+.Nm
+server currently supports the following
+.Tn FTP
+requests.
+The case of the requests is ignored.
+.Bl -column "Request" -offset indent
+.It Sy Request Ta Sy Description
+.It ABOR Ta "abort previous command"
+.It ACCT Ta "specify account (ignored)"
+.It ALLO Ta "allocate storage (vacuously)"
+.It APPE Ta "append to a file"
+.It CDUP Ta "change to parent of current working directory"
+.It CWD Ta "change working directory"
+.It DELE Ta "delete a file"
+.It EPSV Ta "prepare for server-to-server transfer"
+.It EPRT Ta "specify data connection port"
+.It FEAT Ta "list extra features that are not defined in" Cm "RFC 959"
+.It HELP Ta "give help information"
+.It LIST Ta "give list files in a directory" Pq Dq Li "ls -lA"
+.It LPSV Ta "prepare for server-to-server transfer"
+.It LPRT Ta "specify data connection port"
+.It MLSD Ta "list contents of directory in a machine-processable form"
+.It MLST Ta "show a pathname in a machine-processable form"
+.It MKD Ta "make a directory"
+.It MDTM Ta "show last modification time of file"
+.It MODE Ta "specify data transfer" Em mode
+.It NLST Ta "give name list of files in directory"
+.It NOOP Ta "do nothing"
+.It OPTS Ta "define persistent options for a given command"
+.It PASS Ta "specify password"
+.It PASV Ta "prepare for server-to-server transfer"
+.It PORT Ta "specify data connection port"
+.It PWD Ta "print the current working directory"
+.It QUIT Ta "terminate session"
+.It REST Ta "restart incomplete transfer"
+.It RETR Ta "retrieve a file"
+.It RMD Ta "remove a directory"
+.It RNFR Ta "specify rename-from file name"
+.It RNTO Ta "specify rename-to file name"
+.It SITE Ta "non-standard commands (see next section)"
+.It SIZE Ta "return size of file"
+.It STAT Ta "return status of server"
+.It STOR Ta "store a file"
+.It STOU Ta "store a file with a unique name"
+.It STRU Ta "specify data transfer" Em structure
+.It SYST Ta "show operating system type of server system"
+.It TYPE Ta "specify data transfer" Em type
+.It USER Ta "specify user name"
+.It XCUP Ta "change to parent of current working directory (deprecated)"
+.It XCWD Ta "change working directory (deprecated)"
+.It XMKD Ta "make a directory (deprecated)"
+.It XPWD Ta "print the current working directory (deprecated)"
+.It XRMD Ta "remove a directory (deprecated)"
+.El
+.Pp
+The following non-standard or
+.Ux
+specific commands are supported by the SITE request.
+.Pp
+.Bl -column Request -offset indent
+.It Sy Request Ta Sy Description
+.It CHMOD Ta "change mode of a file, e.g. ``SITE CHMOD 755 filename''"
+.It HELP Ta "give help information."
+.It IDLE Ta "set idle-timer, e.g. ``SITE IDLE 60''"
+.It RATEGET Ta "set maximum get rate throttle in bytes/second, e.g. ``SITE RATEGET 5k''"
+.It RATEPUT Ta "set maximum put rate throttle in bytes/second, e.g. ``SITE RATEPUT 5k''"
+.It UMASK Ta "change umask, e.g. ``SITE UMASK 002''"
+.El
+.Pp
+The following
+.Tn FTP
+requests (as specified in
+.Cm RFC 959 )
+are recognized, but are not implemented:
+.Sy ACCT ,
+.Sy SMNT ,
+and
+.Sy REIN .
+.Sy MDTM
+and
+.Sy SIZE
+are not specified in
+.Cm RFC 959 ,
+but will appear in the
+next updated
+.Tn FTP
+RFC.
+.Pp
+The
+.Nm
+server will abort an active file transfer only when the
+.Sy ABOR
+command is preceded by a Telnet "Interrupt Process" (IP)
+signal and a Telnet "Synch" signal in the command Telnet stream,
+as described in Internet
+.Cm RFC 959 .
+If a
+.Sy STAT
+command is received during a data transfer, preceded by a Telnet IP
+and Synch, transfer status will be returned.
+.Pp
+.Nm
+interprets file names according to the
+.Dq globbing
+conventions used by
+.Xr csh 1 .
+This allows users to utilize the metacharacters
+.Dq Li \&*?[]{}~ .
+.Sh User authentication
+.Pp
+.Nm
+authenticates users according to five rules.
+.Pp
+.Bl -enum -offset indent
+.It
+The login name must be in the password data base,
+.Pa /etc/pwd.db ,
+and not have a null password.
+In this case a password must be provided by the client before any
+file operations may be performed.
+If the user has an S/Key key, the response from a successful
+.Sy USER
+command will include an S/Key challenge.
+The client may choose to respond with a
+.Sy PASS
+command giving either
+a standard password or an S/Key one-time password.
+The server will automatically determine which type of password it
+has been given and attempt to authenticate accordingly.
+See
+.Xr skey 1
+for more information on S/Key authentication.
+S/Key is a Trademark of Bellcore.
+.It
+The login name must be allowed based on the information in
+.Xr ftpusers 5 .
+.It
+The user must have a standard shell returned by
+.Xr getusershell 3 .
+If the user's shell field in the password database is empty, the
+shell is assumed to be
+.Pa /bin/sh .
+.It
+If directed by the file
+.Xr ftpchroot 5
+the session's root directory will be changed by
+.Xr chroot 2
+to the directory specified in the
+.Xr ftpd.conf 5
+.Sy chroot
+directive (if set),
+or to the home directory of the user.
+However, the user must still supply a password.
+This feature is intended as a compromise between a fully anonymous account
+and a fully privileged account.
+The account should also be set up as for an anonymous account.
+.It
+If the user name is
+.Dq anonymous
+or
+.Dq ftp ,
+an
+anonymous
+.Tn FTP
+account must be present in the password
+file (user
+.Dq ftp ) .
+In this case the user is allowed
+to log in by specifying any password (by convention an email address for
+the user should be used as the password).
+.Pp
+The server performs a
+.Xr chroot 2
+to the directory specified in the
+.Xr ftpd.conf 5
+.Sy chroot
+directive (if set),
+the
+.Fl a Ar anondir
+directory (if set),
+or to the home directory of the
+.Dq ftp
+user.
+.Pp
+The server then performs a
+.Xr chdir 2
+to the directory specified in the
+.Xr ftpd.conf 5
+.Sy homedir
+directive (if set), otherwise to
+.Pa / .
+.Pp
+If other restrictions are required (such as disabling of certain
+commands and the setting of a specific umask), then appropriate
+entries in
+.Xr ftpd.conf 5
+are required.
+.Pp
+If the first character of the password supplied by an anonymous user
+is
+.Dq - ,
+then the verbose messages displayed at login and upon a
+.Sy CWD
+command are suppressed.
+.El
+.Sh Display file escape sequences
+.Pp
+When
+.Nm
+displays various files back to the client (such as
+.Pa /etc/ftpwelcome
+and
+.Pa /etc/motd ) ,
+various escape strings are replaced with information pertinent
+to the current connection.
+.Pp
+The supported escape strings are:
+.Bl -tag -width "Escape" -offset indent -compact
+.It Sy "Escape"
+.Sy Description
+.It "\&%c"
+Class name.
+.It "\&%C"
+Current working directory.
+.It "\&%E"
+Email address given with
+.Fl e .
+.It "\&%L"
+Local hostname.
+.It "\&%M"
+Maximum number of users for this class.
+Displays
+.Dq unlimited
+if there's no limit.
+.It "\&%N"
+Current number of users for this class.
+.It "\&%R"
+Remote hostname.
+.It "\&%s"
+If the result of the most recent
+.Dq "\&%M"
+or
+.Dq "\&%N"
+was not
+.Dq Li 1 ,
+print an
+.Dq s .
+.It "\&%S"
+If the result of the most recent
+.Dq "\&%M"
+or
+.Dq "\&%N"
+was not
+.Dq Li 1 ,
+print an
+.Dq S .
+.It "\&%T"
+Current time.
+.It "\&%U"
+User name.
+.It "\&%\&%"
+A
+.Dq \&%
+character.
+.El
+.Sh Setting up a restricted ftp subtree
+.Pp
+In order that system security is not breached, it is recommended
+that the
+subtrees for the
+.Dq ftp
+and
+.Dq chroot
+accounts be constructed with care, following these rules
+(replace
+.Dq ftp
+in the following directory names
+with the appropriate account name for
+.Sq chroot
+users):
+.Bl -tag -width "~ftp/incoming" -offset indent
+.It Pa ~ftp
+Make the home directory owned by
+.Dq root
+and unwritable by anyone.
+.It Pa ~ftp/bin
+Make this directory owned by
+.Dq root
+and unwritable by anyone (mode 555).
+Generally any conversion commands should be installed
+here (mode 111).
+.It Pa ~ftp/etc
+Make this directory owned by
+.Dq root
+and unwritable by anyone (mode 555).
+The files
+.Pa pwd.db
+(see
+.Xr passwd 5 )
+and
+.Pa group
+(see
+.Xr group 5 )
+must be present for the
+.Sy LIST
+command to be able to display owner and group names instead of numbers.
+The password field in
+.Xr passwd 5
+is not used, and should not contain real passwords.
+The file
+.Pa motd ,
+if present, will be printed after a successful login.
+These files should be mode 444.
+.It Pa ~ftp/pub
+This directory and the subdirectories beneath it should be owned
+by the users and groups responsible for placing files in them,
+and be writable only by them (mode 755 or 775).
+They should
+.Em not
+be owned or writable by ftp or its group.
+.It Pa ~ftp/incoming
+This directory is where anonymous users place files they upload.
+The owners should be the user
+.Dq ftp
+and an appropriate group.
+Members of this group will be the only users with access to these
+files after they have been uploaded; these should be people who
+know how to deal with them appropriately.
+If you wish anonymous
+.Tn FTP
+users to be able to see the names of the
+files in this directory the permissions should be 770, otherwise
+they should be 370.
+.Pp
+The following
+.Xr ftpd.conf 5
+directives should be used:
+.Dl "modify guest off"
+.Dl "umask guest 0707"
+.Pp
+This will result in anonymous users being able to upload files to this
+directory, but they will not be able to download them, delete them, or
+overwrite them, due to the umask and disabling of the commands mentioned
+above.
+.It Pa ~ftp/tmp
+This directory is used to create temporary files which contain
+the error messages generated by a conversion or
+.Sy LIST
+command.
+The owner should be the user
+.Dq ftp .
+The permissions should be 300.
+.Pp
+If you don't enable conversion commands, or don't want anonymous users
+uploading files here (see
+.Pa ~ftp/incoming
+above), then don't create this directory.
+However, error messages from conversion or
+.Sy LIST
+commands won't be returned to the user.
+(This is the traditional behaviour.)
+Note that the
+.Xr ftpd.conf 5
+directive
+.Sy upload
+can be used to prevent users uploading here.
+.El
+.Pp
+To set up "ftp-only" accounts that provide only
+.Tn FTP ,
+but no valid shell
+login, you can copy/link
+.Pa /sbin/nologin
+to
+.Pa /sbin/ftplogin ,
+and enter
+.Pa /sbin/ftplogin
+to
+.Pa /etc/shells
+to allow logging-in via
+.Tn FTP
+into the accounts, which must have
+.Pa /sbin/ftplogin
+as login shell.
+.Sh FILES
+.Bl -tag -width /etc/ftpwelcome -compact
+.It Pa /etc/ftpchroot
+List of normal users who should be
+.Xr chroot 2 ed.
+.It Pa /etc/ftpd.conf
+Configure file conversions and other settings.
+.It Pa /etc/ftpusers
+List of unwelcome/restricted users.
+.It Pa /etc/ftpwelcome
+Welcome notice before login.
+.It Pa /etc/motd
+Welcome notice after login.
+.It Pa /etc/nologin
+If it exists, displayed and access is refused.
+.It Pa /var/run/ftpd.pids-CLASS
+State file of logged-in processes for the
+.Nm
+class
+.Sq CLASS .
+.It Pa /var/run/utmp
+List of logged-in users on the system.
+.It Pa /var/log/wtmp
+Login history database.
+.El
+.Sh SEE ALSO
+.Xr ftp 1 ,
+.Xr skey 1 ,
+.Xr who 1 ,
+.Xr getusershell 3 ,
+.Xr ftpd.conf 5 ,
+.Xr ftpchroot 5 ,
+.Xr ftpusers 5 ,
+.Xr syslogd 8
+.Sh STANDARDS
+.Nm
+recognizes all commands in
+.Cm RFC 959 ,
+follows the guidelines in
+.Cm RFC 1123 ,
+recognizes all commands in
+.Cm RFC 2228
+(although they are not supported yet),
+and supports the extensions from
+.Cm RFC 2389 ,
+.Cm RFC 2428
+and
+.Cm draft-ietf-ftpext-mlst-11 .
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Pp
+Various features such as the
+.Xr ftpd.conf 5
+functionality,
+.Cm RFC 2389 ,
+and
+.Cm draft-ietf-ftpext-mlst-11
+support was implemented in
+.Nx 1.3
+and later releases by Luke Mewburn <lukem@netbsd.org>.
+.Sh BUGS
+The server must run as the super-user to create sockets with
+privileged port numbers (i.e, those less than
+.Dv IPPORT_RESERVED ,
+which is 1024).
+If
+.Nm
+is listening on a privileged port
+it maintains an effective user id of the logged in user, reverting
+to the super-user only when binding addresses to privileged sockets.
+The
+.Fl r
+option can be used to override this behaviour and force privileges to
+be permanently revoked; see
+.Sx SECURITY CONSIDERATIONS
+below for more details.
+.Pp
+.Nm
+may have trouble handling connections from scoped IPv6 addresses, or
+IPv4 mapped addresses
+.Po
+IPv4 connection on
+.Dv AF_INET6
+socket
+.Pc .
+For the latter case, running two daemons,
+one for IPv4 and one for IPv6, will avoid the problem.
+.Sh SECURITY CONSIDERATIONS
+.Cm RFC 959
+provides no restrictions on the
+.Sy PORT
+command, and this can lead to security problems, as
+.Nm
+can be fooled into connecting to any service on any host.
+With the
+.Dq checkportcmd
+feature of the
+.Xr ftpd.conf 5 ,
+.Sy PORT
+commands with different host addresses, or TCP ports lower than
+.Dv IPPORT_RESERVED
+will be rejected.
+This also prevents
+.Sq third-party proxy ftp
+from working.
+Use of this option is
+.Em strongly
+recommended, and enabled by default.
+.Pp
+By default
+.Nm
+uses a port that is one less than the port it is listening on to
+communicate back to the client for the
+.Sy EPRT ,
+.Sy LPRT ,
+and
+.Sy PORT
+commands, unless overridden with
+.Fl P Ar dataport .
+As the default port for
+.Nm
+(21) is a privileged port below
+.Dv IPPORT_RESERVED ,
+.Nm
+retains the ability to switch back to root privileges to bind these
+ports.
+In order to increase security by reducing the potential for a bug in
+.Nm
+providing a remote root compromise,
+.Nm
+will permanently drop root privileges if one of the following is true:
+.Bl -enum -offset indent
+.It
+.Nm
+is running on a port greater than
+.Dv IPPORT_RESERVED
+and the user has logged in as a
+.Sq guest
+or
+.Sq chroot
+user.
+.It
+.Nm
+was invoked with
+.Fl r .
+.El
+.Pp
+Don't create
+.Pa ~ftp/tmp
+if you don't want anonymous users to upload files there.
+That directory is only necessary if you want to display the error
+messages of conversion commands to the user.
+Note that if uploads are disabled with the
+.Xr ftpd.conf 5
+directive
+.Sy upload ,
+then this directory cannot be abused by the user in this way, so it
+should be safe to create.
diff --git a/contrib/lukemftpd/src/ftpd.c b/contrib/lukemftpd/src/ftpd.c
new file mode 100644
index 0000000..c5c2f2e
--- /dev/null
+++ b/contrib/lukemftpd/src/ftpd.c
@@ -0,0 +1,2947 @@
+/* $NetBSD: ftpd.c,v 1.125 2001/04/25 01:46:26 lukem Exp $ */
+
+/*
+ * Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (C) 1997 and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * FTP server.
+ */
+
+#define FTP_NAMES
+
+#include "lukemftpd.h"
+
+#if HAVE_GETSPNAM
+#include <shadow.h>
+#endif
+
+#include <arpa/telnet.h>
+
+#ifdef SKEY
+#include <skey.h>
+#endif
+#ifdef KERBEROS5
+#include <com_err.h>
+#include <krb5/krb5.h>
+#endif
+
+#define GLOBAL
+#include "extern.h"
+#include "pathnames.h"
+#include "version.h"
+
+int data;
+jmp_buf urgcatch;
+int sflag;
+int stru; /* avoid C keyword */
+int mode;
+int dataport; /* use specific data port */
+int dopidfile; /* maintain pid file */
+int doutmp; /* update utmp file */
+int dowtmp; /* update wtmp file */
+int doxferlog; /* syslog wu-ftpd style xferlog entries */
+int dropprivs; /* if privileges should or have been dropped */
+int mapped; /* IPv4 connection on AF_INET6 socket */
+off_t file_size;
+off_t byte_count;
+static char ttyline[20];
+static struct utmp utmp; /* for utmp */
+
+static const char *anondir = NULL;
+static const char *confdir = _DEFAULT_CONFDIR;
+
+#if defined(KERBEROS) || defined(KERBEROS5)
+int has_ccache = 0;
+int notickets = 1;
+char *krbtkfile_env = NULL;
+char *tty = ttyline;
+int login_krb5_forwardable_tgt = 0;
+#endif
+
+int epsvall = 0;
+
+/*
+ * Timeout intervals for retrying connections
+ * to hosts that don't accept PORT cmds. This
+ * is a kludge, but given the problems with TCP...
+ */
+#define SWAITMAX 90 /* wait at most 90 seconds */
+#define SWAITINT 5 /* interval between retries */
+
+int swaitmax = SWAITMAX;
+int swaitint = SWAITINT;
+
+static int bind_pasv_addr(void);
+static int checkuser(const char *, const char *, int, int, char **);
+static int checkaccess(const char *);
+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 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 struct passwd *sgetpwnam(const char *);
+
+int main(int, char *[]);
+
+#if defined(KERBEROS)
+int klogin(struct passwd *, char *, char *, char *);
+void kdestroy(void);
+#endif
+#if defined(KERBEROS5)
+int k5login(struct passwd *, char *, char *, char *);
+void k5destroy(void);
+#endif
+
+char * __progname;
+
+int
+main(int argc, char *argv[])
+{
+ int addrlen, ch, on = 1, tos, keepalive;
+#ifdef KERBEROS5
+ krb5_error_code kerror;
+#endif
+ char *p;
+
+ __progname = strrchr(argv[0], '/');
+ if (__progname == NULL)
+ __progname = argv[0];
+ else
+ __progname++;
+
+ connections = 1;
+ debug = 0;
+ logging = 0;
+ pdata = -1;
+ sflag = 0;
+ dataport = 0;
+ dopidfile = 1; /* default: DO use a pid file to count users */
+ doutmp = 0; /* default: Do NOT log to utmp */
+ dowtmp = 1; /* default: DO log to wtmp */
+ doxferlog = 0; /* default: Do NOT syslog xferlog */
+ dropprivs = 0;
+ mapped = 0;
+ usedefault = 1;
+ emailaddr = NULL;
+ hostname[0] = '\0';
+ homedir[0] = '\0';
+ gidcount = 0;
+ is_oob = 0;
+ version = FTPD_VERSION;
+
+ /*
+ * 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);
+
+ while ((ch = getopt(argc, argv, "a:c:C:de:h:HlP:qQrst:T:uUvV:wWX"))
+ != -1) {
+ switch (ch) {
+ case 'a':
+ anondir = optarg;
+ break;
+
+ case 'c':
+ confdir = optarg;
+ break;
+
+ case 'C':
+ pw = sgetpwnam(optarg);
+ exit(checkaccess(optarg) ? 0 : 1);
+ /* NOTREACHED */
+
+ case 'd':
+ case 'v': /* deprecated */
+ debug = 1;
+ break;
+
+ case 'e':
+ emailaddr = optarg;
+ break;
+
+ case 'h':
+ strlcpy(hostname, optarg, sizeof(hostname));
+ break;
+
+ case 'H':
+ if (gethostname(hostname, sizeof(hostname)) == -1)
+ hostname[0] = '\0';
+ hostname[sizeof(hostname) - 1] = '\0';
+ break;
+
+ case 'l':
+ logging++; /* > 1 == extra logging */
+ break;
+
+ case 'P':
+ dataport = (int)strtol(optarg, &p, 10);
+ if (*p != '\0' || dataport < IPPORT_RESERVED ||
+ dataport > IPPORT_ANONMAX) {
+ syslog(LOG_WARNING, "Invalid dataport %s",
+ optarg);
+ dataport = 0;
+ }
+ break;
+
+ case 'q':
+ dopidfile = 1;
+ break;
+
+ case 'Q':
+ dopidfile = 0;
+ break;
+
+ case 'r':
+ dropprivs = 1;
+ break;
+
+ case 's':
+ sflag = 1;
+ break;
+
+ case 't':
+ case 'T':
+ syslog(LOG_WARNING,
+ "-%c has been deprecated in favour of ftpd.conf",
+ ch);
+ break;
+
+ case 'u':
+ doutmp = 1;
+ break;
+
+ case 'U':
+ doutmp = 0;
+ break;
+
+ case 'V':
+ if (EMPTYSTR(optarg) || strcmp(optarg, "-") == 0)
+ version = NULL;
+ else
+ version = xstrdup(optarg);
+ break;
+
+ case 'w':
+ dowtmp = 1;
+ break;
+
+ case 'W':
+ dowtmp = 0;
+ break;
+
+ case 'X':
+ doxferlog = 1;
+ break;
+
+ default:
+ if (optopt == 'a' || optopt == 'C')
+ exit(1);
+ syslog(LOG_WARNING, "unknown flag -%c ignored", optopt);
+ break;
+ }
+ }
+ if (EMPTYSTR(confdir))
+ confdir = _DEFAULT_CONFDIR;
+
+ memset((char *)&his_addr, 0, sizeof(his_addr));
+ addrlen = sizeof(his_addr.si_su);
+ if (getpeername(0, (struct sockaddr *)&his_addr.si_su, &addrlen) < 0) {
+ syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
+ exit(1);
+ }
+ his_addr.su_len = addrlen;
+ memset((char *)&ctrl_addr, 0, sizeof(ctrl_addr));
+ addrlen = sizeof(ctrl_addr.si_su);
+ if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
+ syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
+ exit(1);
+ }
+ ctrl_addr.su_len = addrlen;
+#ifdef INET6
+ if (his_addr.su_family == AF_INET6
+ && IN6_IS_ADDR_V4MAPPED(&his_addr.su_6addr)) {
+#if 1
+ /*
+ * IPv4 control connection arrived to AF_INET6 socket.
+ * I hate to do this, but this is the easiest solution.
+ *
+ * The assumption is untrue on SIIT environment.
+ */
+ struct sockinet tmp_addr;
+ const int off = sizeof(struct in6_addr) - sizeof(struct in_addr);
+
+ tmp_addr = his_addr;
+ memset(&his_addr, 0, sizeof(his_addr));
+ his_addr.su_family = AF_INET;
+ his_addr.su_len = sizeof(his_addr.si_su.su_sin);
+ memcpy(&his_addr.su_addr, &tmp_addr.su_6addr.s6_addr[off],
+ sizeof(his_addr.su_addr));
+ his_addr.su_port = tmp_addr.su_port;
+
+ tmp_addr = ctrl_addr;
+ memset(&ctrl_addr, 0, sizeof(ctrl_addr));
+ ctrl_addr.su_family = AF_INET;
+ ctrl_addr.su_len = sizeof(ctrl_addr.si_su.su_sin);
+ memcpy(&ctrl_addr.su_addr, &tmp_addr.su_6addr.s6_addr[off],
+ sizeof(ctrl_addr.su_addr));
+ ctrl_addr.su_port = tmp_addr.su_port;
+#else
+ while (fgets(line, sizeof(line), fd) != NULL) {
+ if ((cp = strchr(line, '\n')) != NULL)
+ *cp = '\0';
+ reply(-530, "%s", line);
+ }
+ (void) fflush(stdout);
+ (void) fclose(fd);
+ reply(530,
+ "Connection from IPv4 mapped address is not supported.");
+ exit(0);
+#endif
+
+ mapped = 1;
+ } else
+#endif /* INET6 */
+ mapped = 0;
+#ifdef IP_TOS
+ if (!mapped && his_addr.su_family == AF_INET) {
+ tos = IPTOS_LOWDELAY;
+ if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos,
+ sizeof(int)) < 0)
+ syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+ }
+#endif
+ /* if the hostname hasn't been given, attempt to determine it */
+ if (hostname[0] == '\0') {
+ if (getnameinfo((struct sockaddr *)&ctrl_addr.si_su,
+ ctrl_addr.su_len, hostname, sizeof(hostname), NULL, 0, 0)
+ != 0)
+ (void)gethostname(hostname, sizeof(hostname));
+ hostname[sizeof(hostname) - 1] = '\0';
+ }
+
+ /* set this here so klogin can use it... */
+ (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
+
+ (void) freopen(_PATH_DEVNULL, "w", stderr);
+ (void) signal(SIGPIPE, lostconn);
+ (void) signal(SIGCHLD, SIG_IGN);
+ if (signal(SIGURG, myoob) == SIG_ERR)
+ syslog(LOG_WARNING, "signal: %m");
+
+ /* Try to handle urgent data inline */
+#ifdef SO_OOBINLINE
+ if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_WARNING, "setsockopt: %m");
+#endif
+ /* Set keepalives on the socket to detect dropped connections. */
+#ifdef SO_KEEPALIVE
+ keepalive = 1;
+ if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive,
+ sizeof(int)) < 0)
+ syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+#endif
+
+#ifdef F_SETOWN
+ if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
+ syslog(LOG_WARNING, "fcntl F_SETOWN: %m");
+#endif
+ logremotehost(&his_addr);
+ /*
+ * Set up default state
+ */
+ data = -1;
+ type = TYPE_A;
+ form = FORM_N;
+ stru = STRU_F;
+ mode = MODE_S;
+ tmpline[0] = '\0';
+ hasyyerrored = 0;
+
+#ifdef KERBEROS5
+ kerror = krb5_init_context(&kcontext);
+ if (kerror) {
+ syslog(LOG_ERR, "%s when initializing Kerberos context",
+ error_message(kerror));
+ exit(0);
+ }
+#endif /* KERBEROS5 */
+
+ init_curclass();
+ curclass.timeout = 300; /* 5 minutes, as per login(1) */
+ curclass.type = CLASS_REAL;
+
+ /* If logins are disabled, print out the message. */
+ if (display_file(_PATH_NOLOGIN, 530)) {
+ reply(530, "System not available.");
+ exit(0);
+ }
+ (void)display_file(conffilename(_PATH_FTPWELCOME), 220);
+ /* reply(220,) must follow */
+ if (EMPTYSTR(version))
+ reply(220, "%s FTP server ready.", hostname);
+ else
+ reply(220, "%s FTP server (%s) ready.", hostname, version);
+
+ (void) setjmp(errcatch);
+ ftp_loop();
+ /* NOTREACHED */
+}
+
+static void
+lostconn(int signo)
+{
+
+ if (debug)
+ syslog(LOG_DEBUG, "lost connection");
+ dologout(1);
+}
+
+/*
+ * Save the result of a getpwnam. Used for USER command, since
+ * the data returned must not be clobbered by any other command
+ * (e.g., globbing).
+ */
+static struct passwd *
+sgetpwnam(const char *name)
+{
+ static struct passwd save;
+ struct passwd *p;
+
+ if ((p = getpwnam(name)) == NULL)
+ return (p);
+ if (save.pw_name) {
+ free((char *)save.pw_name);
+ memset(save.pw_passwd, 0, strlen(save.pw_passwd));
+ free((char *)save.pw_passwd);
+ free((char *)save.pw_gecos);
+ free((char *)save.pw_dir);
+ free((char *)save.pw_shell);
+ }
+ save = *p;
+ save.pw_name = xstrdup(p->pw_name);
+ save.pw_passwd = xstrdup(p->pw_passwd);
+ save.pw_gecos = xstrdup(p->pw_gecos);
+ save.pw_dir = xstrdup(p->pw_dir);
+ save.pw_shell = xstrdup(p->pw_shell);
+ return (&save);
+}
+
+static int login_attempts; /* number of failed login attempts */
+static int askpasswd; /* had user command, ask for passwd */
+static char curname[10]; /* current USER name */
+
+/*
+ * USER command.
+ * Sets global passwd pointer pw if named account exists and is acceptable;
+ * sets askpasswd if a PASS command is expected. If logged in previously,
+ * need to reset state. If name is "ftp" or "anonymous", the name is not in
+ * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
+ * If account doesn't exist, ask for passwd anyway. Otherwise, check user
+ * requesting login privileges. Disallow anyone who does not have a standard
+ * shell as returned by getusershell(). Disallow anyone mentioned in the file
+ * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
+ */
+void
+user(const char *name)
+{
+ if (logged_in) {
+ switch (curclass.type) {
+ case CLASS_GUEST:
+ reply(530, "Can't change user from guest login.");
+ return;
+ case CLASS_CHROOT:
+ reply(530, "Can't change user from chroot user.");
+ return;
+ case CLASS_REAL:
+ if (dropprivs) {
+ reply(530, "Can't change user.");
+ return;
+ }
+ end_login();
+ break;
+ default:
+ abort();
+ }
+ }
+
+#if defined(KERBEROS)
+ kdestroy();
+#endif
+#if defined(KERBEROS5)
+ k5destroy();
+#endif
+
+ curclass.type = CLASS_REAL;
+ if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
+ /* need `pw' setup for checkaccess() and checkuser () */
+ if ((pw = sgetpwnam("ftp")) == NULL)
+ reply(530, "User %s unknown.", name);
+ else if (! checkaccess("ftp") || ! checkaccess("anonymous"))
+ reply(530, "User %s access denied.", name);
+ else {
+ curclass.type = CLASS_GUEST;
+ askpasswd = 1;
+ reply(331,
+ "Guest login ok, type your name as password.");
+ }
+ if (!askpasswd && logging)
+ syslog(LOG_NOTICE,
+ "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
+ return;
+ }
+
+ pw = sgetpwnam(name);
+ if (logging)
+ strlcpy(curname, name, sizeof(curname));
+
+#ifdef SKEY
+ if (skey_haskey(name) == 0) {
+ const char *myskey;
+
+ myskey = skey_keyinfo(name);
+ reply(331, "Password [%s] required for %s.",
+ myskey ? myskey : "error getting challenge", name);
+ } else
+#endif
+ reply(331, "Password required for %s.", name);
+
+ askpasswd = 1;
+ /*
+ * Delay before reading passwd after first failed
+ * attempt to slow down passwd-guessing programs.
+ */
+ if (login_attempts)
+ sleep((unsigned) login_attempts);
+}
+
+/*
+ * Determine whether something is to happen (allow access, chroot)
+ * for a user. Each line is a shell-style glob followed by
+ * `yes' or `no'.
+ *
+ * For backward compatability, `allow' and `deny' are synonymns
+ * for `yes' and `no', respectively.
+ *
+ * Each glob is matched against the username in turn, and the first
+ * match found is used. If no match is found, the result is the
+ * argument `def'. If a match is found but without and explicit
+ * `yes'/`no', the result is the opposite of def.
+ *
+ * If the file doesn't exist at all, the result is the argument
+ * `nofile'
+ *
+ * Any line starting with `#' is considered a comment and ignored.
+ *
+ * Returns 0 if the user is denied, or 1 if they are allowed.
+ *
+ * NOTE: needs struct passwd *pw setup before use.
+ */
+static int
+checkuser(const char *fname, const char *name, int def, int nofile,
+ char **retclass)
+{
+ FILE *fd;
+ int retval;
+ char *glob, *perm, *class, *buf, *p;
+ size_t len, line;
+
+ retval = def;
+ if (retclass != NULL)
+ *retclass = NULL;
+ if ((fd = fopen(conffilename(fname), "r")) == NULL)
+ return nofile;
+
+ line = 0;
+ for (;
+ (buf = fparseln(fd, &len, &line, NULL, FPARSELN_UNESCCOMM |
+ FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL;
+ free(buf), buf = NULL) {
+ glob = perm = class = NULL;
+ p = buf;
+ if (len < 1)
+ continue;
+ if (p[len - 1] == '\n')
+ p[--len] = '\0';
+ if (EMPTYSTR(p))
+ continue;
+
+ NEXTWORD(p, glob);
+ NEXTWORD(p, perm);
+ NEXTWORD(p, class);
+ if (EMPTYSTR(glob))
+ continue;
+ if (!EMPTYSTR(class)) {
+ if (strcasecmp(class, "all") == 0 ||
+ strcasecmp(class, "none") == 0) {
+ syslog(LOG_WARNING,
+ "%s line %d: illegal user-defined class `%s' - skipping entry",
+ fname, (int)line, class);
+ continue;
+ }
+ }
+
+ /* have a host specifier */
+ if ((p = strchr(glob, '@')) != NULL) {
+ unsigned long net, mask, addr;
+ int bits;
+
+ *p++ = '\0';
+ /* check against network or CIDR */
+ if (isdigit(*p) &&
+ (bits = inet_net_pton(AF_INET, p,
+ &net, sizeof(net))) != -1) {
+ net = ntohl(net);
+ mask = 0xffffffffU << (32 - bits);
+ addr = ntohl(his_addr.su_addr.s_addr);
+ if ((addr & mask) != net)
+ continue;
+
+ /* check against hostname glob */
+ } else if (fnmatch(p, remotehost, 0) != 0)
+ continue;
+ }
+
+ /* have a group specifier */
+ if ((p = strchr(glob, ':')) != NULL) {
+ gid_t *groups, *ng;
+ int gsize, i, found;
+
+ *p++ = '\0';
+ groups = NULL;
+ gsize = 16;
+ do {
+ ng = realloc(groups, gsize * sizeof(gid_t));
+ if (ng == NULL)
+ fatal(
+ "Local resource failure: realloc");
+ groups = ng;
+ } while (getgrouplist(pw->pw_name, pw->pw_gid,
+ groups, &gsize) == -1);
+ found = 0;
+ for (i = 0; i < gsize; i++) {
+ struct group *g;
+
+ if ((g = getgrgid(groups[i])) == NULL)
+ continue;
+ if (fnmatch(p, g->gr_name, 0) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ free(groups);
+ if (!found)
+ continue;
+ }
+
+ /* check against username glob */
+ if (fnmatch(glob, name, 0) != 0)
+ continue;
+
+ if (perm != NULL &&
+ ((strcasecmp(perm, "allow") == 0) ||
+ (strcasecmp(perm, "yes") == 0)))
+ retval = 1;
+ else if (perm != NULL &&
+ ((strcasecmp(perm, "deny") == 0) ||
+ (strcasecmp(perm, "no") == 0)))
+ retval = 0;
+ else
+ retval = !def;
+ if (!EMPTYSTR(class) && retclass != NULL)
+ *retclass = xstrdup(class);
+ free(buf);
+ break;
+ }
+ (void) fclose(fd);
+ return (retval);
+}
+
+/*
+ * Check if user is allowed by /etc/ftpusers
+ * returns 1 for yes, 0 for no
+ *
+ * NOTE: needs struct passwd *pw setup (for checkuser())
+ */
+static int
+checkaccess(const char *name)
+{
+
+ return (checkuser(_PATH_FTPUSERS, name, 1, 0, NULL));
+}
+
+/*
+ * Terminate login as previous user (if any), resetting state;
+ * used when USER command is given or login fails.
+ */
+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 */
+ show_chdir_messages(-1); /* flush chdir cache */
+ if (pw != NULL && pw->pw_passwd != NULL)
+ memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
+ pw = NULL;
+ logged_in = 0;
+ quietmessages = 0;
+ gidcount = 0;
+ curclass.type = CLASS_REAL;
+ (void) seteuid((uid_t)0);
+}
+
+void
+pass(const char *passwd)
+{
+ int rval;
+ const char *cp, *shell;
+ char *class, root[MAXPATHLEN];
+ char *p;
+ int len;
+
+ class = NULL;
+ if (logged_in || askpasswd == 0) {
+ reply(503, "Login with USER first.");
+ return;
+ }
+ askpasswd = 0;
+ if (curclass.type != CLASS_GUEST) {
+ /* "ftp" is the only account allowed with no password */
+ if (pw == NULL) {
+ rval = 1; /* failure below */
+ goto skip;
+ }
+#if defined(KERBEROS)
+ if (klogin(pw, "", hostname, (char *)passwd) == 0) {
+ rval = 0;
+ goto skip;
+ }
+#endif
+#if defined(KERBEROS5)
+ if (k5login(pw, "", hostname, (char *)passwd) == 0) {
+ rval = 0;
+ goto skip;
+ }
+#endif
+#ifdef SKEY
+ if (skey_haskey(pw->pw_name) == 0) {
+ char *p;
+ int r;
+
+ p = xstrdup(passwd);
+ r = skey_passcheck(pw->pw_name, p);
+ free(p);
+ if (r != -1) {
+ rval = 0;
+ goto skip;
+ }
+ }
+#endif
+ if (!sflag)
+ rval = checkpassword(pw, passwd);
+ else
+ rval = 1;
+
+ skip:
+
+ /*
+ * If rval > 0, the user failed the authentication check
+ * above. If rval == 0, either Kerberos or local
+ * authentication succeeded.
+ */
+ if (rval) {
+ reply(530, "%s", rval == 2 ? "Password expired." :
+ "Login incorrect.");
+ if (logging) {
+ syslog(LOG_NOTICE,
+ "FTP LOGIN FAILED FROM %s", remotehost);
+ syslog(LOG_AUTHPRIV | LOG_NOTICE,
+ "FTP LOGIN FAILED FROM %s, %s",
+ remotehost, curname);
+ }
+ pw = NULL;
+ if (login_attempts++ >= 5) {
+ syslog(LOG_NOTICE,
+ "repeated login failures from %s",
+ remotehost);
+ exit(0);
+ }
+ return;
+ }
+ }
+
+ /* password ok; see if anything else prevents login */
+ if (! checkuser(_PATH_FTPUSERS, pw->pw_name, 1, 0, &class)) {
+ reply(530, "User %s may not use FTP.", pw->pw_name);
+ if (logging)
+ syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
+ remotehost, pw->pw_name);
+ goto bad;
+ }
+ /* if not guest user, check for valid shell */
+ if ((shell = pw->pw_shell) == NULL || *shell == 0)
+ shell = _PATH_BSHELL;
+ while ((cp = getusershell()) != NULL)
+ if (strcmp(cp, shell) == 0)
+ break;
+ endusershell();
+ if (cp == NULL && curclass.type != CLASS_GUEST) {
+ reply(530, "User %s may not use FTP.", pw->pw_name);
+ if (logging)
+ syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
+ remotehost, pw->pw_name);
+ goto bad;
+ }
+
+ login_attempts = 0; /* this time successful */
+ if (setegid((gid_t)pw->pw_gid) < 0) {
+ reply(550, "Can't set gid.");
+ goto bad;
+ }
+ (void) initgroups(pw->pw_name, pw->pw_gid);
+ /* 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 */
+
+ logged_in = 1;
+
+ /* check user in /etc/ftpchroot */
+ if (checkuser(_PATH_FTPCHROOT, pw->pw_name, 0, 0, NULL)) {
+ if (curclass.type == CLASS_GUEST) {
+ syslog(LOG_NOTICE,
+ "Can't change guest user to chroot class; remove entry in %s",
+ _PATH_FTPCHROOT);
+ exit(1);
+ }
+ curclass.type = CLASS_CHROOT;
+ }
+ if (class == NULL) {
+ switch (curclass.type) {
+ case CLASS_GUEST:
+ class = xstrdup("guest");
+ break;
+ case CLASS_CHROOT:
+ class = xstrdup("chroot");
+ break;
+ case CLASS_REAL:
+ class = xstrdup("real");
+ break;
+ default:
+ syslog(LOG_ERR, "unknown curclass.type %d; aborting",
+ curclass.type);
+ abort();
+ }
+ }
+
+ /* parse ftpd.conf, setting up various parameters */
+ parse_conf(class);
+ connections = 1;
+ if (dopidfile)
+ count_users();
+ if (curclass.limit != -1 && connections > curclass.limit) {
+ if (! EMPTYSTR(curclass.limitfile))
+ (void)display_file(conffilename(curclass.limitfile),
+ 530);
+ reply(530,
+ "User %s access denied, connection limit of %d reached.",
+ pw->pw_name, 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);
+ goto bad;
+ }
+
+ homedir[0] = '/';
+ switch (curclass.type) {
+ case CLASS_GUEST:
+ /*
+ * We MUST do a chdir() after the chroot. Otherwise
+ * the old current directory will be accessible as "."
+ * outside the new root!
+ */
+ format_path(root,
+ curclass.chroot ? curclass.chroot :
+ anondir ? anondir :
+ pw->pw_dir);
+ format_path(homedir,
+ curclass.homedir ? curclass.homedir :
+ "/");
+ if (EMPTYSTR(homedir))
+ homedir[0] = '/';
+ if (EMPTYSTR(root) || chroot(root) < 0) {
+ syslog(LOG_NOTICE,
+ "GUEST user %s: can't chroot to %s: %m",
+ pw->pw_name, root);
+ goto bad_guest;
+ }
+ if (chdir(homedir) < 0) {
+ syslog(LOG_NOTICE,
+ "GUEST user %s: can't chdir to %s: %m",
+ pw->pw_name, homedir);
+ bad_guest:
+ reply(550, "Can't set guest privileges.");
+ goto bad;
+ }
+ break;
+ case CLASS_CHROOT:
+ format_path(root,
+ curclass.chroot ? curclass.chroot :
+ pw->pw_dir);
+ format_path(homedir,
+ curclass.homedir ? curclass.homedir :
+ "/");
+ if (EMPTYSTR(homedir))
+ homedir[0] = '/';
+ if (EMPTYSTR(root) || chroot(root) < 0) {
+ syslog(LOG_NOTICE,
+ "CHROOT user %s: can't chroot to %s: %m",
+ pw->pw_name, root);
+ goto bad_chroot;
+ }
+ if (chdir(homedir) < 0) {
+ syslog(LOG_NOTICE,
+ "CHROOT user %s: can't chdir to %s: %m",
+ pw->pw_name, homedir);
+ bad_chroot:
+ reply(550, "Can't change root.");
+ goto bad;
+ }
+ break;
+ case CLASS_REAL:
+ /* only chroot REAL if explictly requested */
+ if (! EMPTYSTR(curclass.chroot)) {
+ format_path(root, curclass.chroot);
+ if (EMPTYSTR(root) || chroot(root) < 0) {
+ syslog(LOG_NOTICE,
+ "REAL user %s: can't chroot to %s: %m",
+ pw->pw_name, root);
+ goto bad_chroot;
+ }
+ }
+ format_path(homedir,
+ curclass.homedir ? curclass.homedir :
+ pw->pw_dir);
+ if (EMPTYSTR(homedir) || chdir(homedir) < 0) {
+ if (chdir("/") < 0) {
+ syslog(LOG_NOTICE,
+ "REAL user %s: can't chdir to %s: %m",
+ pw->pw_name,
+ !EMPTYSTR(homedir) ? homedir : "/");
+ reply(530,
+ "User %s: can't change directory to %s.",
+ pw->pw_name,
+ !EMPTYSTR(homedir) ? homedir : "/");
+ goto bad;
+ } else {
+ reply(-230,
+ "No directory! Logging in with home=/");
+ homedir[0] = '/';
+ }
+ }
+ break;
+ }
+#if HAVE_SETLOGIN
+ setlogin(pw->pw_name);
+#endif
+ if (dropprivs ||
+ (curclass.type != CLASS_REAL &&
+ ntohs(ctrl_addr.su_port) > IPPORT_RESERVED + 1)) {
+ dropprivs++;
+ if (setgid((gid_t)pw->pw_gid) < 0) {
+ reply(550, "Can't set gid.");
+ goto bad;
+ }
+ if (setuid((uid_t)pw->pw_uid) < 0) {
+ reply(550, "Can't set uid.");
+ goto bad;
+ }
+ } else {
+ if (seteuid((uid_t)pw->pw_uid) < 0) {
+ reply(550, "Can't set uid.");
+ 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);
+
+ if (curclass.type == CLASS_GUEST && passwd[0] == '-')
+ quietmessages = 1;
+
+ /*
+ * Display a login message, if it exists.
+ * N.B. reply(230,) must follow the message.
+ */
+ (void)display_file(conffilename(curclass.motd), 230);
+ show_chdir_messages(230);
+ if (curclass.type == CLASS_GUEST) {
+ char *p;
+
+ reply(230, "Guest login ok, access restrictions apply.");
+#if HAVE_SETPROCTITLE
+ snprintf(proctitle, sizeof(proctitle),
+ "%s: anonymous/%.*s", remotehost,
+ (int) (sizeof(proctitle) - sizeof(remotehost) -
+ sizeof(": anonymous/")), passwd);
+ setproctitle("%s", proctitle);
+#endif /* HAVE_SETPROCTITLE */
+ if (logging)
+ syslog(LOG_INFO,
+ "ANONYMOUS FTP LOGIN FROM %s, %s (class: %s, type: %s)",
+ remotehost, passwd,
+ curclass.classname, CURCLASSTYPE);
+ /* store guest password reply into pw_passwd */
+ REASSIGN(pw->pw_passwd, xstrdup(passwd));
+ for (p = pw->pw_passwd; *p; p++)
+ if (!isgraph(*p))
+ *p = '_';
+ } else {
+ reply(230, "User %s logged in.", pw->pw_name);
+#if HAVE_SETPROCTITLE
+ snprintf(proctitle, sizeof(proctitle),
+ "%s: %s", remotehost, pw->pw_name);
+ setproctitle("%s", proctitle);
+#endif /* HAVE_SETPROCTITLE */
+ if (logging)
+ syslog(LOG_INFO,
+ "FTP LOGIN FROM %s as %s (class: %s, type: %s)",
+ remotehost, pw->pw_name,
+ curclass.classname, CURCLASSTYPE);
+ }
+ (void) umask(curclass.umask);
+ goto cleanuppass;
+
+ bad:
+ /* Forget all about it... */
+ end_login();
+
+ cleanuppass:
+ if (class)
+ free(class);
+}
+
+void
+retrieve(char *argv[], const char *name)
+{
+ FILE *fin, *dout;
+ struct stat st;
+ int (*closefunc)(FILE *) = NULL;
+ int log, sendrv, closerv, stderrfd, isconversion, isdata, isls;
+ struct timeval start, finish, td, *tdp;
+ const char *dispname;
+
+ sendrv = closerv = stderrfd = -1;
+ isconversion = isdata = isls = log = 0;
+ tdp = NULL;
+ dispname = name;
+ fin = dout = NULL;
+ if (argv == NULL) { /* if not running a command ... */
+ log = 1;
+ isdata = 1;
+ fin = fopen(name, "r");
+ closefunc = fclose;
+ if (fin == NULL) /* doesn't exist?; try a conversion */
+ argv = do_conversion(name);
+ if (argv != NULL) {
+ isconversion++;
+ syslog(LOG_DEBUG, "get command: '%s' on '%s'",
+ argv[0], name);
+ }
+ }
+ if (argv != NULL) {
+ char temp[MAXPATHLEN];
+
+ if (strcmp(argv[0], INTERNAL_LS) == 0) {
+ isls = 1;
+ stderrfd = -1;
+ } else {
+ (void)snprintf(temp, sizeof(temp), "%s", TMPFILE);
+ stderrfd = mkstemp(temp);
+ if (stderrfd != -1)
+ (void)unlink(temp);
+ }
+ dispname = argv[0];
+ fin = ftpd_popen(argv, "r", stderrfd);
+ closefunc = ftpd_pclose;
+ st.st_size = -1;
+ st.st_blksize = BUFSIZ;
+ }
+ if (fin == NULL) {
+ if (errno != 0) {
+ perror_reply(550, dispname);
+ if (log)
+ logxfer("get", -1, name, NULL, NULL,
+ strerror(errno));
+ }
+ goto cleanupretrieve;
+ }
+ byte_count = -1;
+ if (argv == NULL
+ && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
+ reply(550, "%s: not a plain file.", dispname);
+ goto done;
+ }
+ if (restart_point) {
+ if (type == TYPE_A) {
+ off_t i;
+ int c;
+
+ for (i = 0; i < restart_point; i++) {
+ if ((c=getc(fin)) == EOF) {
+ perror_reply(550, dispname);
+ goto done;
+ }
+ if (c == '\n')
+ i++;
+ }
+ } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
+ perror_reply(550, dispname);
+ goto done;
+ }
+ }
+ dout = dataconn(dispname, st.st_size, "w");
+ if (dout == NULL)
+ goto done;
+
+ (void)gettimeofday(&start, NULL);
+ sendrv = send_data(fin, dout, st.st_blksize, isdata);
+ (void)gettimeofday(&finish, NULL);
+ (void) fclose(dout); /* close now to affect timing stats */
+ dout = NULL;
+ timersub(&finish, &start, &td);
+ tdp = &td;
+ done:
+ if (log)
+ logxfer("get", byte_count, name, NULL, tdp, NULL);
+ closerv = (*closefunc)(fin);
+ if (sendrv == 0) {
+ FILE *err;
+ struct stat sb;
+
+ if (!isls && argv != NULL && closerv != 0) {
+ reply(-226,
+ "Command returned an exit status of %d",
+ closerv);
+ if (isconversion)
+ syslog(LOG_WARNING,
+ "retrieve command: '%s' returned %d",
+ argv[0], closerv);
+ }
+ if (!isls && argv != NULL && stderrfd != -1 &&
+ (fstat(stderrfd, &sb) == 0) && sb.st_size > 0 &&
+ ((err = fdopen(stderrfd, "r")) != NULL)) {
+ char *cp, line[LINE_MAX];
+
+ reply(-226, "Command error messages:");
+ rewind(err);
+ while (fgets(line, sizeof(line), err) != NULL) {
+ if ((cp = strchr(line, '\n')) != NULL)
+ *cp = '\0';
+ reply(0, " %s", line);
+ }
+ (void) fflush(stdout);
+ (void) fclose(err);
+ /* a reply(226,) must follow */
+ }
+ reply(226, "Transfer complete.");
+ }
+ cleanupretrieve:
+ closedataconn(dout);
+ if (stderrfd != -1)
+ (void)close(stderrfd);
+ if (isconversion)
+ free(argv);
+}
+
+void
+store(const char *name, const char *mode, int unique)
+{
+ FILE *fout, *din;
+ struct stat st;
+ int (*closefunc)(FILE *);
+ struct timeval start, finish, td, *tdp;
+ char *desc;
+
+ din = NULL;
+ desc = (*mode == 'w') ? "put" : "append";
+ if (unique && stat(name, &st) == 0 &&
+ (name = gunique(name)) == NULL) {
+ logxfer(desc, -1, name, NULL, NULL,
+ "cannot create unique file");
+ goto cleanupstore;
+ }
+
+ if (restart_point)
+ mode = "r+";
+ fout = fopen(name, mode);
+ closefunc = fclose;
+ tdp = NULL;
+ if (fout == NULL) {
+ perror_reply(553, name);
+ logxfer(desc, -1, name, NULL, NULL, strerror(errno));
+ goto cleanupstore;
+ }
+ byte_count = -1;
+ if (restart_point) {
+ if (type == TYPE_A) {
+ off_t i;
+ int c;
+
+ for (i = 0; i < restart_point; i++) {
+ if ((c=getc(fout)) == EOF) {
+ perror_reply(550, name);
+ goto done;
+ }
+ if (c == '\n')
+ i++;
+ }
+ /*
+ * We must do this seek to "current" position
+ * because we are changing from reading to
+ * writing.
+ */
+ if (fseek(fout, 0L, SEEK_CUR) < 0) {
+ perror_reply(550, name);
+ goto done;
+ }
+ } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
+ perror_reply(550, name);
+ goto done;
+ }
+ }
+ din = dataconn(name, (off_t)-1, "r");
+ if (din == NULL)
+ goto done;
+ (void)gettimeofday(&start, NULL);
+ if (receive_data(din, fout) == 0) {
+ if (unique)
+ reply(226, "Transfer complete (unique file name:%s).",
+ name);
+ else
+ reply(226, "Transfer complete.");
+ }
+ (void)gettimeofday(&finish, NULL);
+ (void) fclose(din); /* close now to affect timing stats */
+ din = NULL;
+ timersub(&finish, &start, &td);
+ tdp = &td;
+ done:
+ logxfer(desc, byte_count, name, NULL, tdp, NULL);
+ (*closefunc)(fout);
+ cleanupstore:
+ closedataconn(din);
+}
+
+static FILE *
+getdatasock(const char *mode)
+{
+ int on, s, t, tries;
+ in_port_t port;
+
+ on = 1;
+ if (data >= 0)
+ return (fdopen(data, mode));
+ if (! dropprivs)
+ (void) seteuid((uid_t)0);
+ s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
+ if (s < 0)
+ goto bad;
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+ (char *) &on, sizeof(on)) < 0)
+ goto bad;
+ if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
+ (char *) &on, sizeof(on)) < 0)
+ goto bad;
+ /* anchor socket to avoid multi-homing problems */
+ data_source = ctrl_addr;
+ /*
+ * By default source port for PORT connctions is
+ * ctrlport-1 (see RFC959 section 5.2).
+ * However, if privs have been dropped and that
+ * would be < IPPORT_RESERVED, use a random port
+ * instead.
+ */
+ if (dataport)
+ port = dataport;
+ else
+ port = ntohs(ctrl_addr.su_port) - 1;
+ if (dropprivs && port < IPPORT_RESERVED)
+ port = 0; /* use random port */
+ data_source.su_port = htons(port);
+
+ for (tries = 1; ; tries++) {
+ if (bind(s, (struct sockaddr *)&data_source.si_su,
+ data_source.su_len) >= 0)
+ break;
+ if (errno != EADDRINUSE || tries > 10)
+ goto bad;
+ sleep(tries);
+ }
+ if (! dropprivs)
+ (void) seteuid((uid_t)pw->pw_uid);
+#ifdef IP_TOS
+ if (!mapped && ctrl_addr.su_family == AF_INET) {
+ on = IPTOS_THROUGHPUT;
+ if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
+ sizeof(int)) < 0)
+ syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+ }
+#endif
+ return (fdopen(s, mode));
+ bad:
+ /* Return the real value of errno (close may change it) */
+ t = errno;
+ if (! dropprivs)
+ (void) seteuid((uid_t)pw->pw_uid);
+ (void) close(s);
+ errno = t;
+ return (NULL);
+}
+
+FILE *
+dataconn(const char *name, off_t size, const char *mode)
+{
+ char sizebuf[32];
+ FILE *file;
+ int retry = 0, tos, keepalive;
+
+ file_size = size;
+ byte_count = 0;
+ if (size != (off_t) -1)
+ (void)snprintf(sizebuf, sizeof(sizebuf), " (" LLF " byte%s)",
+ (LLT)size, PLURAL(size));
+ else
+ sizebuf[0] = '\0';
+ if (pdata >= 0) {
+ struct sockinet from;
+ int s, fromlen = sizeof(from.su_len);
+
+ (void) alarm(curclass.timeout);
+ s = accept(pdata, (struct sockaddr *)&from.si_su, &fromlen);
+ (void) alarm(0);
+ if (s < 0) {
+ reply(425, "Can't open data connection.");
+ (void) close(pdata);
+ pdata = -1;
+ return (NULL);
+ }
+ (void) close(pdata);
+ pdata = s;
+ switch (from.su_family) {
+ case AF_INET:
+#ifdef IP_TOS
+ if (!mapped) {
+ tos = IPTOS_THROUGHPUT;
+ (void) setsockopt(s, IPPROTO_IP, IP_TOS,
+ (char *)&tos, sizeof(int));
+ }
+ break;
+#endif
+ }
+ /* Set keepalives on the socket to detect dropped conns. */
+#ifdef SO_KEEPALIVE
+ keepalive = 1;
+ (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&keepalive, sizeof(int));
+#endif
+ reply(150, "Opening %s mode data connection for '%s'%s.",
+ type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+ return (fdopen(pdata, mode));
+ }
+ if (data >= 0) {
+ reply(125, "Using existing data connection for '%s'%s.",
+ name, sizebuf);
+ usedefault = 1;
+ return (fdopen(data, mode));
+ }
+ if (usedefault)
+ data_dest = his_addr;
+ usedefault = 1;
+ file = getdatasock(mode);
+ if (file == NULL) {
+ char hbuf[NI_MAXHOST];
+ char pbuf[NI_MAXSERV];
+
+ if (getnameinfo((struct sockaddr *)&data_source.si_su,
+ data_source.su_len, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ strlcpy(hbuf, "?", sizeof(hbuf));
+ reply(425, "Can't create data socket (%s,%s): %s.",
+ hbuf, pbuf, strerror(errno));
+ return (NULL);
+ }
+ data = fileno(file);
+ while (connect(data, (struct sockaddr *)&data_dest.si_su,
+ data_dest.su_len) < 0) {
+ if (errno == EADDRINUSE && retry < swaitmax) {
+ sleep((unsigned) swaitint);
+ retry += swaitint;
+ continue;
+ }
+ perror_reply(425, "Can't build data connection");
+ (void) fclose(file);
+ data = -1;
+ return (NULL);
+ }
+ reply(150, "Opening %s mode data connection for '%s'%s.",
+ type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+ return (file);
+}
+
+void
+closedataconn(FILE *fd)
+{
+
+ if (fd != NULL)
+ (void)fclose(fd);
+ data = -1;
+ if (pdata >= 0)
+ (void)close(pdata);
+ pdata = -1;
+}
+
+/*
+ * Tranfer the contents of "instr" to "outstr" peer using the appropriate
+ * 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)
+{
+ int c, filefd, netfd, rval;
+ char *buf;
+
+ transflag = 1;
+ rval = -1;
+ buf = NULL;
+ if (setjmp(urgcatch))
+ goto cleanup_send_data;
+
+ switch (type) {
+
+ case TYPE_A:
+ /* XXXLUKEM: rate limit ascii send (get) */
+ (void) alarm(curclass.timeout);
+ while ((c = getc(instr)) != EOF) {
+ byte_count++;
+ if (c == '\n') {
+ if (ferror(outstr))
+ goto data_err;
+ (void) putc('\r', outstr);
+ if (isdata) {
+ total_data_out++;
+ total_data++;
+ }
+ total_bytes_out++;
+ total_bytes++;
+ }
+ (void) putc(c, outstr);
+ if (isdata) {
+ total_data_out++;
+ total_data++;
+ }
+ total_bytes_out++;
+ total_bytes++;
+ if ((byte_count % 4096) == 0)
+ (void) alarm(curclass.timeout);
+ }
+ (void) alarm(0);
+ fflush(outstr);
+ if (ferror(instr))
+ goto file_err;
+ if (ferror(outstr))
+ goto data_err;
+ rval = 0;
+ goto cleanup_send_data;
+
+ 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;
+
+ (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)
+ goto file_err;
+ rval = 0;
+ goto cleanup_send_data;
+
+ default:
+ reply(550, "Unimplemented TYPE %d in send_data", type);
+ goto cleanup_send_data;
+ }
+
+ data_err:
+ (void) alarm(0);
+ perror_reply(426, "Data connection");
+ goto cleanup_send_data;
+
+ file_err:
+ (void) alarm(0);
+ perror_reply(551, "Error on input file");
+ /* FALLTHROUGH */
+
+ cleanup_send_data:
+ (void) alarm(0);
+ transflag = 0;
+ if (buf)
+ free(buf);
+ if (isdata) {
+ total_files_out++;
+ total_files++;
+ }
+ total_xfers_out++;
+ total_xfers++;
+ return (rval);
+}
+
+/*
+ * Transfer data from peer to "outstr" using the appropriate encapulation of
+ * the data subject to Mode, Structure, and Type.
+ *
+ * N.B.: Form isn't handled.
+ */
+static int
+receive_data(FILE *instr, FILE *outstr)
+{
+ int c, bare_lfs, netfd, filefd, rval;
+ off_t byteswritten;
+ char buf[BUFSIZ];
+#ifdef __GNUC__
+ (void) &bare_lfs;
+#endif
+
+ bare_lfs = 0;
+ transflag = 1;
+ rval = -1;
+ byteswritten = 0;
+ if (setjmp(urgcatch))
+ goto cleanup_recv_data;
+
+#define FILESIZECHECK(x) \
+ do { \
+ if (curclass.maxfilesize != -1 && \
+ (x) > curclass.maxfilesize) { \
+ errno = EFBIG; \
+ goto file_err; \
+ } \
+ } while (0)
+
+ switch (type) {
+
+ case TYPE_I:
+ case TYPE_L:
+ netfd = fileno(instr);
+ filefd = fileno(outstr);
+ (void) alarm(curclass.timeout);
+ if (curclass.rateput) {
+ while (1) {
+ int d;
+ struct timeval then, now, td;
+ off_t bufrem;
+
+ (void)gettimeofday(&then, NULL);
+ errno = c = d = 0;
+ for (bufrem = curclass.rateput; bufrem > 0; ) {
+ if ((c = read(netfd, buf,
+ MIN(sizeof(buf), bufrem))) <= 0)
+ goto recvdone;
+ FILESIZECHECK(byte_count + c);
+ if ((d = write(filefd, buf, c)) != c)
+ goto file_err;
+ (void) alarm(curclass.timeout);
+ bufrem -= c;
+ byte_count += c;
+ total_data_in += c;
+ total_data += c;
+ total_bytes_in += c;
+ total_bytes += c;
+ }
+ (void)gettimeofday(&now, NULL);
+ timersub(&now, &then, &td);
+ if (td.tv_sec == 0)
+ usleep(1000000 - td.tv_usec);
+ }
+ } else {
+ while ((c = read(netfd, buf, sizeof(buf))) > 0) {
+ FILESIZECHECK(byte_count + c);
+ if (write(filefd, buf, c) != c)
+ goto file_err;
+ (void) alarm(curclass.timeout);
+ byte_count += c;
+ total_data_in += c;
+ total_data += c;
+ total_bytes_in += c;
+ total_bytes += c;
+ }
+ }
+ recvdone:
+ if (c < 0)
+ goto data_err;
+ rval = 0;
+ goto cleanup_recv_data;
+
+ case TYPE_E:
+ reply(553, "TYPE E not implemented.");
+ goto cleanup_recv_data;
+
+ case TYPE_A:
+ (void) alarm(curclass.timeout);
+ /* XXXLUKEM: rate limit ascii receive (put) */
+ while ((c = getc(instr)) != EOF) {
+ byte_count++;
+ total_data_in++;
+ total_data++;
+ total_bytes_in++;
+ total_bytes++;
+ if ((byte_count % 4096) == 0)
+ (void) alarm(curclass.timeout);
+ if (c == '\n')
+ bare_lfs++;
+ while (c == '\r') {
+ if (ferror(outstr))
+ goto data_err;
+ if ((c = getc(instr)) != '\n') {
+ byte_count++;
+ total_data_in++;
+ total_data++;
+ total_bytes_in++;
+ total_bytes++;
+ if ((byte_count % 4096) == 0)
+ (void) alarm(curclass.timeout);
+ byteswritten++;
+ FILESIZECHECK(byteswritten);
+ (void) putc ('\r', outstr);
+ if (c == '\0' || c == EOF)
+ goto contin2;
+ }
+ }
+ byteswritten++;
+ FILESIZECHECK(byteswritten);
+ (void) putc(c, outstr);
+ contin2: ;
+ }
+ (void) alarm(0);
+ fflush(outstr);
+ if (ferror(instr))
+ goto data_err;
+ if (ferror(outstr))
+ goto file_err;
+ if (bare_lfs) {
+ reply(-226,
+ "WARNING! %d bare linefeeds received in ASCII mode",
+ bare_lfs);
+ reply(0, "File may not have transferred correctly.");
+ }
+ rval = 0;
+ goto cleanup_recv_data;
+
+ default:
+ reply(550, "Unimplemented TYPE %d in receive_data", type);
+ goto cleanup_recv_data;
+ }
+#undef FILESIZECHECK
+
+ data_err:
+ (void) alarm(0);
+ perror_reply(426, "Data Connection");
+ goto cleanup_recv_data;
+
+ file_err:
+ (void) alarm(0);
+ perror_reply(452, "Error writing file");
+ goto cleanup_recv_data;
+
+ cleanup_recv_data:
+ (void) alarm(0);
+ transflag = 0;
+ total_files_in++;
+ total_files++;
+ total_xfers_in++;
+ total_xfers++;
+ return (rval);
+}
+
+void
+statcmd(void)
+{
+ struct sockinet *su = NULL;
+ static char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+ u_char *a, *p;
+ int ispassive, af;
+ off_t otbi, otbo, otb;
+
+ a = p = (u_char *)NULL;
+
+ reply(-211, "%s FTP server status:", hostname);
+ reply(0, "Version: %s", EMPTYSTR(version) ? "<suppressed>" : version);
+ hbuf[0] = '\0';
+ if (!getnameinfo((struct sockaddr *)&his_addr.si_su, his_addr.su_len,
+ hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST)
+ && strcmp(remotehost, hbuf) != 0)
+ reply(0, "Connected to %s (%s)", remotehost, hbuf);
+ else
+ reply(0, "Connected to %s", remotehost);
+
+ if (logged_in) {
+ if (curclass.type == CLASS_GUEST)
+ reply(0, "Logged in anonymously");
+ else
+ reply(0, "Logged in as %s%s", pw->pw_name,
+ curclass.type == CLASS_CHROOT ? " (chroot)" : "");
+ } else if (askpasswd)
+ reply(0, "Waiting for password");
+ else
+ reply(0, "Waiting for user name");
+ cprintf(stdout, " TYPE: %s", typenames[type]);
+ if (type == TYPE_A || type == TYPE_E)
+ cprintf(stdout, ", FORM: %s", formnames[form]);
+ if (type == TYPE_L) {
+#if NBBY == 8
+ cprintf(stdout, " %d", NBBY);
+#else
+ /* XXX: `bytesize' needs to be defined in this case */
+ cprintf(stdout, " %d", bytesize);
+#endif
+ }
+ cprintf(stdout, "; STRUcture: %s; transfer MODE: %s\r\n",
+ strunames[stru], modenames[mode]);
+ ispassive = 0;
+ if (data != -1) {
+ reply(0, "Data connection open");
+ su = NULL;
+ } else if (pdata != -1) {
+ reply(0, "in Passive mode");
+ if (curclass.advertise.su_len != 0)
+ su = &curclass.advertise;
+ else
+ su = &pasv_addr;
+ ispassive = 1;
+ goto printaddr;
+ } else if (usedefault == 0) {
+ if (epsvall) {
+ reply(0, "EPSV only mode (EPSV ALL)");
+ goto epsvonly;
+ }
+ su = (struct sockinet *)&data_dest;
+ printaddr:
+ /* PASV/PORT */
+ if (su->su_family == AF_INET) {
+ a = (u_char *) &su->su_addr;
+ p = (u_char *) &su->su_port;
+#define UC(b) (((int) b) & 0xff)
+ reply(0, "%s (%d,%d,%d,%d,%d,%d)",
+ ispassive ? "PASV" : "PORT" ,
+ UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+ UC(p[0]), UC(p[1]));
+ }
+
+ /* LPSV/LPRT */
+ {
+ int alen, af, i;
+
+ alen = 0;
+ switch (su->su_family) {
+ case AF_INET:
+ a = (u_char *) &su->su_addr;
+ p = (u_char *) &su->su_port;
+ alen = sizeof(su->su_addr);
+ af = 4;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ a = (u_char *) &su->su_6addr;
+ p = (u_char *) &su->su_port;
+ alen = sizeof(su->su_6addr);
+ af = 6;
+ break;
+#endif
+ default:
+ af = 0;
+ break;
+ }
+ if (af) {
+ cprintf(stdout, " %s (%d,%d",
+ ispassive ? "LPSV" : "LPRT", af, alen);
+ for (i = 0; i < alen; i++)
+ cprintf(stdout, ",%d", UC(a[i]));
+ cprintf(stdout, ",%d,%d,%d)\r\n",
+ 2, UC(p[0]), UC(p[1]));
+#undef UC
+ }
+ }
+
+ /* EPRT/EPSV */
+ epsvonly:
+ af = af2epsvproto(su->su_family);
+ hbuf[0] = '\0';
+ if (af > 0) {
+ struct sockinet tmp;
+
+ tmp = *su;
+#ifdef INET6
+ if (tmp.su_family == AF_INET6)
+ tmp.su_scope_id = 0;
+#endif
+ if (getnameinfo((struct sockaddr *)&tmp.si_su,
+ tmp.su_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV) == 0)
+ reply(0, "%s (|%d|%s|%s|)",
+ ispassive ? "EPSV" : "EPRT",
+ af, hbuf, sbuf);
+ }
+ } else
+ reply(0, "No data connection");
+
+ if (logged_in) {
+ reply(0,
+ "Data sent: " LLF " byte%s in " LLF " file%s",
+ (LLT)total_data_out, PLURAL(total_data_out),
+ (LLT)total_files_out, PLURAL(total_files_out));
+ reply(0,
+ "Data received: " LLF " byte%s in " LLF " file%s",
+ (LLT)total_data_in, PLURAL(total_data_in),
+ (LLT)total_files_in, PLURAL(total_files_in));
+ reply(0,
+ "Total data: " LLF " byte%s in " LLF " file%s",
+ (LLT)total_data, PLURAL(total_data),
+ (LLT)total_files, PLURAL(total_files));
+ }
+ otbi = total_bytes_in;
+ otbo = total_bytes_out;
+ otb = total_bytes;
+ reply(0, "Traffic sent: " LLF " byte%s in " LLF " transfer%s",
+ (LLT)otbo, PLURAL(otbo),
+ (LLT)total_xfers_out, PLURAL(total_xfers_out));
+ reply(0, "Traffic received: " LLF " byte%s in " LLF " transfer%s",
+ (LLT)otbi, PLURAL(otbi),
+ (LLT)total_xfers_in, PLURAL(total_xfers_in));
+ reply(0, "Total traffic: " LLF " byte%s in " LLF " transfer%s",
+ (LLT)otb, PLURAL(otb),
+ (LLT)total_xfers, PLURAL(total_xfers));
+
+ if (logged_in) {
+ struct ftpconv *cp;
+
+ reply(0, "%s", "");
+ reply(0, "Class: %s, type: %s",
+ curclass.classname, CURCLASSTYPE);
+ reply(0, "Check PORT/LPRT commands: %sabled",
+ CURCLASS_FLAGS_ISSET(checkportcmd) ? "en" : "dis");
+ if (! EMPTYSTR(curclass.display))
+ 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, "Current connections: %d", connections);
+ if (curclass.limit == -1)
+ reply(0, "Maximum connections: unlimited");
+ else
+ reply(0, "Maximum connections: %d", curclass.limit);
+ if (curclass.limitfile)
+ reply(0, "Connection limit exceeded message file: %s",
+ curclass.limitfile);
+ if (! EMPTYSTR(curclass.chroot))
+ reply(0, "Chroot format: %s", curclass.chroot);
+ if (! EMPTYSTR(curclass.homedir))
+ reply(0, "Homedir format: %s", curclass.homedir);
+ if (curclass.maxfilesize == -1)
+ reply(0, "Maximum file size: unlimited");
+ else
+ reply(0, "Maximum file size: " LLF,
+ (LLT)curclass.maxfilesize);
+ if (! EMPTYSTR(curclass.motd))
+ reply(0, "MotD file: %s", curclass.motd);
+ reply(0,
+ "Modify commands (CHMOD, DELE, MKD, RMD, RNFR, UMASK): %sabled",
+ CURCLASS_FLAGS_ISSET(modify) ? "en" : "dis");
+ reply(0, "Upload commands (APPE, STOR, STOU): %sabled",
+ CURCLASS_FLAGS_ISSET(upload) ? "en" : "dis");
+ reply(0, "Sanitize file names: %sabled",
+ CURCLASS_FLAGS_ISSET(sanenames) ? "en" : "dis");
+ reply(0, "PASV/LPSV/EPSV connections: %sabled",
+ CURCLASS_FLAGS_ISSET(passive) ? "en" : "dis");
+ if (curclass.advertise.su_len != 0) {
+ char buf[50]; /* big enough for IPv6 address */
+ const char *bp;
+
+ bp = inet_ntop(curclass.advertise.su_family,
+ (void *)&curclass.advertise.su_addr,
+ buf, sizeof(buf));
+ if (bp != NULL)
+ reply(0, "PASV advertise address: %s", bp);
+ }
+ if (curclass.portmin && curclass.portmax)
+ reply(0, "PASV port range: %d - %d",
+ curclass.portmin, curclass.portmax);
+ if (curclass.rateget)
+ reply(0, "Rate get limit: " LLF " bytes/sec",
+ (LLT)curclass.rateget);
+ else
+ reply(0, "Rate get limit: disabled");
+ if (curclass.rateput)
+ reply(0, "Rate put limit: " LLF " bytes/sec",
+ (LLT)curclass.rateput);
+ else
+ reply(0, "Rate put limit: disabled");
+ reply(0, "Umask: %.04o", curclass.umask);
+ for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
+ if (cp->suffix == NULL || cp->types == NULL ||
+ cp->command == NULL)
+ continue;
+ reply(0, "Conversion: %s [%s] disable: %s, command: %s",
+ cp->suffix, cp->types, cp->disable, cp->command);
+ }
+ }
+
+ reply(211, "End of status");
+}
+
+void
+fatal(const char *s)
+{
+
+ reply(451, "Error in server: %s\n", s);
+ reply(221, "Closing connection due to server error.");
+ dologout(0);
+ /* NOTREACHED */
+}
+
+/*
+ * reply() --
+ * depending on the value of n, display fmt with a trailing CRLF and
+ * prefix of:
+ * n < -1 prefix the message with abs(n) + "-" (initial line)
+ * n == 0 prefix the message with 4 spaces (middle lines)
+ * n > 0 prefix the message with n + " " (final line)
+ */
+void
+reply(int n, const char *fmt, ...)
+{
+ off_t b;
+ va_list ap;
+
+ va_start(ap, fmt);
+ b = 0;
+ if (n == 0)
+ cprintf(stdout, " ");
+ else if (n < 0)
+ cprintf(stdout, "%d-", -n);
+ else
+ cprintf(stdout, "%d ", n);
+ b = vprintf(fmt, ap);
+ total_bytes += b;
+ total_bytes_out += b;
+ cprintf(stdout, "\r\n");
+ (void)fflush(stdout);
+ if (debug) {
+ syslog(LOG_DEBUG, "<--- %d%c", abs(n), (n < 0) ? '-' : ' ');
+ vsyslog(LOG_DEBUG, fmt, ap);
+ }
+}
+
+static void
+logremotehost(struct sockinet *who)
+{
+
+ if (getnameinfo((struct sockaddr *)&who->si_su,
+ who->su_len, remotehost, sizeof(remotehost), NULL, 0, 0))
+ strlcpy(remotehost, "?", sizeof(remotehost));
+
+#if HAVE_SETPROCTITLE
+ snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
+ setproctitle("%s", proctitle);
+#endif /* HAVE_SETPROCTITLE */
+ if (logging)
+ syslog(LOG_INFO, "connection from %s to %s",
+ remotehost, hostname);
+}
+
+/*
+ * Record logout in wtmp file and exit with supplied status.
+ */
+void
+dologout(int status)
+{
+ /*
+ * Prevent reception of SIGURG from resulting in a resumption
+ * back to the main program loop.
+ */
+ transflag = 0;
+
+ 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);
+#endif
+ }
+ /* beware of flushing buffers after a SIGPIPE */
+ _exit(status);
+}
+
+void
+abor(void)
+{
+
+ tmpline[0] = '\0';
+ is_oob = 0;
+ reply(426, "Transfer aborted. Data connection closed.");
+ reply(226, "Abort successful");
+ longjmp(urgcatch, 1);
+}
+
+void
+statxfer(void)
+{
+
+ tmpline[0] = '\0';
+ is_oob = 0;
+ if (file_size != (off_t) -1)
+ reply(213,
+ "Status: " LLF " of " LLF " byte%s transferred",
+ (LLT)byte_count, (LLT)file_size,
+ PLURAL(byte_count));
+ else
+ reply(213, "Status: " LLF " byte%s transferred",
+ (LLT)byte_count, PLURAL(byte_count));
+}
+
+static void
+myoob(int signo)
+{
+ char *cp;
+
+ /* only process if transfer occurring */
+ if (!transflag)
+ return;
+ cp = tmpline;
+ if (getline(cp, sizeof(tmpline), stdin) == NULL) {
+ reply(221, "You could at least say goodbye.");
+ dologout(0);
+ }
+ is_oob = 1;
+ ftp_handle_line(cp);
+ is_oob = 0;
+}
+
+static int
+bind_pasv_addr(void)
+{
+ static int passiveport;
+ int port, len;
+
+ len = pasv_addr.su_len;
+ if (curclass.portmin == 0 && curclass.portmax == 0) {
+ pasv_addr.su_port = 0;
+ return (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len));
+ }
+
+ if (passiveport == 0) {
+ srand(getpid());
+ passiveport = rand() % (curclass.portmax - curclass.portmin)
+ + curclass.portmin;
+ }
+
+ port = passiveport;
+ while (1) {
+ port++;
+ if (port > curclass.portmax)
+ port = curclass.portmin;
+ else if (port == passiveport) {
+ errno = EAGAIN;
+ return (-1);
+ }
+ pasv_addr.su_port = htons(port);
+ if (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len) == 0)
+ break;
+ if (errno != EADDRINUSE)
+ return (-1);
+ }
+ passiveport = port;
+ return (0);
+}
+
+/*
+ * Note: a response of 425 is not mentioned as a possible response to
+ * the PASV command in RFC959. However, it has been blessed as
+ * a legitimate response by Jon Postel in a telephone conversation
+ * with Rick Adams on 25 Jan 89.
+ */
+void
+passive(void)
+{
+ int len;
+ char *p, *a;
+
+ if (pdata >= 0)
+ close(pdata);
+ pdata = socket(AF_INET, SOCK_STREAM, 0);
+ if (pdata < 0 || !logged_in) {
+ perror_reply(425, "Can't open passive connection");
+ return;
+ }
+ pasv_addr = ctrl_addr;
+
+ if (bind_pasv_addr() < 0)
+ goto pasv_error;
+ len = pasv_addr.su_len;
+ if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0)
+ goto pasv_error;
+ pasv_addr.su_len = len;
+ if (listen(pdata, 1) < 0)
+ goto pasv_error;
+ if (curclass.advertise.su_len != 0)
+ a = (char *) &curclass.advertise.su_addr;
+ else
+ a = (char *) &pasv_addr.su_addr;
+ p = (char *) &pasv_addr.su_port;
+
+#define UC(b) (((int) b) & 0xff)
+
+ reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
+ UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
+ return;
+
+ pasv_error:
+ (void) close(pdata);
+ pdata = -1;
+ perror_reply(425, "Can't open passive connection");
+ return;
+}
+
+/*
+ * convert protocol identifier to/from AF
+ */
+int
+lpsvproto2af(int proto)
+{
+
+ switch (proto) {
+ case 4:
+ return AF_INET;
+#ifdef INET6
+ case 6:
+ return AF_INET6;
+#endif
+ default:
+ return -1;
+ }
+}
+
+int
+af2lpsvproto(int af)
+{
+
+ switch (af) {
+ case AF_INET:
+ return 4;
+#ifdef INET6
+ case AF_INET6:
+ return 6;
+#endif
+ default:
+ return -1;
+ }
+}
+
+int
+epsvproto2af(int proto)
+{
+
+ switch (proto) {
+ case 1:
+ return AF_INET;
+#ifdef INET6
+ case 2:
+ return AF_INET6;
+#endif
+ default:
+ return -1;
+ }
+}
+
+int
+af2epsvproto(int af)
+{
+
+ switch (af) {
+ case AF_INET:
+ return 1;
+#ifdef INET6
+ case AF_INET6:
+ return 2;
+#endif
+ default:
+ return -1;
+ }
+}
+
+/*
+ * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
+ * 229 Entering Extended Passive Mode (|||port|)
+ */
+void
+long_passive(char *cmd, int pf)
+{
+ int len;
+ char *p, *a;
+
+ if (!logged_in) {
+ syslog(LOG_NOTICE, "long passive but not logged in");
+ reply(503, "Login with USER first.");
+ return;
+ }
+
+ if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
+ /*
+ * XXX: only EPRT/EPSV ready clients will understand this
+ */
+ if (strcmp(cmd, "EPSV") != 0)
+ reply(501, "Network protocol mismatch"); /*XXX*/
+ else
+ epsv_protounsupp("Network protocol mismatch");
+
+ return;
+ }
+
+ if (pdata >= 0)
+ close(pdata);
+ pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
+ if (pdata < 0) {
+ perror_reply(425, "Can't open passive connection");
+ return;
+ }
+ pasv_addr = ctrl_addr;
+ if (bind_pasv_addr() < 0)
+ goto pasv_error;
+ len = pasv_addr.su_len;
+ if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0)
+ goto pasv_error;
+ pasv_addr.su_len = len;
+ if (listen(pdata, 1) < 0)
+ goto pasv_error;
+ p = (char *) &pasv_addr.su_port;
+
+#define UC(b) (((int) b) & 0xff)
+
+ if (strcmp(cmd, "LPSV") == 0) {
+ struct sockinet *advert;
+
+ if (curclass.advertise.su_len != 0)
+ advert = &curclass.advertise;
+ else
+ advert = &pasv_addr;
+ switch (advert->su_family) {
+ case AF_INET:
+ a = (char *) &advert->su_addr;
+ reply(228,
+ "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)",
+ 4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+ 2, UC(p[0]), UC(p[1]));
+ return;
+#ifdef INET6
+ case AF_INET6:
+ a = (char *) &advert->su_6addr;
+ reply(228,
+ "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
+ 6, 16,
+ UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+ UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
+ UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
+ UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
+ 2, UC(p[0]), UC(p[1]));
+ return;
+#endif
+ }
+#undef UC
+ } else if (strcmp(cmd, "EPSV") == 0) {
+ switch (pasv_addr.su_family) {
+ case AF_INET:
+#ifdef INET6
+ case AF_INET6:
+#endif
+ reply(229, "Entering Extended Passive Mode (|||%d|)",
+ ntohs(pasv_addr.su_port));
+ return;
+ }
+ } else {
+ /* more proper error code? */
+ }
+
+ pasv_error:
+ (void) close(pdata);
+ pdata = -1;
+ perror_reply(425, "Can't open passive connection");
+ return;
+}
+
+int
+extended_port(const char *arg)
+{
+ char *tmp = NULL;
+ char *result[3];
+ char *p, *q;
+ char delim;
+ struct addrinfo hints;
+ struct addrinfo *res = NULL;
+ int i;
+ unsigned long proto;
+
+ tmp = xstrdup(arg);
+ p = tmp;
+ delim = p[0];
+ p++;
+ memset(result, 0, sizeof(result));
+ for (i = 0; i < 3; i++) {
+ q = strchr(p, delim);
+ if (!q || *q != delim)
+ goto parsefail;
+ *q++ = '\0';
+ result[i] = p;
+ p = q;
+ }
+
+ /* some more sanity checks */
+ p = NULL;
+ (void)strtoul(result[2], &p, 10);
+ if (!*result[2] || *p)
+ goto parsefail;
+ p = NULL;
+ proto = strtoul(result[0], &p, 10);
+ if (!*result[0] || *p)
+ goto protounsupp;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = epsvproto2af((int)proto);
+ if (hints.ai_family < 0)
+ goto protounsupp;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(result[1], result[2], &hints, &res))
+ goto parsefail;
+ if (res->ai_next)
+ goto parsefail;
+ if (sizeof(data_dest) < res->ai_addrlen)
+ goto parsefail;
+ memcpy(&data_dest.si_su, res->ai_addr, res->ai_addrlen);
+ data_dest.su_len = res->ai_addrlen;
+#ifdef INET6
+ if (his_addr.su_family == AF_INET6 &&
+ data_dest.su_family == AF_INET6) {
+ /* XXX: more sanity checks! */
+ data_dest.su_scope_id = his_addr.su_scope_id;
+ }
+#endif
+
+ if (tmp != NULL)
+ free(tmp);
+ if (res)
+ freeaddrinfo(res);
+ return 0;
+
+ parsefail:
+ reply(500, "Invalid argument, rejected.");
+ usedefault = 1;
+ if (tmp != NULL)
+ free(tmp);
+ if (res)
+ freeaddrinfo(res);
+ return -1;
+
+ protounsupp:
+ epsv_protounsupp("Protocol not supported");
+ usedefault = 1;
+ if (tmp != NULL)
+ free(tmp);
+ if (res)
+ freeaddrinfo(res);
+ return -1;
+}
+
+/*
+ * 522 Protocol not supported (proto,...)
+ * as we assume address family for control and data connections are the same,
+ * we do not return the list of address families we support - instead, we
+ * return the address family of the control connection.
+ */
+void
+epsv_protounsupp(const char *message)
+{
+ int proto;
+
+ proto = af2epsvproto(ctrl_addr.su_family);
+ if (proto < 0)
+ reply(501, "%s", message); /* XXX */
+ else
+ reply(522, "%s, use (%d)", message, proto);
+}
+
+/*
+ * Generate unique name for file with basename "local".
+ * The file named "local" is already known to exist.
+ * Generates failure reply on error.
+ *
+ * XXX: this function should under go changes similar to
+ * the mktemp(3)/mkstemp(3) changes.
+ */
+static char *
+gunique(const char *local)
+{
+ static char new[MAXPATHLEN];
+ struct stat st;
+ char *cp;
+ int count;
+
+ cp = strrchr(local, '/');
+ if (cp)
+ *cp = '\0';
+ if (stat(cp ? local : ".", &st) < 0) {
+ perror_reply(553, cp ? local : ".");
+ return (NULL);
+ }
+ if (cp)
+ *cp = '/';
+ for (count = 1; count < 100; count++) {
+ (void)snprintf(new, sizeof(new) - 1, "%s.%d", local, count);
+ if (stat(new, &st) < 0)
+ return (new);
+ }
+ reply(452, "Unique file name cannot be created.");
+ return (NULL);
+}
+
+/*
+ * Format and send reply containing system error number.
+ */
+void
+perror_reply(int code, const char *string)
+{
+ int save_errno;
+
+ save_errno = errno;
+ reply(code, "%s: %s.", string, strerror(errno));
+ errno = save_errno;
+}
+
+static char *onefile[] = {
+ "",
+ 0
+};
+
+void
+send_file_list(const char *whichf)
+{
+ struct stat st;
+ DIR *dirp = NULL;
+ struct dirent *dir;
+ FILE *dout = NULL;
+ char **dirlist, *dirname, *p;
+ int simple = 0;
+ int freeglob = 0;
+ glob_t gl;
+
+#ifdef __GNUC__
+ (void) &dout;
+ (void) &dirlist;
+ (void) &simple;
+ (void) &freeglob;
+#endif
+
+ p = NULL;
+ if (strpbrk(whichf, "~{[*?") != NULL) {
+ int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE|GLOB_LIMIT;
+
+ memset(&gl, 0, sizeof(gl));
+ freeglob = 1;
+ if (glob(whichf, flags, 0, &gl)) {
+ reply(550, "not found");
+ goto out;
+ } else if (gl.gl_pathc == 0) {
+ errno = ENOENT;
+ perror_reply(550, whichf);
+ goto out;
+ }
+ dirlist = gl.gl_pathv;
+ } else {
+ p = xstrdup(whichf);
+ onefile[0] = p;
+ dirlist = onefile;
+ simple = 1;
+ }
+ /* XXX: } for vi sm */
+
+ if (setjmp(urgcatch)) {
+ transflag = 0;
+ goto out;
+ }
+ while ((dirname = *dirlist++) != NULL) {
+ int trailingslash = 0;
+
+ if (stat(dirname, &st) < 0) {
+ /*
+ * If user typed "ls -l", etc, and the client
+ * used NLST, do what the user meant.
+ */
+ /* XXX: nuke this support? */
+ if (dirname[0] == '-' && *dirlist == NULL &&
+ transflag == 0) {
+ char *argv[] = { INTERNAL_LS, "", NULL };
+
+ argv[1] = dirname;
+ retrieve(argv, dirname);
+ goto out;
+ }
+ perror_reply(550, whichf);
+ goto cleanup_send_file_list;
+ }
+
+ if (S_ISREG(st.st_mode)) {
+ /*
+ * XXXRFC:
+ * should we follow RFC959 and not work
+ * for non directories?
+ */
+ if (dout == NULL) {
+ dout = dataconn("file list", (off_t)-1, "w");
+ if (dout == NULL)
+ goto out;
+ transflag++;
+ }
+ cprintf(dout, "%s%s\n", dirname,
+ type == TYPE_A ? "\r" : "");
+ continue;
+ } else if (!S_ISDIR(st.st_mode))
+ continue;
+
+ if (dirname[strlen(dirname) - 1] == '/')
+ trailingslash++;
+
+ if ((dirp = opendir(dirname)) == NULL)
+ continue;
+
+ while ((dir = readdir(dirp)) != NULL) {
+ char nbuf[MAXPATHLEN];
+
+ if (ISDOTDIR(dir->d_name) || ISDOTDOTDIR(dir->d_name))
+ continue;
+
+ (void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
+ trailingslash ? "" : "/", dir->d_name);
+
+ /*
+ * We have to do a stat to ensure it's
+ * not a directory or special file.
+ */
+ /*
+ * XXXRFC:
+ * should we follow RFC959 and filter out
+ * non files ? lukem - NO!, or not until
+ * our ftp client uses MLS{T,D} for completion.
+ */
+ if (simple || (stat(nbuf, &st) == 0 &&
+ S_ISREG(st.st_mode))) {
+ char *p;
+
+ if (dout == NULL) {
+ dout = dataconn("file list", (off_t)-1,
+ "w");
+ if (dout == NULL)
+ goto out;
+ transflag++;
+ }
+ p = nbuf;
+ if (nbuf[0] == '.' && nbuf[1] == '/')
+ p = &nbuf[2];
+ cprintf(dout, "%s%s\n", p,
+ type == TYPE_A ? "\r" : "");
+ }
+ }
+ (void) closedir(dirp);
+ }
+
+ if (dout == NULL)
+ reply(550, "No files found.");
+ else if (ferror(dout) != 0)
+ perror_reply(550, "Data connection");
+ else
+ reply(226, "Transfer complete.");
+
+ cleanup_send_file_list:
+ transflag = 0;
+ closedataconn(dout);
+ out:
+ total_xfers++;
+ total_xfers_out++;
+ if (p)
+ free(p);
+ if (freeglob)
+ globfree(&gl);
+}
+
+char *
+conffilename(const char *s)
+{
+ static char filename[MAXPATHLEN];
+
+ if (*s == '/')
+ strlcpy(filename, s, sizeof(filename));
+ else
+ (void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s);
+ return (filename);
+}
+
+/*
+ * logxfer --
+ * if logging > 1, then based on the arguments, syslog a message:
+ * if bytes != -1 "<command> <file1> = <bytes> bytes"
+ * else if file2 != NULL "<command> <file1> <file2>"
+ * else "<command> <file1>"
+ * if elapsed != NULL, append "in xxx.yyy seconds"
+ * if error != NULL, append ": " + error
+ *
+ * if doxferlog != 0, 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)
+{
+ char buf[MAXPATHLEN * 2 + 100], realfile[MAXPATHLEN];
+ const char *r1, *r2;
+ char direction;
+ size_t len;
+ time_t now;
+
+ if (logging <=1 && !doxferlog)
+ return;
+
+ r1 = r2 = NULL;
+ if ((r1 = realpath(file1, realfile)) == NULL)
+ r1 = file1;
+ if (file2 != NULL)
+ if ((r2 = realpath(file2, realfile)) == NULL)
+ r2 = file2;
+
+ /*
+ * syslog command
+ */
+ if (logging > 1) {
+ len = snprintf(buf, sizeof(buf), "%s %s", command, r1);
+ if (bytes != (off_t)-1)
+ len += snprintf(buf + len, sizeof(buf) - len,
+ " = " LLF " byte%s", (LLT) bytes, PLURAL(bytes));
+ else if (r2 != NULL)
+ len += snprintf(buf + len, sizeof(buf) - len,
+ " %s", r2);
+ if (elapsed != NULL)
+ len += snprintf(buf + len, sizeof(buf) - len,
+ " in %ld.%.03d seconds", elapsed->tv_sec,
+ (int)(elapsed->tv_usec / 1000));
+ if (error != NULL)
+ len += snprintf(buf + len, sizeof(buf) - len,
+ ": %s", error);
+ syslog(LOG_INFO, "%s", buf);
+ }
+
+
+ /*
+ * syslog wu-ftpd style log entry, prefixed with "xferlog: "
+ */
+ if (!doxferlog)
+ return;
+
+ if (strcmp(command, "get") == 0)
+ direction = 'o';
+ else if (strcmp(command, "put") == 0 || strcmp(command, "append") == 0)
+ direction = 'i';
+ else
+ return;
+
+ time(&now);
+ syslog(LOG_INFO,
+ "xferlog%s: %.24s %ld %s " LLF " %s %c %s %c %c %s FTP 0 * %c",
+
+/*
+ * XXX: wu-ftpd puts (send) or (recv) in the syslog message, and removes
+ * the full date. This may be problematic for accurate log parsing,
+ * given that syslog messages don't contain the full date.
+ */
+#if 1 /* lukem's method; easier to convert to actual xferlog file */
+ "",
+ ctime(&now),
+#else /* wu-ftpd's syslog method, with an extra unneeded space */
+ (direction == 'i') ? " (recv)" : " (send)",
+ "",
+#endif
+ elapsed == NULL ? 0 : elapsed->tv_sec + (elapsed->tv_usec > 0),
+ remotehost,
+ bytes == (off_t)-1 ? 0 : (LLT) bytes,
+ r1,
+ type == TYPE_A ? 'a' : 'b',
+ "_", /* XXX: take conversions into account? */
+ direction,
+
+ curclass.type == CLASS_GUEST ? 'a' :
+ curclass.type == CLASS_CHROOT ? 'g' :
+ curclass.type == CLASS_REAL ? 'r' : '?',
+
+ curclass.type == CLASS_GUEST ? pw->pw_passwd : pw->pw_name,
+ error != NULL ? 'i' : 'c'
+ );
+}
+
+/*
+ * Determine if `password' is valid for user given in `pw'.
+ * Returns 2 if password expired, 1 if otherwise failed, 0 if ok
+ */
+int
+checkpassword(const struct passwd *pw, const char *password)
+{
+ char *orig, *new;
+ time_t expire;
+#if HAVE_GETSPNAM
+ struct spwd *spw;
+#endif
+
+ expire = 0;
+ if (pw == NULL)
+ return 1;
+
+#if HAVE_GETSPNAM
+ if ((spw = getspnam(pw->pw_name)) == NULL)
+ return 1;
+ orig = spw->sp_pwdp;
+#else
+ orig = pw->pw_passwd; /* save existing password */
+#if HAVE_PW_EXPIRE
+ expire = pw->pw_expire;
+#endif
+#endif /* HAVE_GETSPNAM */
+
+ if (orig[0] == '\0') /* don't allow empty passwords */
+ return 1;
+
+ new = crypt(password, orig); /* encrypt given password */
+ if (strcmp(new, orig) != 0) /* compare */
+ return 1;
+
+ if (expire && time(NULL) >= expire)
+ return 2; /* check if expired */
+
+ return 0; /* OK! */
+}
+
+char *
+xstrdup(const char *s)
+{
+ char *new = strdup(s);
+
+ if (new == NULL)
+ fatal("Local resource failure: malloc");
+ /* NOTREACHED */
+ return (new);
+}
+
+/*
+ * As per fprintf(), but increment total_bytes and total_bytes_out,
+ * by the appropriate amount.
+ */
+void
+cprintf(FILE *fd, const char *fmt, ...)
+{
+ off_t b;
+ va_list ap;
+
+ va_start(ap, fmt);
+ b = vfprintf(fd, fmt, ap);
+ total_bytes += b;
+ total_bytes_out += b;
+}
diff --git a/contrib/lukemftpd/src/ftpd.conf.5 b/contrib/lukemftpd/src/ftpd.conf.5
new file mode 100644
index 0000000..0c7dc68
--- /dev/null
+++ b/contrib/lukemftpd/src/ftpd.conf.5
@@ -0,0 +1,587 @@
+.\" $NetBSD: ftpd.conf.5,v 1.15 2000/12/18 02:32:51 lukem Exp $
+.\"
+.\" Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\" contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd December 18, 2000
+.Dt FTPD.CONF 5
+.Os
+.Sh NAME
+.Nm ftpd.conf
+.Nd
+.Xr ftpd 8
+configuration file
+.Sh DESCRIPTION
+The
+.Nm
+file specifies various configuration options for
+.Xr ftpd 8
+that apply once a user has authenticated their connection.
+.Pp
+.Nm
+consists of a series of lines, each of which may contain a
+configuration directive, a comment, or a blank line.
+Directives that appear later in the file override settings by previous
+directives.
+This allows
+.Sq wildcard
+entries to define defaults, and then have class-specific overrides.
+.Pp
+A directive line has the format:
+.Dl command class [arguments]
+.Pp
+A
+.Dq \e
+is the escape character; it can be used to escape the meaning of the
+comment character, or if it is the last character on a line, extends
+a configuration directive across multiple lines.
+A
+.Dq #
+is the comment character, and all characters from it to the end of
+line are ignored (unless it is escaped with the escape character).
+.Pp
+Each authenticated user is a member of a
+.Em class ,
+which is determined by
+.Xr ftpusers 5 .
+.Em class
+is used to determine which
+.Nm
+entries apply to the user.
+The following special classes exist when parsing entries in
+.Nm "" :
+.Bl -tag -width "chroot" -compact -offset indent
+.It Sy all
+Matches any class.
+.It Sy none
+Matches no class.
+.El
+.Pp
+Each class has a type, which may be one of:
+.Bl -tag -width "CHROOT" -offset indent
+.It Sy GUEST
+Guests (as per the
+.Dq anonymous
+and
+.Dq ftp
+logins).
+A
+.Xr chroot 2
+is performed after login.
+.It Sy CHROOT
+.Xr chroot 2 ed
+users (as per
+.Xr ftpchroot 5 ) .
+A
+.Xr chroot 2
+is performed after login.
+.It Sy REAL
+Normal users.
+.El
+.Pp
+The
+.Xr ftpd 8
+.Sy STAT
+command will return the class settings for the current user as defined by
+.Nm "" .
+.Pp
+Each configuration line may be one of:
+.Bl -tag -width 4n
+.It Sy advertise Ar class Ar host
+Set the address to advertise in the response to the
+.Sy PASV
+and
+.Sy LPSV
+commands to the address for
+.Ar host
+(which may be either a host name or IP address).
+This may be useful in some firewall configurations, although many
+ftp clients may not work if the address being advertised is different
+to the address that they've connected to.
+If
+.Ar class
+is
+.Dq none
+or no argument is given, disable this.
+.It Sy checkportcmd Ar class Op Sy off
+Check the
+.Sy PORT
+command for validity.
+The
+.Sy PORT
+command will fail if the IP address specified does not match the
+.Tn FTP
+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
+with potential security problems with
+.Tn FTP
+bounce attacks.
+If
+.Ar class
+is
+.Dq none
+or
+.Sy off
+is given, disable this feature, otherwise enable it.
+.It Sy chroot Ar class Op Sy pathformat
+If
+.Ar pathformat
+is not given or
+.Ar class
+is
+.Dq none ,
+use the default behaviour (see below).
+Otherwise,
+.Ar pathformat
+is parsed to create a directory to create as the root directory with
+.Xr chroot 2
+into upon login.
+.Pp
+.Ar pathformat
+can contain the following escape strings:
+.Bl -tag -width "Escape" -offset indent -compact
+.It Sy "Escape"
+.Sy Description
+.It "\&%c"
+Class name.
+.It "\&%d"
+Home directory of user.
+.It "\&%u"
+User name.
+.It "\&%\&%"
+A
+.Dq \&%
+character.
+.El
+.Pp
+The default root directory is:
+.Bl -tag -width "CHROOT" -offset indent -compact
+.It Sy CHROOT
+The user's home directory.
+.It Sy GUEST
+If
+.Fl a Ar anondir
+is given, use
+.Ar anondir ,
+otherwise the home directory of the
+.Sq ftp
+user.
+.It Sy REAL
+By default no
+.Xr chroot 2
+is performed.
+.El
+.It Sy classtype Ar class Ar type
+Set the class type of
+.Ar class
+to
+.Ar type
+(see above).
+.It Xo Sy conversion Ar class
+.Ar suffix Op Ar "type disable command"
+.Xc
+Define an automatic in-line file conversion.
+If a file to retrieve ends in
+.Ar suffix ,
+and a real file (sans
+.Ar suffix )
+exists, then the output of
+.Ar command
+is returned instead of the contents of the file.
+.Pp
+.Bl -tag -width "disable" -offset indent
+.It Ar suffix
+The suffix to initiate the conversion.
+.It Ar type
+A list of valid filetypes for the conversion.
+Valid types are:
+.Sq f
+(file), and
+.Sq d
+(directory).
+.It Ar disable
+The name of file that will prevent conversion if it exists.
+A file name of
+.Dq Pa \&.
+will prevent this disabling action
+(i.e., the conversion is always permitted.)
+.It Ar command
+The command to run for the conversion.
+The first word should be the full path name
+of the command, as
+.Xr execv 3
+is used to execute the command.
+All instances of the word
+.Dq %s
+in
+.Ar command
+are replaced with the requested file (sans
+.Ar suffix ) .
+.El
+.Pp
+Conversion directives specified later in the file override earlier
+conversions with the same suffix.
+.It Sy display Ar class Op Ar file
+If
+.Ar file
+is not given or
+.Ar class
+is
+.Dq none ,
+disable this.
+Otherwise, each time the user enters a new directory, check if
+.Ar file
+exists, and if so, display its contents to the user.
+Escape sequences are supported; refer to
+.Sx Display file escape sequences
+in
+.Xr ftpd 8
+for more information.
+.It Sy homedir Ar class Op Sy pathformat
+If
+.Ar pathformat
+is not given or
+.Ar class
+is
+.Dq none ,
+use the default behaviour (see below).
+Otherwise,
+.Ar pathformat
+is parsed to create a directory to change into upon login, and to use
+as the
+.Sq home
+directory of the user for tilde expansion in pathnames, etc.
+.Ar pathformat
+is parsed as per the
+.Sy chroot
+directive.
+.Pp
+The default home directory is the home directory of the user for
+.Sy REAL
+users, and
+.Pa /
+for
+.Sy GUEST
+and
+.Sy CHROOT
+users.
+.It Xo Sy limit Ar class
+.Ar count Op Ar file
+.Xc
+Limit the maximum number of concurrent connections for
+.Ar class
+to
+.Ar count ,
+with
+.Sq 0
+meaning unlimited connections.
+If the limit is exceeded and
+.Ar file
+is given, display its contents to the user.
+If
+.Ar class
+is
+.Dq none
+or
+.Ar count
+is not specified, disable this.
+If
+.Ar file
+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
+Set the maximum size of an uploaded file to
+.Ar size .
+If
+.Ar class
+is
+.Dq none
+or no argument is given, disable this.
+.It Sy maxtimeout Ar class 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
+.Sy timeout .
+If
+.Ar class
+is
+.Dq none
+or
+.Ar time
+is not specified, set to default of 2 hours.
+.It Sy modify Ar class Op Sy off
+If
+.Ar class
+is
+.Dq none
+or
+.Sy off
+is given, disable the following commands:
+.Sy CHMOD ,
+.Sy DELE ,
+.Sy MKD ,
+.Sy RMD ,
+.Sy RNFR ,
+and
+.Sy UMASK .
+Otherwise, enable them.
+.It Sy motd Ar class Op Ar file
+If
+.Ar file
+is not given or
+.Ar class
+is
+.Dq none ,
+disable this.
+Otherwise, use
+.Ar file
+as the message of the day file to display after login.
+Escape sequences are supported; refer to
+.Sx Display file escape sequences
+in
+.Xr ftpd 8
+for more information.
+If
+.Ar file
+is a relative path, it will be searched for in
+.Pa /etc
+(which can be overridden with
+.Fl c Ar confdir ) .
+.It Sy notify Ar class Op Ar fileglob
+If
+.Ar fileglob
+is not given or
+.Ar class
+is
+.Dq none ,
+disable this.
+Otherwise, each time the user enters a new directory,
+notify the user of any files matching
+.Ar fileglob .
+.It Sy passive Ar class Op Sy off
+If
+.Ar class
+is
+.Dq none
+or
+.Sy off
+is given, disallow passive
+.Sy ( PASV ,
+.Sy LPSV ,
+and
+.Sy EPSV )
+connections.
+Otherwise, enable them.
+.It Sy portrange Ar class Ar min Ar max
+Set the range of port number which will be used for the passive data port.
+.Ar max
+must be greater than
+.Ar min ,
+and both numbers must be be between
+.Dv IPPORT_RESERVED
+(1024) and 65535.
+If
+.Ar class
+is
+.Dq none
+or no arguments are given, disable this.
+.It Sy rateget Ar class Ar rate
+Set the maximum get
+.Pq Sy RETR
+transfer rate throttle for
+.Ar class
+to
+.Ar rate
+bytes per second.
+If
+.Ar rate
+is 0, the throttle is disabled.
+If
+.Ar class
+is
+.Dq none
+or no arguments are given, disable this.
+.Pp
+An optional suffix may be provided, which changes the intrepretation of
+.Ar rate
+as follows:
+.Bl -tag -width 3n -offset indent -compact
+.It b
+Causes no modification. (Default; optional)
+.It k
+Kilo; multiply the argument by 1024
+.It m
+Mega; multiply the argument by 1048576
+.It g
+Giga; multiply the argument by 1073741824
+.It t
+Tera; multiply the argument by 1099511627776
+.El
+.It Sy rateput Ar class Ar rate
+Set the maximum put
+.Pq Sy STOR
+transfer rate throttle for
+.Ar class
+to
+.Ar rate
+bytes per second,
+which is parsed as per
+.Sy rateget Ar rate .
+If
+.Ar class
+is
+.Dq none
+or no arguments are given, disable this.
+.It Sy sanenames Ar class Op Sy off
+If
+.Ar class
+is
+.Dq none
+or
+.Sy off
+is given, 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 template Ar class Op Ar refclass
+Define
+.Ar refclass
+as the
+.Sq template
+for
+.Ar class ;
+any reference to
+.Ar refclass
+in following directives will also apply to members of
+.Ar class .
+This is useful to define a template class so that other classes which are
+to share common attributes can be easily defined without unnecessary
+duplication.
+There can be only one template defined at a time.
+If
+.Ar refclass
+is not given, disable the template for
+.Ar class .
+.It Sy timeout Ar class 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
+.Sy maxtimeout .
+If
+.Ar class
+is
+.Dq none
+or
+.Ar time
+is not specified, set to the default of 15 minutes.
+.It Sy umask Ar class Ar umaskval
+Set the umask to
+.Ar umaskval .
+If
+.Ar class
+is
+.Dq none
+or
+.Ar umaskval
+is not specified, set to the default of
+.Li 027 .
+.It Sy upload Ar class Op Sy off
+If
+.Ar class
+is
+.Dq none
+or
+.Sy off
+is given, disable the following commands:
+.Sy APPE ,
+.Sy STOR ,
+and
+.Sy STOU ,
+as well as the modify commands:
+.Sy CHMOD ,
+.Sy DELE ,
+.Sy MKD ,
+.Sy RMD ,
+.Sy RNFR ,
+and
+.Sy UMASK .
+Otherwise, enable them.
+.El
+.Sh DEFAULTS
+The following defaults are used:
+.Pp
+.Bd -literal -offset indent -compact
+checkportcmd all
+classtype chroot CHROOT
+classtype guest GUEST
+classtype real REAL
+display none
+limit all -1 # unlimited connections
+maxtimeout all 7200 # 2 hours
+modify all
+motd all motd
+notify none
+passive all
+timeout all 900 # 15 minutes
+umask all 027
+upload all
+modify guest off
+umask guest 0707
+.Ed
+.Sh FILES
+.Bl -tag -width /usr/share/examples/ftpd/ftpd.conf -compact
+.It Pa /etc/ftpd.conf
+This file.
+.It Pa /usr/share/examples/ftpd/ftpd.conf
+A sample
+.Nm
+file.
+.El
+.Sh SEE ALSO
+.Xr ftpchroot 5 ,
+.Xr ftpusers 5 ,
+.Xr ftpd 8
+.Sh HISTORY
+The
+.Nm
+functionality was implemented in
+.Nx 1.3
+and later releases by Luke Mewburn, based on work by Simon Burge.
diff --git a/contrib/lukemftpd/src/ftpusers.5 b/contrib/lukemftpd/src/ftpusers.5
new file mode 100644
index 0000000..85f500f
--- /dev/null
+++ b/contrib/lukemftpd/src/ftpusers.5
@@ -0,0 +1,183 @@
+.\" $NetBSD: ftpusers.5,v 1.10 2001/04/25 01:46:26 lukem Exp $
+.\"
+.\" Copyright (c) 1997-2001 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\" contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd July 17, 2000
+.Dt FTPUSERS 5
+.Os
+.Sh NAME
+.Nm ftpusers ,
+.Nm ftpchroot
+.Nd
+.Xr ftpd 8
+access control file
+.Sh DESCRIPTION
+The
+.Nm
+file provides user access control for
+.Xr ftpd 8
+by defining which users may login.
+.Pp
+If the
+.Nm
+file does not exist, all users are denied access.
+.Pp
+A
+.Dq \e
+is the escape character; it can be used to escape the meaning of the
+comment character, or if it is the last character on a line, extends
+a configuration directive across multiple lines.
+A
+.Dq #
+is the comment character, and all characters from it to the end of
+line are ignored (unless it is escaped with the escape character).
+.Pp
+The syntax of each line is:
+.Dl userglob[:groupglob][@host] [directive [class]]
+.Pp
+These elements are:
+.Bl -tag -width "groupglob" -offset indent
+.It Sy userglob
+matched against the user name, using
+.Xr fnmatch 3
+glob matching
+(e.g,
+.Sq f* ) .
+.It Sy groupglob
+matched against all the groups that the user is a member of, using
+.Xr fnmatch 3
+glob matching
+(e.g,
+.Sq *src ) .
+.It Sy host
+either a CIDR address (refer to
+.Xr inet_net_pton 3 )
+to match against the remote address
+(e.g,
+.Sq 1.2.3.4/24 ) ,
+or a glob to match against the remote hostname
+(e.g,
+.Sq *.netbsd.org ) .
+.It Sy directive
+If
+.Dq allow
+or
+.Dq yes
+the user is allowed access.
+If
+.Dq deny
+or
+.Dq no ,
+or
+.Sy directive
+is not given, the user is denied access.
+.It Sy class
+defines the class to use in
+.Xr ftpd.conf 5 .
+.El
+.Pp
+If
+.Sy class
+is not given, it defaults to one of the following:
+.Bl -tag -width "chroot" -offset indent
+.It Sy chroot
+If there is a match in
+.Sx /etc/ftpchroot
+for the user.
+.It Sy guest
+If the user name is
+.Dq anonymous
+or
+.Sq ftp .
+.It Sy real
+If neither of the above is true.
+.El
+.Pp
+No further comparisons are attempted after the first successful match.
+If no match is found, the user is granted access.
+This syntax is backward-compatable with the old syntax.
+.Pp
+If a user requests a guest login, the
+.Xr ftpd 8
+server checks to see that
+both
+.Dq anonymous
+and
+.Dq ftp
+have access, so if you deny all users by default, you will need to add both
+.Dq "anonymous allow"
+and
+.Dq "ftp allow"
+to
+.Pa /etc/ftpusers
+in order to allow guest logins.
+.Ss /etc/ftpchroot
+The file
+.Pa /etc/ftpchroot
+is used to determine which users will have their session's root directory
+changed (using
+.Xr chroot 2 ) ,
+either to the directory specified in the
+.Xr ftpd.conf 5
+.Sy chroot
+directive (if set),
+or to the home directory of the user.
+If the file does not exist, the root directory change is not performed.
+.Pp
+The syntax is similar to
+.Nm "" ,
+except that the
+.Sy class
+argument is ignored.
+If there's a positive match, the session's root directory is changed.
+No further comparisons are attempted after the first successful match.
+This syntax is backward-compatable with the old syntax.
+.Sh FILES
+.Bl -tag -width /etc/ftpchroot -compact
+.It Pa /etc/ftpchroot
+List of normal users who should be
+.Xr chroot 2 ed.
+.It Pa /etc/ftpusers
+This file.
+.It Pa /usr/share/examples/ftpd/ftpusers
+A sample
+.Nm
+file.
+.El
+.Sh SEE ALSO
+.Xr fnmatch 3 ,
+.Xr inet_net_pton 3 ,
+.Xr ftpd.conf 5 ,
+.Xr ftpd 8
diff --git a/contrib/lukemftpd/src/logutmp.c b/contrib/lukemftpd/src/logutmp.c
new file mode 100644
index 0000000..7ef6437
--- /dev/null
+++ b/contrib/lukemftpd/src/logutmp.c
@@ -0,0 +1,111 @@
+/*
+ * Portions Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Portions Copyright (c) 1996, Jason Downs. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "lukemftpd.h"
+
+typedef struct utmp UTMP;
+
+static int fd = -1;
+static int topslot = -1;
+
+/*
+ * Special versions of login()/logout() which hold the utmp file open,
+ * for use with ftpd.
+ */
+
+void
+login(const UTMP *ut)
+{
+ UTMP ubuf;
+
+ /*
+ * First, loop through /etc/ttys, if needed, to initialize the
+ * top of the tty slots, since ftpd has no tty.
+ */
+ if (topslot < 0) {
+ topslot = 0;
+ while (getttyent() != (struct ttyent *)NULL)
+ topslot++;
+ }
+ if ((topslot < 0) || ((fd < 0)
+ && (fd = open(_PATH_UTMP, O_RDWR|O_CREAT, 0644)) < 0))
+ return;
+
+ /*
+ * Now find a slot that's not in use...
+ */
+ (void)lseek(fd, (off_t)(topslot * sizeof(UTMP)), SEEK_SET);
+
+ while (1) {
+ if (read(fd, &ubuf, sizeof(UTMP)) == sizeof(UTMP)) {
+ if (!ubuf.ut_name[0]) {
+ (void)lseek(fd, -(off_t)sizeof(UTMP), SEEK_CUR);
+ break;
+ }
+ topslot++;
+ } else {
+ (void)lseek(fd, (off_t)(topslot * sizeof(UTMP)),
+ SEEK_SET);
+ break;
+ }
+ }
+
+ (void)write(fd, ut, sizeof(UTMP));
+}
+
+int
+logout(const char *line)
+{
+ UTMP ut;
+ int rval;
+
+ rval = 0;
+ if (fd < 0)
+ return(rval);
+
+ (void)lseek(fd, 0, SEEK_SET);
+
+ while (read(fd, &ut, sizeof(UTMP)) == sizeof(UTMP)) {
+ if (!ut.ut_name[0]
+ || strncmp(ut.ut_line, line, UT_LINESIZE))
+ continue;
+ memset(ut.ut_name, 0, UT_NAMESIZE);
+ memset(ut.ut_host, 0, UT_HOSTSIZE);
+ (void)time(&ut.ut_time);
+ (void)lseek(fd, -(off_t)sizeof(UTMP), SEEK_CUR);
+ (void)write(fd, &ut, sizeof(UTMP));
+ rval = 1;
+ }
+ return(rval);
+}
diff --git a/contrib/lukemftpd/src/logwtmp.c b/contrib/lukemftpd/src/logwtmp.c
new file mode 100644
index 0000000..b7f2925
--- /dev/null
+++ b/contrib/lukemftpd/src/logwtmp.c
@@ -0,0 +1,65 @@
+/* $NetBSD: logwtmp.c,v 1.16 2001/02/04 22:04:12 christos Exp $ */
+
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "lukemftpd.h"
+
+#include "extern.h"
+
+static int fd = -1;
+
+/*
+ * Modified version of logwtmp that holds wtmp file open
+ * after first call, for use with ftp (which may chroot
+ * after login, but before logout).
+ */
+void
+logwtmp(const char *line, const char *name, const char *host)
+{
+ struct utmp ut;
+ struct stat buf;
+
+ if (fd < 0 && (fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ if (fstat(fd, &buf) == 0) {
+ (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+ (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+ (void)time(&ut.ut_time);
+ if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
+ sizeof(struct utmp))
+ (void)ftruncate(fd, buf.st_size);
+ }
+}
diff --git a/contrib/lukemftpd/src/pathnames.h b/contrib/lukemftpd/src/pathnames.h
new file mode 100644
index 0000000..a5766b5
--- /dev/null
+++ b/contrib/lukemftpd/src/pathnames.h
@@ -0,0 +1,51 @@
+/* $NetBSD: pathnames.h,v 1.10 2000/03/06 21:42:26 lukem Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ */
+
+#ifndef _DEFAULT_CONFDIR
+#define _DEFAULT_CONFDIR "/etc"
+#endif
+
+#define _PATH_FTPCHROOT "ftpchroot"
+#define _PATH_FTPDCONF "ftpd.conf"
+#define _PATH_FTPLOGINMESG "motd"
+#undef _PATH_FTPUSERS
+#define _PATH_FTPUSERS "ftpusers"
+#define _PATH_FTPWELCOME "ftpwelcome"
+
+#define _PATH_CLASSPIDS "/var/run/ftpd.pids-"
+
+#define TMPFILE "/tmp/ftpdXXXXXXX"
diff --git a/contrib/lukemftpd/src/popen.c b/contrib/lukemftpd/src/popen.c
new file mode 100644
index 0000000..7e8d036
--- /dev/null
+++ b/contrib/lukemftpd/src/popen.c
@@ -0,0 +1,236 @@
+/* $NetBSD: popen.c,v 1.26 2001/04/25 01:46:26 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1999-2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software written by Ken Arnold and
+ * published in UNIX Review, Vol. 6, No. 8.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "lukemftpd.h"
+
+#include "extern.h"
+
+#define INCR 100
+/*
+ * Special version of popen which avoids call to shell. This ensures no-one
+ * may create a pipe to a hidden program as a side effect of a list or dir
+ * command.
+ * If stderrfd != -1, then send stderr of a read command there,
+ * otherwise close stderr.
+ */
+static int *pids;
+static int fds;
+
+extern int ls_main(int, char *[]);
+
+FILE *
+ftpd_popen(char *argv[], const char *type, int stderrfd)
+{
+ FILE *iop;
+ int argc, pdes[2], pid, isls;
+ char **pop;
+ StringList *sl;
+
+ iop = NULL;
+ isls = 0;
+ if ((*type != 'r' && *type != 'w') || type[1])
+ return (NULL);
+
+ if (!pids) {
+ if ((fds = getdtablesize()) <= 0)
+ return (NULL);
+ if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
+ return (NULL);
+ memset(pids, 0, fds * sizeof(int));
+ }
+ if (pipe(pdes) < 0)
+ return (NULL);
+
+ if ((sl = sl_init()) == NULL)
+ goto pfree;
+
+ /* glob each piece */
+ if (sl_add(sl, xstrdup(argv[0])) == -1)
+ goto pfree;
+ for (argc = 1; argv[argc]; argc++) {
+ glob_t gl;
+ int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE|GLOB_LIMIT;
+
+ memset(&gl, 0, sizeof(gl));
+ if (glob(argv[argc], flags, NULL, &gl)) {
+ if (sl_add(sl, xstrdup(argv[argc])) == -1) {
+ globfree(&gl);
+ goto pfree;
+ }
+ } else {
+ for (pop = gl.gl_pathv; *pop; pop++) {
+ if (sl_add(sl, xstrdup(*pop)) == -1) {
+ globfree(&gl);
+ goto pfree;
+ }
+ }
+ }
+ globfree(&gl);
+ }
+ if (sl_add(sl, NULL) == -1)
+ goto pfree;
+
+#ifndef NO_INTERNAL_LS
+ 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]);
+ (void)close(pdes[1]);
+ goto pfree;
+ /* NOTREACHED */
+ case 0: /* child */
+ if (*type == 'r') {
+ if (pdes[1] != STDOUT_FILENO) {
+ dup2(pdes[1], STDOUT_FILENO);
+ (void)close(pdes[1]);
+ }
+ if (stderrfd == -1)
+ (void)close(STDERR_FILENO);
+ else
+ dup2(stderrfd, STDERR_FILENO);
+ (void)close(pdes[0]);
+ } else {
+ if (pdes[0] != STDIN_FILENO) {
+ dup2(pdes[0], STDIN_FILENO);
+ (void)close(pdes[0]);
+ }
+ (void)close(pdes[1]);
+ }
+#ifndef NO_INTERNAL_LS
+ if (isls) { /* use internal ls */
+#if HAVE_OPTRESET
+ optreset = 1;
+#endif
+ optind = optopt = 1;
+ closelog();
+ exit(ls_main(sl->sl_cur - 1, sl->sl_str));
+ }
+#endif
+
+ execv(sl->sl_str[0], sl->sl_str);
+ _exit(1);
+ }
+ /* parent; assume fdopen can't fail... */
+ if (*type == 'r') {
+ iop = fdopen(pdes[0], type);
+ (void)close(pdes[1]);
+ } else {
+ iop = fdopen(pdes[1], type);
+ (void)close(pdes[0]);
+ }
+ pids[fileno(iop)] = pid;
+
+ pfree:
+ if (sl)
+ sl_free(sl, 1);
+ return (iop);
+}
+
+int
+ftpd_pclose(FILE *iop)
+{
+ int fdes, status;
+ pid_t pid;
+ sigset_t sigset, osigset;
+
+ /*
+ * pclose returns -1 if stream is not associated with a
+ * `popened' command, or, if already `pclosed'.
+ */
+ if (pids == 0 || pids[fdes = fileno(iop)] == 0)
+ return (-1);
+ (void)fclose(iop);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGINT);
+ sigaddset(&sigset, SIGQUIT);
+ sigaddset(&sigset, SIGHUP);
+ sigprocmask(SIG_BLOCK, &sigset, &osigset);
+ while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
+ continue;
+ sigprocmask(SIG_SETMASK, &osigset, NULL);
+ pids[fdes] = 0;
+ if (pid < 0)
+ return (pid);
+ if (WIFEXITED(status))
+ return (WEXITSTATUS(status));
+ return (1);
+}
diff --git a/contrib/lukemftpd/src/version.h b/contrib/lukemftpd/src/version.h
new file mode 100644
index 0000000..1a075c7
--- /dev/null
+++ b/contrib/lukemftpd/src/version.h
@@ -0,0 +1,40 @@
+/* $NetBSD: version.h,v 1.32 2001/04/25 01:46:26 lukem Exp $ */
+/*-
+ * Copyright (c) 1999-2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FTPD_VERSION
+#define FTPD_VERSION "NetBSD-ftpd 20010425"
+#endif
diff --git a/contrib/lukemftpd/todo b/contrib/lukemftpd/todo
new file mode 100644
index 0000000..83ca631
--- /dev/null
+++ b/contrib/lukemftpd/todo
@@ -0,0 +1,17 @@
+autoconf checks:
+ - HAVE_FTP_NAMES if FTP_NAMES et al in <arpa/ftp.h>
+ - replace getopt() if optreset (BSD) or getoptreset() (irix)
+ is not available?
+ - IF_NAMESIZE not available on darwin
+
+fix internalls (actually fts) on IRIX
+
+enable utmp stuff (need to make it portable)
+
+enable wtmp stuff (need to make it portable)
+
+enable kerberos support once its fixed?
+
+add getenv(3) to replace putenv(3) cruft?
+
+barf if neither flock() nor lockf() is available
OpenPOWER on IntegriCloud