From 299281efb0b6a071b558f4d2b354dc1c0ba81afa Mon Sep 17 00:00:00 2001 From: "David E. O'Brien" Date: Thu, 19 Jul 2001 16:25:08 +0000 Subject: [PATCH] Import of LukeM's ftpd version 1.1. --- contrib/lukemftpd/COPYING | 47 + contrib/lukemftpd/ChangeLog | 176 ++ contrib/lukemftpd/INSTALL | 98 + contrib/lukemftpd/Makefile.in | 29 + contrib/lukemftpd/NEWS | 13 + contrib/lukemftpd/README | 102 + contrib/lukemftpd/THANKS | 9 + contrib/lukemftpd/acconfig.h | 101 + contrib/lukemftpd/aclocal.m4 | 257 ++ contrib/lukemftpd/config.h.in | 274 ++ contrib/lukemftpd/configure | 4091 +++++++++++++++++++++++++++++ contrib/lukemftpd/configure.in | 300 +++ contrib/lukemftpd/install-sh | 251 ++ contrib/lukemftpd/lukemftpd.h | 396 +++ contrib/lukemftpd/src/Makefile.in | 61 + contrib/lukemftpd/src/arpaftp.h | 111 + contrib/lukemftpd/src/cmds.c | 791 ++++++ contrib/lukemftpd/src/conf.c | 1007 +++++++ contrib/lukemftpd/src/extern.h | 372 +++ contrib/lukemftpd/src/ftpcmd.y | 1808 +++++++++++++ contrib/lukemftpd/src/ftpd.8 | 833 ++++++ contrib/lukemftpd/src/ftpd.c | 2947 +++++++++++++++++++++ contrib/lukemftpd/src/ftpd.conf.5 | 587 +++++ contrib/lukemftpd/src/ftpusers.5 | 183 ++ contrib/lukemftpd/src/logutmp.c | 111 + contrib/lukemftpd/src/logwtmp.c | 65 + contrib/lukemftpd/src/pathnames.h | 51 + contrib/lukemftpd/src/popen.c | 236 ++ contrib/lukemftpd/src/version.h | 40 + contrib/lukemftpd/todo | 17 + 30 files changed, 15364 insertions(+) create mode 100644 contrib/lukemftpd/COPYING create mode 100644 contrib/lukemftpd/ChangeLog create mode 100644 contrib/lukemftpd/INSTALL create mode 100644 contrib/lukemftpd/Makefile.in create mode 100644 contrib/lukemftpd/NEWS create mode 100644 contrib/lukemftpd/README create mode 100644 contrib/lukemftpd/THANKS create mode 100644 contrib/lukemftpd/acconfig.h create mode 100644 contrib/lukemftpd/aclocal.m4 create mode 100644 contrib/lukemftpd/config.h.in create mode 100755 contrib/lukemftpd/configure create mode 100644 contrib/lukemftpd/configure.in create mode 100755 contrib/lukemftpd/install-sh create mode 100644 contrib/lukemftpd/lukemftpd.h create mode 100644 contrib/lukemftpd/src/Makefile.in create mode 100644 contrib/lukemftpd/src/arpaftp.h create mode 100644 contrib/lukemftpd/src/cmds.c create mode 100644 contrib/lukemftpd/src/conf.c create mode 100644 contrib/lukemftpd/src/extern.h create mode 100644 contrib/lukemftpd/src/ftpcmd.y create mode 100644 contrib/lukemftpd/src/ftpd.8 create mode 100644 contrib/lukemftpd/src/ftpd.c create mode 100644 contrib/lukemftpd/src/ftpd.conf.5 create mode 100644 contrib/lukemftpd/src/ftpusers.5 create mode 100644 contrib/lukemftpd/src/logutmp.c create mode 100644 contrib/lukemftpd/src/logwtmp.c create mode 100644 contrib/lukemftpd/src/pathnames.h create mode 100644 contrib/lukemftpd/src/popen.c create mode 100644 contrib/lukemftpd/src/version.h create mode 100644 contrib/lukemftpd/todo diff --git a/contrib/lukemftpd/COPYING b/contrib/lukemftpd/COPYING new file mode 100644 index 000000000000..fe7b79bca3dd --- /dev/null +++ b/contrib/lukemftpd/COPYING @@ -0,0 +1,47 @@ +Copyright 2001 Luke Mewburn . 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 000000000000..76cb9da03884 --- /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 + + * pull in 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" + - ensure replydirname() do not truncate the names. + From: Paul Janzen + - 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 if it exists, but still check each _PATH_xxx and + define to something sane if not found; certain platforms have a + lobotomised + +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 + +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 000000000000..80fa04b8d08d --- /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 000000000000..6b751cbb4d87 --- /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 000000000000..b1c0211c673c --- /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 000000000000..60d645fbd7fd --- /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 . + +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: . + + +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 000000000000..b6ce509614fc --- /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 +Curt Sampson +Jun-ichiro itojun Hagino +Matthew R. Green +Todd Vierling diff --git a/contrib/lukemftpd/acconfig.h b/contrib/lukemftpd/acconfig.h new file mode 100644 index 000000000000..88caee0a0c83 --- /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 */ +#undef HAVE_AF_INET6 + +/* Define if `struct sockaddr_in6' exists in */ +#undef HAVE_SOCKADDR_IN6 + +/* Define if `struct addrinfo' exists in */ +#undef HAVE_ADDRINFO + +/* + * Define if 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 */ +#undef HAVE_WORKING_GLOB + +/* Define if crypt() is declared in */ +#undef HAVE_CRYPT_D + +/* Define if fclose() is declared in */ +#undef HAVE_FCLOSE_D + +/* Define if optarg is declared in or */ +#undef HAVE_OPTARG_D + +/* Define if optind is declared in or */ +#undef HAVE_OPTIND_D + +/* Define if optreset exists */ +#undef HAVE_OPTRESET + +/* Define if pclose() is declared in */ +#undef HAVE_PCLOSE_D + +/* Define if getusershell() is declared in */ +#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 000000000000..572f5c5cdf9f --- /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 +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 . 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 +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 000000000000..b32c4c1e6697 --- /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 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 and . */ +#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 header file. */ +#undef HAVE_ARPA_NAMESER_H + +/* Define if you have the header file. */ +#undef HAVE_DIRENT_H + +/* Define if you have the header file. */ +#undef HAVE_ERR_H + +/* Define if you have the header file. */ +#undef HAVE_FTS_H + +/* Define if you have the header file. */ +#undef HAVE_LIBUTIL_H + +/* Define if you have the header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_PATHS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SYSMACROS_H + +/* Define if you have the 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 */ +#undef HAVE_AF_INET6 + +/* Define if `struct sockaddr_in6' exists in */ +#undef HAVE_SOCKADDR_IN6 + +/* Define if `struct addrinfo' exists in */ +#undef HAVE_ADDRINFO + +/* + * Define if 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 */ +#undef HAVE_WORKING_GLOB + +/* Define if crypt() is declared in */ +#undef HAVE_CRYPT_D + +/* Define if fclose() is declared in */ +#undef HAVE_FCLOSE_D + +/* Define if optarg is declared in or */ +#undef HAVE_OPTARG_D + +/* Define if optind is declared in or */ +#undef HAVE_OPTIND_D + +/* Define if optreset exists */ +#undef HAVE_OPTRESET + +/* Define if pclose() is declared in */ +#undef HAVE_PCLOSE_D + +/* Define if getusershell() is declared in */ +#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 000000000000..2a7563d59d8e --- /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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 < +/* 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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 < +/* 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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 < +#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 <&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 <&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 <&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 < +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 < +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 < +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 < +#include +#include +#include +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 +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 +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 < +#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 +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 <&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 < +#include +#include +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 < +#if STDC_HEADERS +#include +#include +#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 < +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 <&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 < +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 < +#include +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 < +#include +#include +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 < +#include +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 < +#include +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 < +#include +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 < +#include +#include +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 < +#else +# define dirent direct +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# 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 < +#include +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 <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 < +/* 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 <&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 < +/* 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 <&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 < +/* 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 <&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 < +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 < +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 < +#include +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 < +#include +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 < +#include +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 < +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 < +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 < + 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 < + 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 < +/* 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 <&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 < + #include + #include +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 < +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 < +/* 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 <&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 </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 < 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 <> $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 <> $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 <> $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 <> $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 000000000000..87331d04793a --- /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 ] , [ +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 +#include ], [ 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 +#include +#include ], [ + 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 +#include ], [ 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 +#include ], + [ int X = AF_INET6 ], [AC_DEFINE(HAVE_AF_INET6, 1)]) + + AC_MSG_TRY_COMPILE(for struct sockaddr_in6, ftp_cv_HAVE_SOCKADDR_IN6, [ +#include +#include ], + [ struct sockaddr_in6 X ], [AC_DEFINE(HAVE_SOCKADDR_IN6, 1)]) + +fi + +AC_MSG_TRY_COMPILE(for struct addrinfo, ftp_cv_HAVE_ADDRINFO, [ +#include +#include +#include ], + [ 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 +#else +# define dirent direct +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# 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 +#include ], + [ 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 ], [ char *(*X)() = crypt ], [AC_DEFINE(HAVE_CRYPT_D, 1)]) + +AC_MSG_TRY_COMPILE(for fclose() declaration, ftp_cv_HAVE_FCLOSE_D, [ +#include ], [ int (*X)() = fclose ], [AC_DEFINE(HAVE_FCLOSE_D, 1)]) + +AC_MSG_TRY_COMPILE(for optarg declaration, ftp_cv_HAVE_OPTARG_D, [ +#include +#include ], [ char *X = optarg ], [AC_DEFINE(HAVE_OPTARG_D, 1)]) + +AC_MSG_TRY_COMPILE(for optind declaration, ftp_cv_HAVE_OPTIND_D, [ +#include +#include ], [ int X = optind ], [AC_DEFINE(HAVE_OPTIND_D, 1)]) + +AC_MSG_TRY_LINK(for optreset, ftp_cv_HAVE_OPTRESET, [ +#include +#include ], [ int X = optreset ], [AC_DEFINE(HAVE_OPTRESET, 1)]) + +AC_MSG_TRY_COMPILE(for pclose() declaration, ftp_cv_HAVE_PCLOSE_D, [ +#include ], [ 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 ], [ 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 + 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 + 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 + #include + #include ], + [ 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 ], [ 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 000000000000..e9de23842dcd --- /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 000000000000..c697701616ca --- /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 +#include +#include +#include +#include +#include +#if HAVE_SYS_SYSMACROS_H +# include +#endif + +#include +#include +#include + +#if HAVE_FTP_NAMES +# include +#else +# include "arpaftp.h" +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_DIRENT_H +# include +#else +# define dirent direct +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#if HAVE_ERR_H +# include +#endif + +#if HAVE_WORKING_GLOB +# include +#else +# include "ftpglob.h" +#endif + +#if HAVE_PATHS_H +# include +#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 +#else +# include "ftpfts.h" +#endif + +#if HAVE_UTIL_H +# include +#endif + +#if HAVE_LIBUTIL_H +# include +#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 000000000000..e4fe6c6f7e8d --- /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 000000000000..52be7c154b34 --- /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 000000000000..51efbb8f252c --- /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 000000000000..19b928393976 --- /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 : ""); + 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 : ""); + 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- + * 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 000000000000..15cf939a4a5c --- /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 + +#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" : \ + "" + +#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 000000000000..aeea190dc51e --- /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 STRING +%token ALL +%token NUMBER + +%type check_login octal_number byte_size +%type struct_code mode_code type_code form_code decimal_integer +%type pathstring pathname password username +%type mechanism_name base64data prot_code + +%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, " username" }, + { "PASS", PASS, ZSTR1, 1, " password" }, + { "ACCT", ACCT, STR1, 0, "(specify account)" }, + { "CWD", CWD, OSTR, 1, "[ 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, " b0, b1, b2, b3, b4" }, + { "LPRT", LPRT, ARGS, 1, " af, hal, h1, h2, h3,..., pal, p1, p2..." }, + { "EPRT", EPRT, STR1, 1, " |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, "[ af|ALL]" }, + { "TYPE", TYPE, ARGS, 1, " [ A | E | I | L ]" }, + { "STRU", STRU, ARGS, 1, "(specify file structure)" }, + { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, + { "RETR", RETR, STR1, 1, " file-name" }, + { "STOR", STOR, STR1, 1, " file-name" }, + { "STOU", STOU, STR1, 1, " file-name" }, + { "APPE", APPE, STR1, 1, " file-name" }, + { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, + { "REST", REST, ARGS, 1, " offset (restart command)" }, + { "RNFR", RNFR, STR1, 1, " file-name" }, + { "RNTO", RNTO, STR1, 1, " file-name" }, + { "ABOR", ABOR, NOARGS, 4, "(abort operation)" }, + { "DELE", DELE, STR1, 1, " file-name" }, + { "RMD", RMD, STR1, 1, " path-name" }, + { "MKD", MKD, STR1, 1, " path-name" }, + { "PWD", PWD, NOARGS, 1, "(return current directory)" }, + { "LIST", LIST, OSTR, 1, "[ path-name ]" }, + { "NLST", NLST, OSTR, 1, "[ path-name ]" }, + { "SITE", SITE, SITECMD, 1, "site-cmd [ arguments ]" }, + { "SYST", SYST, NOARGS, 1, "(get type of operating system)" }, + { "STAT", STAT, OSTR, 4, "[ path-name ]" }, + { "HELP", HELP, OSTR, 1, "[ ]" }, + { "NOOP", NOOP, NOARGS, 2, "" }, + + /* From RFC 2228, in order defined */ + { "AUTH", AUTH, STR1, 1, " mechanism-name" }, + { "ADAT", ADAT, STR1, 1, " base-64-data" }, + { "PROT", PROT, STR1, 1, " prot-code" }, + { "PBSZ", PBSZ, ARGS, 1, " decimal-integer" }, + { "CCC", CCC, NOARGS, 1, "(Disable data protection)" }, + { "MIC", MIC, STR1, 4, " base64data" }, + { "CONF", CONF, STR1, 4, " base64data" }, + { "ENC", ENC, STR1, 4, " base64data" }, + + /* From RFC 2389, in order defined */ + { "FEAT", FEAT, NOARGS, 1, "(display extended features)" }, + { "OPTS", OPTS, STR1, 1, " command [ options ]" }, + + /* from draft-ietf-ftpext-mlst-11 */ + { "MDTM", MDTM, OSTR, 1, " path-name" }, + { "SIZE", SIZE, OSTR, 1, " path-name" }, + { "MLST", MLST, OSTR, 2, "[ path-name ]" }, + { "MLSD", MLSD, OSTR, 1, "[ 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, "[ directory-name ]" }, + { "XMKD", MKD, STR1, 1, " path-name" }, + { "XPWD", PWD, NOARGS, 1, "(return current directory)" }, + { "XRMD", RMD, STR1, 1, " path-name" }, + + { NULL, 0, 0, 0, 0 } +}; + +struct tab sitetab[] = { + { "CHMOD", CHMOD, NSTR, 1, " mode file-name" }, + { "HELP", HELP, OSTR, 1, "[ ]" }, + { "IDLE", IDLE, ARGS, 1, "[ maximum-idle-time ]" }, + { "RATEGET", RATEGET,OSTR, 1, "[ get-throttle-rate ]" }, + { "RATEPUT", RATEPUT,OSTR, 1, "[ put-throttle-rate ]" }, + { "UMASK", UMASK, ARGS, 1, "[ umask ]" }, + { NULL, 0, 0, 0, NULL } +}; + +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 + +/* + * 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 000000000000..65f993a484a8 --- /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 . +.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 000000000000..c5c2f2e20858 --- /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 +#endif + +#include + +#ifdef SKEY +#include +#endif +#ifdef KERBEROS5 +#include +#include +#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) ? "" : 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 " = bytes" + * else if file2 != NULL " " + * else " " + * 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 000000000000..0c7dc687bda9 --- /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 000000000000..85f500f09292 --- /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 000000000000..7ef643719844 --- /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 000000000000..b7f2925ab596 --- /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 000000000000..a5766b5bce4c --- /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 000000000000..7e8d0366c27b --- /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 000000000000..1a075c7c8f6d --- /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 000000000000..83ca631a2b2b --- /dev/null +++ b/contrib/lukemftpd/todo @@ -0,0 +1,17 @@ +autoconf checks: + - HAVE_FTP_NAMES if FTP_NAMES et al in + - 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