diff -urN proftpd-1.2.6rc1.orig/Make.rules.in proftpd-1.2.6rc1-tls/Make.rules.in --- proftpd-1.2.6rc1.orig/Make.rules.in Tue Jun 11 18:18:05 2002 +++ proftpd-1.2.6rc1-tls/Make.rules.in Wed Jul 3 10:54:31 2002 @@ -58,10 +58,10 @@ #CFLAGS=-g -pedantic -DUSESHADOW -DDEBUG_NOFORK OBJS=main.o timers.o sets.o pool.o dirtree.o support.o inet.o log.o \ - io.o ident.o data.o modules.o auth.o fs.o + io.o ident.o data.o modules.o auth.o fs.o @TLS_OBJS@ BUILD_OBJS=src/main.o src/timers.o src/sets.o src/pool.o src/dirtree.o \ src/support.o src/inet.o src/log.o src/io.o src/ident.o \ - src/data.o src/modules.o src/auth.o src/fs.o + src/data.o src/modules.o src/auth.o src/fs.o @TLS_BUILD_OBJS@ LIB_OBJS=getopt.o getopt1.o pr_fnmatch.o strsep.o vsnprintf.o glibc-glob.o \ glibc-mkstemp.o pwgrent.o diff -urN proftpd-1.2.6rc1.orig/README.TLS proftpd-1.2.6rc1-tls/README.TLS --- proftpd-1.2.6rc1.orig/README.TLS Thu Jan 1 01:00:00 1970 +++ proftpd-1.2.6rc1-tls/README.TLS Mon Jun 10 11:56:48 2002 @@ -0,0 +1,147 @@ +TLS patch for proftpd-1.2.5 together with OpenSSL >= 0.9.4, based on the +"draft-murray-auth-ftp-ssl-09.txt" IETF draft. +Copyright (c) 2000 Peter 'Luna' Runestig +The verify_crl() function by Ralf S. Engelschall +This product includes software developed by the OpenSSL Project +for use in the OpenSSL Toolkit. (http://www.openssl.org/) +This product includes cryptographic software written by +Eric Young (eay@cryptsoft.com) + +Patching: + $ tar xzf proftpd-1.2.5.tar.gz + $ cd proftpd-1.2.5 + $ patch -p1 < ../proftpd-tls.current.patch + + Or just use the prepatched tarball. + +Configuring: + $ ./configure [--with-openssl-dir=DIR] + +Building: + $ make + +Installation: + $ make install + +By default, proftpd looks for a single configuration file at +/usr/local/etc/proftpd.conf. Copy sample-configurations/basic.conf to +/usr/local/etc/proftpd.conf and modify to suit your needs. More advanced +configuration examples are also included. + +The proftpd server tries to use these TLS related files by default: +ftpd-rsa.pem RSA certificate, may include private key +ftpd-rsa-key.pem RSA private key +ftpd-dsa.pem DSA certificate, may include private key +ftpd-dsa-key.pem DSA private key +ftpd-crl.pem Certificate Revokation List +ftpd-dhparam.pem DH Parameters (a set of DH params is compiled in) + +These files is searched for in the following directorys (in this order): +* Current working directory of the process. +* Specified by the `X509_get_default_cert_dir_env()` environment variable + (usually $SSL_CERT_DIR). +* `X509_get_default_cert_dir()`, usually (openssl-dir)/certs. +* `X509_get_default_private_dir()`, usually (openssl-dir/private. + +Default CRL directory for the proftpd server is (openssl-dir)/crl. + +If you don't have any "proper" certificate files (signed by some CA), you might +create a self-signed one using the ``openssl'' command: +$ openssl req -new -x509 -days 365 -nodes -out ftpd-rsa.pem -keyout ftpd-rsa-key.pem +This creates a cert which is valid 365 days, you might want to adjust that. + +X509 client authentication +-------------------------- +Support for user authentication is possible through the custom function +int x509_to_user(X509 *peer_cert, char *userid, int len) in the file +src/x509_to_user.c, and by a .tlslogin file in the user's home directory. + +o tls_userid_from_client_cert() is called and returns a user id or NULL. + tls_userid_from_client_cert() calls the site specific function + x509_to_user(). + +o If the user name, set by the USER command, equals the user id mapped from the + client cert, the user is logged right in. + +o If "USER" differ from the user id mapped from the client cert the function + tls_is_user_valid() is called to check "USER"'s ~/.tlslogin file. + That file, if it exist, contains one or more X509 certificates in PEM for- + mat. If the client cert is present in the file, the user is logged right in. + +o If tls_userid_from_client_cert() can't map a user id from the client cert, + tls_is_user_valid() is called to check "USER"'s ~/.tlslogin file. If the + client cert is present in the file, the user is logged right in. + +Hash symlinks for certs: ln -s cert.pem `openssl x509 -hash -noout -in cert.pem`.0 +Hash symlinks for CRLs: ln -s crl.pem `openssl crl -hash -noout -in crl.pem`.r0 + +Default cipher list is "ALL:!EXP". + +How to put together a 'cipher list string': + Key Exchange Algorithms: + "kRSA" RSA key exchange + "kDHr" Diffie-Hellman key exchange (key from RSA cert) + "kDHd" Diffie-Hellman key exchange (key from DSA cert) + "kEDH' Ephemeral Diffie-Hellman key exchange (temporary key) + + Authentication Algorithm: + "aNULL" No authentication + "aRSA" RSA authentication + "aDSS" DSS authentication + "aDH" Diffie-Hellman authentication + + Cipher Encoding Algorithm: + "eNULL" No encodiing + "DES" DES encoding + "3DES" Triple DES encoding + "RC4" RC4 encoding + "RC2" RC2 encoding + "IDEA" IDEA encoding + + MAC Digest Algorithm: + "MD5" MD5 hash function + "SHA1" SHA1 hash function + "SHA" SHA hash function (should not be used) + + Aliases: + "ALL" all ciphers + "SSLv2" all SSL version 2.0 ciphers (should not be used) + "SSLv3" all SSL version 3.0 ciphers + "EXP" all export ciphers (40-bit) + "EXPORT56" all export ciphers (56-bit) + "LOW" all low strength ciphers (no export) + "MEDIUM" all ciphers with 128-bit encryption + "HIGH" all ciphers using greater than 128-bit encryption + "RSA" all ciphers using RSA key exchange + "DH" all ciphers using Diffie-Hellman key exchange + "EDH" all ciphers using Ephemeral Diffie-Hellman key exchange + "ADH" all ciphers using Anonymous Diffie-Hellman key exchange + "DSS" all ciphers using DSS authentication + "NULL" all ciphers using no encryption + +Each item in the list may include a prefix modifier: + + "+" move cipher(s) to the current location in the list + "-" remove cipher(s) from the list (may be added again by + a subsequent list entry) + "!" kill cipher from the list (it may not be added again + by a subsequent list entry) + +If no modifier is specified the entry is added to the list at the current +position. "+" may also be used to combine tags to specify entries such as +"RSA+RC4" describes all ciphers that use both RSA and RC4. + +For example, all available ciphers not including ADH key exchange: + + ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP + +All algorithms including ADH and export but excluding patented algorithms: + + HIGH:MEDIUM:LOW:EXPORT56:EXP:ADH:!kRSA:!aRSA:!RC4:!RC2:!IDEA + +The OpenSSL command + + openssl ciphers -v + +may be used to list all of the ciphers and the order described by a specific +. diff -urN proftpd-1.2.6rc1.orig/acconfig.h proftpd-1.2.6rc1-tls/acconfig.h --- proftpd-1.2.6rc1.orig/acconfig.h Sat Mar 17 21:34:31 2001 +++ proftpd-1.2.6rc1-tls/acconfig.h Mon Jun 10 11:56:48 2002 @@ -18,6 +18,12 @@ /* Define if you have BSD sendfile() semantics */ #undef HAVE_BSD_SENDFILE +/* Define to build with SSL/TLS support */ +#undef TLS + +/* Define this symbol if support for OpenSSL zlib compression is enabled. */ +#undef ZLIB + /* Define if you have Linux sendfile() semantics */ #undef HAVE_LINUX_SENDFILE diff -urN proftpd-1.2.6rc1.orig/config.h.in proftpd-1.2.6rc1-tls/config.h.in --- proftpd-1.2.6rc1.orig/config.h.in Fri Jun 28 00:36:25 2002 +++ proftpd-1.2.6rc1-tls/config.h.in Wed Jul 3 10:54:31 2002 @@ -19,6 +19,12 @@ /* Define if you have BSD sendfile() semantics */ #undef HAVE_BSD_SENDFILE +/* Define to build with SSL/TLS support */ +#undef TLS + +/* Define this symbol if support for OpenSSL zlib compression is enabled. */ +#undef ZLIB + /* Define if you have Linux sendfile() semantics */ #undef HAVE_LINUX_SENDFILE @@ -423,7 +429,7 @@ /* Define if you have the header file. */ #undef HAVE_UTMPX_H -/* Define if you have the "vmsdir.h" header file. */ +/* Define if you have the header file. */ #undef HAVE_VMSDIR_H /* Define if you have the bind library (-lbind). */ diff -urN proftpd-1.2.6rc1.orig/configure proftpd-1.2.6rc1-tls/configure --- proftpd-1.2.6rc1.orig/configure Fri Jun 28 00:39:29 2002 +++ proftpd-1.2.6rc1-tls/configure Wed Jul 3 11:18:14 2002 @@ -838,6 +838,8 @@ --enable-shadow force compilation of shadowed password support + --disable-tls disable TLS security + --enable-tls_zlib enable use of OpenSSL zlib compression (EXPERIMENTAL) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -854,6 +856,7 @@ LIST is a ':' separated list of modules to add e.g. --with-modules=mod_pam:mod_readme + --with-openssl-dir=DIR specify location of the OpenSSL directory Some influential environment variables: CC C compiler command @@ -3495,6 +3498,32 @@ fi +# Check whether --with-openssl-dir or --without-openssl-dir was given. +if test "${with_openssl_dir+set}" = set; then + withval="$with_openssl_dir" + OPENSSLDIR=$withval +fi; +if test -n "$OPENSSLDIR"; then + LIBS="$LIBS -L$OPENSSLDIR/lib" + CPPFLAGS="$CPPFLAGS -I$OPENSSLDIR/include" +fi + +# Check whether --enable-tls or --disable-tls was given. +if test "${enable_tls+set}" = set; then + enableval="$enable_tls" + +else + enable_tls=yes +fi; +# Check whether --enable-tls_zlib or --disable-tls_zlib was given. +if test "${enable_tls_zlib+set}" = set; then + enableval="$enable_tls_zlib" + +else + enable_tls_zlib=no +fi; + + echo "$as_me:$LINENO: checking for set_auth_parameters in -lsecurity" >&5 echo $ECHO_N "checking for set_auth_parameters in -lsecurity... $ECHO_C" >&6 if test "${ac_cv_lib_security_set_auth_parameters+set}" = set; then @@ -10449,6 +10478,216 @@ esac fi +if test "$enable_tls" = yes; then + # look for OpenSSL libraries + echo "$as_me:$LINENO: checking for X509_STORE_load_locations in -lcrypto" >&5 +echo $ECHO_N "checking for X509_STORE_load_locations in -lcrypto... $ECHO_C" >&6 +if test "${ac_cv_lib_crypto_X509_STORE_load_locations+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char X509_STORE_load_locations (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +X509_STORE_load_locations (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_crypto_X509_STORE_load_locations=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_crypto_X509_STORE_load_locations=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_X509_STORE_load_locations" >&5 +echo "${ECHO_T}$ac_cv_lib_crypto_X509_STORE_load_locations" >&6 +if test $ac_cv_lib_crypto_X509_STORE_load_locations = yes; then + LIBTLS=-lcrypto +else + { { echo "$as_me:$LINENO: error: Could not find OpenSSL library needed for SSL/TLS support. Try again using --with-openssl-dir=DIR" >&5 +echo "$as_me: error: Could not find OpenSSL library needed for SSL/TLS support. Try again using --with-openssl-dir=DIR" >&2;} + { (exit 1); exit 1; }; } +fi + + echo "$as_me:$LINENO: checking for SSL_accept in -lssl" >&5 +echo $ECHO_N "checking for SSL_accept in -lssl... $ECHO_C" >&6 +if test "${ac_cv_lib_ssl_SSL_accept+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lssl -lcrypto $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char SSL_accept (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +SSL_accept (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ssl_SSL_accept=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_ssl_SSL_accept=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_ssl_SSL_accept" >&5 +echo "${ECHO_T}$ac_cv_lib_ssl_SSL_accept" >&6 +if test $ac_cv_lib_ssl_SSL_accept = yes; then + LIBTLS="-lssl $LIBTLS" +else + { { echo "$as_me:$LINENO: error: Could not find OpenSSL library needed for SSL/TLS support. Try again using --with-openssl-dir=DIR" >&5 +echo "$as_me: error: Could not find OpenSSL library needed for SSL/TLS support. Try again using --with-openssl-dir=DIR" >&2;} + { (exit 1); exit 1; }; } +fi + + ac_core_modules="$ac_core_modules mod_tls.o" + ac_build_core_modules="$ac_build_core_modules modules/mod_tls.o" + TLS_OBJS="tlsutil.o x509_to_user.o" + TLS_BUILD_OBJS="src/tlsutil.o src/x509_to_user.o" + + + cat >>confdefs.h <<\_ACEOF +#define TLS 1 +_ACEOF + + if test "$enable_tls_zlib" = yes; then + echo "$as_me:$LINENO: checking for compress in -lz" >&5 +echo $ECHO_N "checking for compress in -lz... $ECHO_C" >&6 +if test "${ac_cv_lib_z_compress+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lz $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char compress (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +compress (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_z_compress=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_z_compress=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_z_compress" >&5 +echo "${ECHO_T}$ac_cv_lib_z_compress" >&6 +if test $ac_cv_lib_z_compress = yes; then + LIBS="$LIBS -lz" +else + { { echo "$as_me:$LINENO: error: Could not find ZLIB library needed." >&5 +echo "$as_me: error: Could not find ZLIB library needed." >&2;} + { (exit 1); exit 1; }; } +fi + + cat >>confdefs.h <<\_ACEOF +#define ZLIB 1 +_ACEOF + + fi + LIBS="$LIBS $LIBTLS" +fi + for ac_func in setproctitle do @@ -11740,10 +11979,13 @@ s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@RANLIB@,$RANLIB,;t t s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@OPENSSLDIR@,$OPENSSLDIR,;t t s,@CPP@,$CPP,;t t s,@install_user@,$install_user,;t t s,@install_group@,$install_group,;t t s,@ALLOCA@,$ALLOCA,;t t +s,@TLS_OBJS@,$TLS_OBJS,;t t +s,@TLS_BUILD_OBJS@,$TLS_BUILD_OBJS,;t t s,@MODULES@,$MODULES,;t t s,@BUILD_MODULES@,$BUILD_MODULES,;t t s,@ADDL_DIRS@,$ADDL_DIRS,;t t diff -urN proftpd-1.2.6rc1.orig/configure.in proftpd-1.2.6rc1-tls/configure.in --- proftpd-1.2.6rc1.orig/configure.in Fri Jun 28 00:36:25 2002 +++ proftpd-1.2.6rc1-tls/configure.in Wed Jul 3 10:54:31 2002 @@ -239,6 +239,20 @@ AC_DEFINE(HAVE__PW_STAYOPEN) fi +dnl TLS options +AC_ARG_WITH(openssl-dir, + [ --with-openssl-dir=DIR specify location of the OpenSSL directory], + OPENSSLDIR=$withval) +if test -n "$OPENSSLDIR"; then + LIBS="$LIBS -L$OPENSSLDIR/lib" + CPPFLAGS="$CPPFLAGS -I$OPENSSLDIR/include" +fi +AC_SUBST(OPENSSLDIR) +AC_ARG_ENABLE(tls, [ --disable-tls disable TLS security], + , enable_tls=yes) +AC_ARG_ENABLE(tls_zlib, [ --enable-tls_zlib enable use of OpenSSL zlib compression (EXPERIMENTAL)], + , enable_tls_zlib=no) + AC_CHECK_LIB(security, set_auth_parameters) AC_CHECK_HEADERS(sys/security.h) AC_CHECK_HEADERS(krb.h) @@ -536,6 +550,28 @@ esac fi +dnl TLS options +if test "$enable_tls" = yes; then + # look for OpenSSL libraries + AC_CHECK_LIB(crypto, X509_STORE_load_locations, LIBTLS=-lcrypto, + AC_MSG_ERROR(Could not find OpenSSL library needed for SSL/TLS support. Try again using --with-openssl-dir=DIR)) + AC_CHECK_LIB(ssl, SSL_accept, LIBTLS="-lssl $LIBTLS", + AC_MSG_ERROR(Could not find OpenSSL library needed for SSL/TLS support. Try again using --with-openssl-dir=DIR), -lcrypto) + ac_core_modules="$ac_core_modules mod_tls.o" + ac_build_core_modules="$ac_build_core_modules modules/mod_tls.o" + TLS_OBJS="tlsutil.o x509_to_user.o" + TLS_BUILD_OBJS="src/tlsutil.o src/x509_to_user.o" + AC_SUBST(TLS_OBJS) + AC_SUBST(TLS_BUILD_OBJS) + AC_DEFINE(TLS) + if test "$enable_tls_zlib" = yes; then + AC_CHECK_LIB(z, compress, LIBS="$LIBS -lz", + AC_MSG_ERROR(Could not find ZLIB library needed.)) + AC_DEFINE(ZLIB) + fi + LIBS="$LIBS $LIBTLS" +fi + dnl Check for various argv[] replacing functions on various OSs AC_CHECK_FUNCS(setproctitle) AC_CHECK_HEADERS(libutil.h) diff -urN proftpd-1.2.6rc1.orig/contrib/dist/rpm/proftpd.spec.in proftpd-1.2.6rc1-tls/contrib/dist/rpm/proftpd.spec.in --- proftpd-1.2.6rc1.orig/contrib/dist/rpm/proftpd.spec.in Sun May 19 16:38:42 2002 +++ proftpd-1.2.6rc1-tls/contrib/dist/rpm/proftpd.spec.in Thu Jul 11 21:03:37 2002 @@ -1,21 +1,45 @@ # $Id: proftpd.spec.in,v 1.14 2002/05/19 14:38:42 jwm Exp $ # +%define tls 1 +%if %{tls} +%define TLSVERSION 20020711 +%define TLSVERSIONRELEASE 1 +%endif +%if %{tls} +Summary: ProFTPD -- Professional FTP Server (TLS enabled). +%else Summary: ProFTPD -- Professional FTP Server. +%endif Name: proftpd Version: @VERSION@ +%if %{tls} +Release: 1.tls.%{TLSVERSION}.%{TLSVERSIONRELEASE} +%else Release: 1 +%endif Copyright: GPL Group: System Environment/Daemons -Packager: Daniel Roesen +Packager: Daniel Roesen and Dr. Peter Bieringer (TLS) Vendor: The ProFTPD Group URL: http://www.proftpd.org/ Source: ftp://ftp.proftpd.org/distrib/%{name}-%{version}.tar.gz +%if %{tls} +Patch0: ftp://ftp.runestig.com/pub/%{name}-%{version}-tls.%{TLSVERSION}.patch.gz +%endif Prefix: /usr +%if %{tls} +BuildRoot: %{_builddir}/%{name}-%{version}-%{TLSVERSION}-root +Requires: pam >= 0.72, openssl +%else BuildRoot: %{_builddir}/%{name}-%{version}-root Requires: pam >= 0.72 +%endif Provides: ftpserver Prereq: fileutils Obsoletes: proftpd-core +%if %{tls} +BuildPreReq: openssl-devel +%endif %description ProFTPD is an enhanced FTP server with a focus toward simplicity, security, @@ -26,6 +50,9 @@ There are two other packages you can use to setup for inetd or standalone operation. +%if %{tls} +This package is TLS enabled, used TLS patch version is: %{TLSVERSION} +%endif %package standalone Summary: ProFTPD -- Setup for standalone operation. @@ -39,7 +66,7 @@ %package inetd Summary: ProFTPD -- Setup for inetd operation. Group: System Environment/Daemons -Requires: proftpd +Requires: proftpd-tls Obsoletes: proftpd-standalone %description inetd @@ -47,6 +74,9 @@ %prep %setup -q +%if %{tls} +%patch0 -p1 +%endif CFLAGS="$RPM_OPT_FLAGS" ./configure \ --prefix=%{prefix} \ --sysconfdir=/etc \ @@ -178,6 +208,9 @@ - Added use of %defattr to allow build of RPMs by non-root users For details see http://bugs.proftpd.org/show_bug.cgi?id=1580 +* Mon May 07 2001 Dr. Peter Bieringer +- Make "tls" usage switchable + * Mon Mar 05 2001 Daniel Roesen - PAM >= 0.72 is now a requirement. Versions before are broken and Red Hat provides a PAM update for all RH 6.x releases. See: diff -urN proftpd-1.2.6rc1.orig/doc/rfc/draft-murray-auth-ftp-ssl-09.txt proftpd-1.2.6rc1-tls/doc/rfc/draft-murray-auth-ftp-ssl-09.txt --- proftpd-1.2.6rc1.orig/doc/rfc/draft-murray-auth-ftp-ssl-09.txt Thu Jan 1 01:00:00 1970 +++ proftpd-1.2.6rc1-tls/doc/rfc/draft-murray-auth-ftp-ssl-09.txt Mon Jun 10 11:56:48 2002 @@ -0,0 +1,1679 @@ + + + + + + + Paul Ford-Hutchinson + IBM UK Ltd + Martin Carpenter + Verisign Inc + Tim Hudson +INTERNET-DRAFT (draft) RSA Australia Ltd + Eric Murray + Wave Systems Inc + Volker Wiegand + SuSE Linux + + 2nd April, 2002 +This document expires on 2nd October, 2002 + + + Securing FTP with TLS + + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/1id-abstracts.txt + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 1] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + +Index + 1. .......... Abstract + 2. .......... Introduction + 3. .......... Audience + 4. .......... Session negotiation on the control port + 5. .......... Response to FEAT command + 6. .......... Data Connection Behaviour + 7. .......... Mechanisms for the AUTH Command + 8. .......... Data Connection Security + 9. .......... A discussion of negotiation behaviour + 10. ......... Who negotiates what, where and how + 11. ......... Timing Diagrams + 12. ......... Discussion of the REIN command + 13. ......... Discussion of the STAT and ABOR commands + 14. ......... Security Considerations + 15. ......... IANA Considerations + 16. ......... Other Parameters + 17. ......... Network Management + 18. ......... Internationalization + 19. ......... Scalability & Limits + 20. ......... Applicability + 21. ......... Acknowledgements + 22. ......... References + 23. ......... Authors' Contact Addresses + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 2] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + +1. Abstract + + This document describes a mechanism that can be used by FTP clients + and servers to implement security and authentication using the TLS + protocol defined by [RFC-2246] and the extensions to the FTP protocol + defined by [RFC-2228]. It describes the subset of the extensions + that are required and the parameters to be used; discusses some of + the policy issues that clients and servers will need to take; + considers some of the implications of those policies and discusses + some expected behaviours of implementations to allow interoperation. + This document is intended to provide TLS support for FTP in a similar + way to that provided for SMTP in [RFC-2487] and HTTP in [RFC-2817]. + + TLS is not the only mechanism for securing file transfer, however it + does offer some of the following positive attributes:- + + - Flexible security levels. TLS can support confidentiality, + integrity, authentication or some combination of all of these. + This allows clients and servers to dynamically, during a session, + decide on the level of security required for a particular data + transfer, + + - It is possible to use TLS identities to authenticate client + users and not just client hosts. + + - Formalised public key management. By use of well established + client identity mechnisms (supported by TLS) during the + authentication phase, certificate management may be built into a + central function. Whilst this may not be desirable for all uses + of secured file transfer, it offers advantages in certain + structured environments. + + - Co-existence and interoperation with authentication mechanisms + that are already in place for the HTTPS protocol. This allows web + browsers to incorporate secure file transfer using the same + infrastructure that has been set up to allow secure web browsing. + + The TLS protocol is a development of the Netscape Communication + Corporation's SSL protocol and this document can be used to allow the + FTP protocol to be used with either SSL or TLS. The actual protocol + used will be decided by the negotiation of the protected session by + the TLS/SSL layer. This document will only refer to the TLS + protocol, however, it is understood that the Client and Server MAY + actually be using SSL if they are so configured. + + Note that this specification is in accordance with the FTP RFC + [RFC-959] and relies on the TLS protocol [RFC-2246] and the FTP + security extensions [RFC-2228]. + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 3] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + +2. Introduction + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", + "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" and + "OPTIONAL" that appear in this document are to be interpreted as + described in [RFC-2119]. + + This document is an attempt to describe how three other documents + should combined to provide a useful, interoperable, secure file + transfer protocol. Those documents are:- + + + RFC 959 [RFC-959] + + The description of the Internet File Transfer Protocol + + RFC 2246 [RFC-2246] + + The description of the Transport Layer Security protocol + (developed from the Netscape Secure Sockets Layer (SSL) + protocol version 3.0). + + RFC 2228 [RFC-2228] + + Extensions to the FTP protocol to allow negotiation of security + mechanisms to allow authentication, confidentiality and message + integrity. + + The File Transfer Protocol (FTP) currently defined in [RFC-959] and + in place on the Internet is an excellent mechanism for exchanging + files. The security extensions to FTP in [RFC-2228] offer a + comprehensive set of commands and responses that can be used to add + authentication, integrity and confidentiality to the FTP protocol. + The TLS protocol is a popular (due to its wholesale adoption in the + HTTP environment) mechanism for generally securing a socket + connection. + There are many ways in which these three protocols can be combined + which would ensure that interoperation is impossible. This document + describes one method by which FTP can operate securely in such a way + as to provide both flexibility and interoperation. This necessitates + a brief description of the actual negotiation mechanism ; a much more + detailed description of the policies and practices that would be + required and a discussion of the expected behaviours of clients and + servers to allow either party to impose their security requirements + on the FTP session. + + +3. Audience + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 4] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + This document is aimed at developers who wish to implement TLS as a + security mechanism to secure FTP clients and/or servers. + + +4. Session negotiation on the control port + + The server listens on the normal FTP control port {FTP-PORT} and the + session initiation is not secured at all. Once the client wishes to + secure the session, the AUTH command is sent and the server MAY then + allow TLS negotiation to take place. + + 4.1 Client wants a secured session + + If a client wishes to attempt to secure a session then it SHOULD, + in accordance with [RFC-2228] send the AUTH command with the + parameter requesting TLS {TLS-PARM}. + + + The client then needs to behave according to its policies depending + on the response received from the server and also the result of the + TLS negotiation. i.e. A client which receives an AUTH rejection + MAY choose to continue with the session unprotected if it so + desires. + + 4.2 Server wants a secured session + + The FTP protocol does not allow a server to directly dictate client + behaviour, however the same effect can be achieved by refusing to + accept certain FTP commands until the session is secured to an + acceptable level to the server. + + The server response to an 'AUTH TLS' command which it will honour, is + '234'. + + Note. The '334' response as defined in [RFC-2228] implies that an + ADAT exchange will folow. This document does not use the ADAT + command and so the '334' reply is incorrect. + + Note. The FTP protocol insists that a USER command be used to + identify the entity attempting to use the ftp server. Although the + TLS negotiation may be providing authentication information the USER + command must still be isssued by the client. However, it will be a + server implementation issue to decide which credentials to accept and + what consistency checks to make between any client cert used and the + parameter on the USER command. + +5. Response to the FEAT command + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 5] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + The FEAT command (introduced in [RFC-2389]) allows servers with + additional features to advertise these to a client by responding to + the FEAT command. If a server supports the FEAT command then it MUST + advertise supported AUTH, PBSZ and PROT commands in the reply as + described in section 3.2 of [RFC-2389]. Additionally, the AUTH + command should have a reply that identifies 'TLS' as one of the + possible parameters to AUTH. It is not necessary to identify the + 'TLS-C' synonym separately. + + Example reply (in same style is [RFC-2389]) + C> FEAT + S> 211-Extensions supported + S> AUTH TLS + S> PBSZ + S> PROT + S> 211 END + + +6. Data Connection Behaviour + + The Data Connection in the FTP model can be used in one of three + ways. (Note: these descriptions are not necessarily placed in exact + chronological order, but do describe the steps required. - See + diagrams later for clarification) + + i) Classic FTP client/server data exchange + + - The client obtains a port; sends the port number to the + server; the server connects to the client. The client issues a + send or receive request to the server on the control connection + and the data transfer commences on the data connection. + + ii) Firewall-Friendly client/server data exchange (as discussed + in [RFC-1579]) using the PASV command to reverse the direction + of the data connection. + + - The client requests that the server open a port; the server + obtains a port and returns the address and port number to the + client; the client connects to the server on this port. The + client issues a send or receive request on the control + connection and the data transfer commences on the data + connection. + + iii) Client initiated server/server data exchange (proxy or + PASV connections) + + - The client requests that server A opens a port; server A + obtains a port and returns it to the client; the client sends + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 6] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + this port number to server B. Server B connects to server A. + The client sends a send or receive request to server A and the + complement to server B and the data transfer commences. In + this model server A is the proxy or PASV host and is a client + for the Data Connection to server B. + + For i) and ii) the FTP client MUST be the TLS client and the FTP + server MUST be the TLS server. + + That is to say, it does not matter which side initiates the + connection with a connect() call or which side reacts to the + connection via the accept() call; the FTP client as defined in + [RFC-959] is always the TLS client as defined in [RFC-2246]. + + In scenario iii) there is a problem in that neither server A nor + server B is the TLS client given the fact that an FTP server must act + as a TLS server for Firewall-Friendly FTP [RFC-1579]. Thus this is + explicitly excluded in the security extensions document [RFC-2228], + and in this document. + + + +7. Mechanisms for the AUTH Command + + The AUTH command takes a single parameter to define the security + mechanism to be negotiated. As the SSL/TLS protocols self-negotiate + their levels there is no need to distinguish SSL vs TLS in the + application layer. The proposed mechanism name for negotiating TLS + will be the character string identified in {TLS-PARM}. This will + allow the client and server to negotiate TLS on the control + connection without altering the protection of the data channel. To + protect the data channel as well, the PBSZ:PROT command sequence MUST + be used. + + Note: The data connection state MAY be modified by the client issuing + the PROT command with the new desired level of data channel + protection and the server replying in the affirmative. This data + channel protection negotiation can happen at any point in the session + (even straight after a PORT or PASV command) and as often as is + required. + + See also Section 15, "IANA Considerations". + + +8. Data Connection Security + + The Data Connection security level is determined by the PROT command + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 7] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + The PROT command, as specified in [RFC-2228] allows client/server + negotiation of the security level of the data connection. Once a + PROT command has been issued by the client and accepted by the + server returning the '200' reply, the security of subsequent data + connections MUST be at that level until another PROT command is + issued and accepted; the session ends; a REIN command is issued; + or the security of the session (via an AUTH command) is re- + negotiated. + + Data Connection Security Negotiation (the PROT command) + + Note: In line with [RFC-2228], there is no facility for securing + the Data connection with an insecure Control connection. + Specifically, the PROT command MUST be preceded by a PBSZ command + and a PBSZ command MUST be preceded by a successful security data + exchange (the TLS negotiation in this case) + + The command defined in [RFC-2228] to negotiate data connection + security is the PROT command. As defined there are four values + that the PROT command parameter can take. + + 'C' - Clear - neither Integrity nor Privacy + + 'S' - Safe - Integrity without Privacy + + 'E' - Confidential - Privacy without Integrity + + 'P' - Private - Integrity and Privacy + + As TLS negotiation encompasses (and exceeds) the Safe / + Confidential / Private distinction, only Private (use TLS) and + Clear (don't use TLS) are used. + + For TLS, the data connection can have one of two security levels. + + 1)Clear (requested by 'PROT C') + + 2)Private (requested by 'PROT P') + + With 'Clear' protection level, the data connection is made without + TLS at all. Thus the connection is unauthenticated and has no + confidentiality or integrity. This might be the desired behaviour + for servers sending file lists, pre-encrypted data or non- + sensitive data (e.g. for anonymous FTP servers). + + If the data connection security level is 'Private' then a TLS + negotiation must take place on the data connection, to the + satisfaction of the Client and Server prior to any data being + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 8] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + transmitted over the connection. The TLS layers of the Client and + Server will be responsible for negotiating the exact TLS Cipher + Suites that will be used (and thus the eventual security of the + connection). + + + In addition, the PBSZ (protection buffer size) command, as + detailed in [RFC-2228], is compulsory prior to any PROT command. + This document also defines a data channel encapsulation mechanism + for protected data buffers. For FTP-TLS, which appears to the FTP + application as a streaming protection mechanism, this is not + required. Thus the PBSZ command must still be issued, but must + have a parameter of '0' to indicate that no buffering is taking + place and the data connection should not be encapsulated. + Note that PBSZ 0 is not in the grammar of [RFC-2228], section + 8.1, where it is stated: + PBSZ ::= any + decimal integer from 1 to (2^32)-1 + However it should be noted that using a value of '0' to mean a + streaming protocol is a reasonable use of '0' for that parameter + and is not ambiguous. + + Initial Data Connection Security + + The initial state of the data connection MUST be 'Clear' (this is + the behaviour as indicated by [RFC-2228].) + + +9. A Discussion of Negotiation Behaviour + + 9.1. The server's view of the control connection + + A server MAY have a policy statement somewhere that might: + + - Deny any command before TLS is negotiated (this might cause + problems if a SITE or some such command is required prior to + login) + - Deny certain commands before TLS is negotiated (such as USER, + PASS or ACCT) + - Deny insecure USER commands for certain users (e.g. not + ftp/anonymous) + - Deny secure USER commands for certain users (e.g. + ftp/anonymous) + - Define the level(s) of TLS to be allowed + - Define the CipherSuites allowed to be used (perhaps on a per + host/domain/... basis) + - Allow TLS authentication as a substitute for local + authentication. + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 9] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + - Define data connection policies (see next section) + + It is possible that the TLS negotiation may not be completed + satisfactorily for the server, in which case it can be one of + these states. + + The TLS negotiation failed completely + + In this case, the control connection should still be up in + unprotected mode and the server SHOULD issue an unprotected + '421' reply to end the session. + + The TLS negotiation completed successfully, but the server + decides that the session parameters are not acceptable (e.g. + Distinguished Name in the client certificate is not + permitted to use the server) + + In this case, the control connection should still be up in a + protected state, so the server MAY either continue to refuse to + service commands or issue a protected '421' reply and close the + connection. + + The TLS negotiation failed during the TLS handshake + + In this case, the control connection is in an unknown state and + the server SHOULD simply drop the control connection. + + Server code will be responsible for implementing the required + policies and ensuring that the client is prevented from + circumventing the chosen security by refusing to service those + commands that are against policy. + + 9.2. The server's view of the data connection + + The server can take one of four basic views of the data connection + + 1 - Don't allow encryption at all (in which case the PROT + command should not allow any value other than 'C' - if it is + allowed at all) + 2 - Allow the client to choose protection or not + 3 - Insist on data protection (in which case the PROT command + must be issued prior to the first attempted data transfer) + 4 - Decide on one of the above three for each and every data + connection + + The server SHOULD only check the status of the data protection + level (for options 3 and 4 above) on the actual command that will + initiate the data transfer (and not on the PORT or PASV). The + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 10] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + following commands, defined in [RFC-959] cause data connections to + be opened and thus may be rejected (before any 1xx) message due to + an incorrect PROT setting. + + + STOR + RETR + NLST + LIST + STOU + APPE + + + The reply to indicate that the PROT setting is incorrect is + '521 data connection cannot be opened with this PROT setting' + If the protection level indicates that TLS is required, then it + should be negotiated once the data connection is made. Thus, the + '150' reply only states that the command can be used given the + current PROT level. Should the server not like the TLS + negotiation then it will close the data port immediately and + follow the '150' command with a '522' reply indicating that the + TLS negotiation failed or was unacceptable. (Note: this means + that the application can pass a standard list of CipherSuites to + the TLS layer for negotiation and review the one negotiated for + applicability in each instance). + + It is quite reasonable for the server to insist that the data + connection uses a TLS cached session. This might be a cache of a + previous data connection or of the control connection. If this is + the reason for the the refusal to allow the data transfer then the + '522' reply should indicate this. + Note: this has an important impact on client design, but allows + servers to minimise the cycles used during TLS negotiation by + refusing to perform a full negotiation with a previously + authenticated client. + + It should be noted that the TLS authentication of the server will + be authentication of the server host itself and not a user on the + server host. + + 9.3. The client's view of the control connection + + In most cases it is likely that the client will be using TLS + because the server would refuse to interact insecurely. To allow + for this, clients SHOULD be able to be flexible enough to manage + the securing of a session at the appropriate time and still allow + the user/server policies to dictate exactly when in the session + the security is negotiated. + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 11] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + In the case where it is the client that is insisting on the + securing of the session, it will need to ensure that the + negotiations are all completed satisfactorily and will need to be + able to inform the user sensibly should the server not support, or + be prepared to use, the required security levels. + + Clients SHOULD be coded in such a manner as to allow the timing of + the AUTH, PBSZ and PROT commands to be flexible and dictated by + the server. It is quite reasonable for a server to refuse certain + commands prior to these commands, similarly it is quite possible + that a SITE or quoted command might be needed by a server prior to + the AUTH. A client MUST allow a user to override the timing of + these commands to suit a specific server. + For example, a client SHOULD NOT insist on sending the AUTH as the + first command in a session, nor should it insist on issuing a + PBSZ, PROT pair directly after the AUTH. This may well be the + default behaviour, but must be overridable by a user. + + Note: The TLS negotiation may not be completed satisfactorily for + the client, in which case it will be in one of these states: + + The TLS negotiation failed completely + + In this case, the control connection should still be up in + unprotected mode and the client should issue an unprotected + QUIT command to end the session. + + The TLS negotiation completed successfully, but the client + decides that the session parameters are not acceptable (e.g. + Distinguished Name in certificate is not the actual server + expected) + + In this case, the control connection should still be up in a + protected state, so the client should issue a protected QUIT + command to end the session. + + The TLS negotiation failed during the TLS handshake + + In this case, the control connection is in an unknown state + and the client should simply drop the control connection. + + 9.4. The client's view of the data connection + + Client security policies + + Clients do not typically have 'policies' as such, instead they + rely on the user defining their actions and, to a certain extent, + are reactive to the server policy. Thus a client will need to + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 12] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + have commands that will allow the user to switch the protection + level of the data connection dynamically, however, there may be a + general 'policy' that attempts all LIST and NLST commands on a + Clear connection first (and automatically switches to Private if + it fails). In this case there would need to be a user command + available to ensure that a given data transfer was not attempted + on an insecure data connection. + + Clients also need to understand that the level of the PROT setting + is only checked for a particular data transfer after that transfer + has been requested. Thus a refusal by the server to accept a + particular data transfer should not be read by the client as a + refusal to accept that data protection level in toto, as not only + may other data transfers be acceptable at that protection level, + but it is entirely possible that the same transfer may be accepted + at the same protection level at a later point in the session. + + It should be noted that the TLS authentication of the client + should be authentication of a user on the client host and not the + client host itself. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 13] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + +10. Who negotiates what, where and how + + 10.1. Do we protect at all ? + + Client issues 'AUTH TLS', server accepts or rejects. + If server needs AUTH, then it refuses to accept certain commands + until it gets a successfully protected session. + + 10.2. What level of protection do we use on the Control connection ? + + Decided entirely by the TLS CipherSuite negotiation. + + 10.3. Do we protect data connections in general ? + + Client issues PROT command, server accepts or rejects. + + + 10.4. Is protection required for a particular data transfer ? + + A client would already have issued a PROT command if it required + the connection to be protected. + If a server needs to have the connection protected then it will + reply to the STOR/RETR/NLST/... command with a '522' indicating + that the current state of the data connection protection level is + not sufficient for that data transfer at that time. + + 10.5. What level of protection is required for a particular data + transfer ? + + Decided entirely by the TLS CipherSuite negotiation. + + Thus it can be seen that, for flexibility, it is desirable for the + FTP application to be able to interact with the TLS layer upon which + it sits to define and discover the exact TLS CipherSuites that are to + be/have been negotiated and make decisions accordingly. + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 14] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + +11. Timing Diagrams + + 11.1. Establishing a protected session + + Client Server + control data data control +==================================================================== + + socket() + bind() + socket() + connect() ----------------------------------------------> accept() + <---------------------------------------------- 220 + AUTH TLS ----------------------------------------------> + <---------------------------------------------- 234 + TLSneg() <----------------------------------------------> TLSneg() + PBSZ 0 ----------------------------------------------> + <---------------------------------------------- 200 + PROT P ----------------------------------------------> + <---------------------------------------------- 200 + USER fred ----------------------------------------------> + <---------------------------------------------- 331 + PASS pass ----------------------------------------------> + <---------------------------------------------- 230 + +Note 1: the order of the PBSZ/PROT pair and the USER/PASS pair (with +respect to each other) is not important (i.e. the USER/PASS can happen +prior to the PBSZ/PROT - or indeed the server can refuse to allow a +PBSZ/PROT pair until the USER/PASS pair has happened). + +Note 2: the PASS command might not be required at all (if the USER +parameter and any client identity presented provide sufficient +authentication). The server would indicate this by issuing a '232' +reply to the USER command instead of the '331' which requests a PASS +from the client. + +Note 3: the AUTH command might not be the first command after the +receipt of the 220 welcome message. + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 15] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + 11.2. A standard data transfer without protection. + + Client Server + control data data control +==================================================================== + + socket() + bind() + PORT w,x,y,z,a,b -----------------------------------------> + <----------------------------------------------------- 200 + STOR file ------------------------------------------------> + socket() + bind() + <----------------------------------------------------- 150 + accept() <----------- connect() + write() -----------> read() + close() -----------> close() + <----------------------------------------------------- 226 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 16] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + 11.3. A firewall-friendly data transfer without protection + + Client Server + control data data control +==================================================================== + + PASV --------------------------------------------------------> + socket() + bind() + <------------------------------------------ 227 (w,x,y,z,a,b) + socket() + STOR file ---------------------------------------------------> + connect() ----------> accept() + <-------------------------------------------------------- 150 + write() ----------> read() + close() ----------> close() + <-------------------------------------------------------- 226 + + + Note: Implementors should be aware that then connect()/accept() + function is performed prior to the receipt of the reply from the + STOR command. This contrasts with situation when (non-firewall- + friendly) PORT is used prior to the STOR, and the accept()/connect() + is performed after the reply from the aforementioned STOR has been + dealt with. + + + + + + + + + + + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 17] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + 11.4. A standard data transfer with protection + + Client Server + control data data control +==================================================================== + + socket() + bind() + PORT w,x,y,z,a,b --------------------------------------------> + <-------------------------------------------------------- 200 + STOR file ---------------------------------------------------> + socket() + bind() + <-------------------------------------------------------- 150 + accept() <---------- connect() + TLSneg() <----------> TLSneg() + TLSwrite() ----------> TLSread() + TLSshutdown() -------> TLSshutdown() + close() ----------> close() + <-------------------------------------------------------- 226 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 18] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + 11.5. A firewall-friendly data transfer with protection + + Client Server + control data data control +==================================================================== + + PASV --------------------------------------------------------> + socket() + bind() + <------------------------------------------ 227 (w,x,y,z,a,b) + socket() + STOR file ---------------------------------------------------> + connect() ----------> accept() + <-------------------------------------------------------- 150 + TLSneg() <---------> TLSneg() + TLSwrite() ---------> TLSread() + TLSshutdown() -------> TLSshutdown() + close() ---------> close() + <-------------------------------------------------------- 226 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 19] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + +12. Discussion of the REIN command + + The REIN command, defined in [RFC-959], allows the user to reset the + state of the FTP session. From [RFC-959]: + REINITIALIZE (REIN) + This command terminates a USER, flushing all I/O and account + information, except to allow any transfer in progress to be + completed. All parameters are reset to the default settings + and the control connection is left open. This is identical to + the state in which a user finds himself immediately after the + control connection is opened. A USER command may be expected + to follow. + When this command is processed by the server, the TLS session(s) + MUST be cleared and the control and data connections revert to + unprotected, clear communications. It MAY be acceptable to use + cached TLS sessions for subsequent connections, however a server MUST + not mandate this. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 20] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + +13. Discussion of the STAT and ABOR commands + + The ABOR and STAT commands and the use of TCP Urgent Pointers + + [RFC-959] describes the use of Telnet commands (IP and DM) and the + TCP Urgent pointer to indicate the transmission of commands on the + control channel during the execution of a data transfer. FTP uses + the Telnet Interrupt Process and Data Mark commands in conjunction + with Urgent data to preface two commands: ABOR (Abort Transfer) + and STAT (Status request). + + The Urgent Pointer was used because in a Unix implementation the + receipt of a TCP packet marked as Urgent would result in the the + execution of the SIGURG interrupt handler. This reliance on + interrupt handlers was necessary on systems which did not + implement select() or did not support multiple threads. TLS does + not support the notion of Urgent data. + + When TLS is implemented as a security method in FTP the server + SHOULD NOT rely on the use of SIGURG to process input on the + control channel during data transfers. The client MUST send all + data including Telnet commands across the TLS session. The TLS + session will be corrupted if any data is sent on a socket while + TLS is active. + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 21] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + +14. Security Considerations + + This entire document deals with security considerations related to + the File Transfer Protocol. + + 14.1. Verification of Authentication tokens + + 14.1.1. Server Certificates + + Although it is entirely an implementation decision, it is + recommended that certificates used for server authentication of + the TLS session contain the server identification information + in a similar manner to those used for http servers. (see + [RFC-2818]) + + Similarly, it is recommended that the certificate used for + server authentication of Data connections is the same + certificate as that used for the corresponding Control + connection. + + 14.1.2. Client Certificates + + - Deciding which client certificates to allow and defining + which fields define what authentication information is entirely + a server implementation issue. + + - It is also server implementation issue to decide if the + authentication token presented for the data connection must + match the one used for the corresponding control connection. + + 14.2. Addressing FTP Security Considerations [RFC-2577] + + 14.2.1. Bounce Attack + + A bounce attack should be harder in a secured FTP environment + because: + + - The FTP server that is being used to initiate a false + connection will always be a 'server' in the TLS context. + Therefore, only services that act as 'clients' in the TLS + context could be vulnerable. This would be a counter- + intuitive way to implement TLS on a service. + + - The FTP server would detect that the authentication + credentials for the data connection are not the same as + those for the control connection, thus the server policies + COULD be set to drop the data connection. + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 22] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + - Genuine users are less likely to initiate such attacks + when the authentication is strong and malicious users are + less likely to gain access to the FTP server if the + authentication is not easily subverted (password guessing, + network tracing, etc...) + + 14.2.2. Restricting Access + + This document presents a strong mechanism for solving the issue + raised in this section. + + 14.2.3. Protecting Passwords + + The twin solutions of strong authentication and data + confidentiality ensure that this is not an issue when TLS is + used to protect the control session. + + 14.2.4. Privacy + + The TLS protocol ensures data confidentiality by encryption. + Privacy (e.g. access to download logs, user profile + information, etc...) is outside the scope of this document (and + [RFC-2577] presumably) + + 14.2.5. Protecting Usernames + + This is not an issue when TLS is used as the primary + authentication mechanism. + + 14.2.6. Port Stealing + + This proposal will do little for the Denial of Service element + of this section, however, strong authentication on the data + connection will prevent unauthorised connections retrieving or + submitting files. + + 14.2.7. Software-Base Security Problems + + Nothing in this proposal will affect the discussion in this + section. + + +15. IANA Considerations + + {FTP-PORT} - The port assigned to the FTP control connection is 21. + +16. Other Parameters + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 23] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + {TLS-PARM} - The parameter for the AUTH command to indicate that TLS + is required. To request the TLS protocol in accordance with this + document, the client MUST use 'TLS' + + To maintain backward compatability with older versions of this + document, the server SHOULD accept 'TLS-C' as a synonym for 'TLS' + + Note - [RFC-2228] states that these parameters are case- + insensitive. + + +17. Network Management + + NONE + + +18. Internationalization + + NONE + + +19. Scalability & Limits + + There are no issues other than those concerned with the ability of + the server to refuse to have a complete TLS negotiation for each and + every data connection, which will allow servers to retain throughput + whilst using cycles only when necessary. + + + + + + + + + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 24] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + +20. Applicability + + This mechanism is generally applicable as a mechanism for securing + the FTP protocol. It is unlikely that anonymous FTP clients or + servers will require such security (although some might like the + authentication features without the confidentiality). + + +21. Acknowledgements + + o Netscape Communications Corporation for the original SSL protocol. + + o Eric Young for the SSLeay libraries. + + o University of California, Berkley for the original implementations + of FTP and ftpd on which the initial implementation of these + extensions were layered. + + o IETF CAT working group. + + o IETF TLS working group. + + o IETF FTPEXT working group. + + o Jeff Altman for the ABOR and STAT discussion. + + + + + + + + + + + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 25] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + +22. References + + [RFC-959] J. Postel, "File Transfer Protocol" + RFC 959, October 1985. + + [RFC-1579] S. Bellovin, "Firewall-Friendly FTP" + RFC 1579, February 1994. + + [RFC-2119] S. Bradner, "Key words for use in RFCs to Indicate + Requirement Levels" + RFC 2119, March 1997. + + [RFC-2222] J. Myers, "Simple Authentication and Security Layer" + RFC 2222, October 1997. + + [RFC-2228] M. Horowitz, S. Lunt, "FTP Security Extensions" + RFC 2228, October 1997. + + [RFC-2246] T. Dierks, C. Allen, "The TLS Protocol Version 1.0" + RFC 2246, January 1999. + + [RFC-2389] P Hethmon, R.Elz, "Feature Negotiation Mechanism for the + File Transfer Protocol" + RFC 2389, August 1998. + + [RFC-2487] P Hoffman, "SMTP Service Extension for Secure SMTP over + TLS" + RFC 2487, January 1999. + + [RFC-2577] M Allman, S Ostermann, "FTP Security Considerations" + RFC 2577, May 1999. + + [RFC-2817] R. Khare, S. Lawrence, "Upgrading to TLS Within HTTP/1.1" + RFC 2817, May 2000. + + [RFC-2818] E. Rescorla, "HTTP Over TLS" + RFC 2818, May 2000. + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 26] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + +23. Authors' Contact Addresses + +The FTP-TLS draft information site is at http://www.ford- +hutchinson.com/~fh-1-pfh/ftps-ext.html + + +Please send comments to Paul Ford-Hutchinson at the address below + + Tim Hudson Paul Ford-Hutchinson + RSA Data Security IBM UK Ltd + Australia Pty Ltd PO Box 31 + Birmingham Road + Warwick + United Kingdom + tel - +61 7 3227 4444 +44 1926 462005 + fax - +61 7 3227 4400 +44 1926 496482 +email - tjh@rsasecurity.com.au paulfordh@uk.ibm.com + + Martin Carpenter Eric Murray + Verisign Ltd Wave Systems Inc. +email - mcarpenter@verisign.com ericm@lne.com + + Volker Wiegand + SuSE Linux +email - wiegand@suse.de + + + + + + + + + + + + + + + + + + + + + + + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 27] + + + + + +Internet-Draft Secure FTP using TLS 2nd April, 2002 + + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + +Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +This document expires on 2nd October, 2002 + + + + +Ford-Hutchinson, Carpenter, Hudson, Murray & Wiegand FORMFEED[Page 28] + diff -urN proftpd-1.2.6rc1.orig/include/conf.h proftpd-1.2.6rc1-tls/include/conf.h --- proftpd-1.2.6rc1.orig/include/conf.h Tue Jun 25 19:35:14 2002 +++ proftpd-1.2.6rc1-tls/include/conf.h Wed Jul 3 10:54:31 2002 @@ -33,6 +33,10 @@ #include "version.h" #include "config.h" +#if defined(TLS) && defined(HAVE_SENDFILE) +/* using sendfile() together with TLS breaks things! */ +#undef HAVE_SENDFILE +#endif #include "default_paths.h" diff -urN proftpd-1.2.6rc1.orig/include/ftp.h proftpd-1.2.6rc1-tls/include/ftp.h --- proftpd-1.2.6rc1.orig/include/ftp.h Fri May 10 18:52:39 2002 +++ proftpd-1.2.6rc1-tls/include/ftp.h Mon Jun 10 11:56:48 2002 @@ -102,6 +102,7 @@ #define R_226 "226" /* Closing data connection. File transfer/abort successful */ #define R_227 "227" /* Entering passive mode (h1,h2,h3,h4,p1,p2) */ #define R_230 "230" /* User logged in, proceed */ +#define R_232 "232" /* User logged in, authorized by security data exchange */ #define R_250 "250" /* Requested file action okay, completed. */ #define R_257 "257" /* "PATHNAME" created. */ #define R_331 "331" /* User name okay, need password. */ @@ -110,6 +111,7 @@ #define R_421 "421" /* Service not available, closing control connection (service is about to be shutdown) */ #define R_425 "425" /* Can't open data connection */ #define R_426 "426" /* Connection closed; transfer aborted */ +#define R_431 "431" /* Can't accept specified protection level, maybe some resource unavailable */ #define R_450 "450" /* Requested file action not taken (file unavailable; busy) */ #define R_451 "451" /* Requested action aborted; local error in processing */ #define R_452 "452" /* Requested action not taken; insufficient storage space */ @@ -120,6 +122,8 @@ #define R_504 "504" /* Command not implemented for that parameter */ #define R_530 "530" /* Not logged in */ #define R_532 "532" /* Need account for storing files */ +#define R_534 "534" /* Request denied for policy reasons */ +#define R_536 "536" /* Current security mechanism doesn't support the specified protection level */ #define R_550 "550" /* Requested action not taken. No access, etc */ #define R_551 "551" /* Requested action not taken, page type unknown */ #define R_552 "552" /* Requested file action aborted, exceeding storage allocation */ diff -urN proftpd-1.2.6rc1.orig/include/io.h proftpd-1.2.6rc1-tls/include/io.h --- proftpd-1.2.6rc1.orig/include/io.h Tue Jul 2 19:01:47 2002 +++ proftpd-1.2.6rc1-tls/include/io.h Wed Jul 3 10:54:31 2002 @@ -32,6 +32,10 @@ #ifndef __IO_H #define __IO_H +#ifdef TLS +#include +#endif + #define IO_READ 0 #define IO_WRITE 1 @@ -81,6 +85,9 @@ IOBUF *buf; IOREQ *req; /* Request buffer */ int bufsize; /* Default size of request buffer */ +#ifdef TLS + SSL *tls_session; /* OpenSSL SSL pointer */ +#endif }; struct IO_Buffer { diff -urN proftpd-1.2.6rc1.orig/include/tls_dh.h proftpd-1.2.6rc1-tls/include/tls_dh.h --- proftpd-1.2.6rc1.orig/include/tls_dh.h Thu Jan 1 01:00:00 1970 +++ proftpd-1.2.6rc1-tls/include/tls_dh.h Mon Jun 10 11:56:48 2002 @@ -0,0 +1,187 @@ +static unsigned char dh512_p[]={ + 0xC0,0xC5,0x23,0x8D,0x3A,0xB3,0xA3,0x63,0x57,0xC0,0xD3,0xFE, + 0xD4,0xC2,0x8F,0x17,0x0E,0x7A,0xDB,0x8E,0x3B,0xB6,0xA5,0xC2, + 0x60,0x7D,0xE7,0x03,0xCC,0xA3,0x10,0xCC,0x82,0x39,0x3C,0x68, + 0xA0,0x82,0x9C,0x7A,0x4A,0x96,0x8C,0xB0,0x1A,0xB4,0xB8,0xA0, + 0x9E,0x64,0x9D,0x40,0x77,0x8A,0x9C,0x97,0x96,0x69,0x3D,0xCA, + 0xA8,0x25,0xAE,0xAB, + }; +static unsigned char dh512_g[]={ + 0x02, + }; + +DH *get_dh512() + { + DH *dh; + + if ((dh=DH_new()) == NULL) return(NULL); + dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL); + dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + return(NULL); + return(dh); + } +/* +-----BEGIN DH PARAMETERS----- +MEYCQQDAxSONOrOjY1fA0/7Uwo8XDnrbjju2pcJgfecDzKMQzII5PGiggpx6SpaM +sBq0uKCeZJ1Ad4qcl5ZpPcqoJa6rAgEC +-----END DH PARAMETERS----- +*/ +static unsigned char dh768_p[]={ + 0xB3,0x95,0x74,0xCE,0x0B,0xFD,0xAB,0xC3,0x53,0x9B,0x0B,0xFD, + 0x6E,0xB2,0x64,0x64,0x02,0xDD,0xFF,0x2E,0x77,0xEB,0x0D,0x6C, + 0xCE,0x04,0x2C,0x8E,0x5A,0xA7,0x96,0x45,0x54,0xA6,0x2F,0xBC, + 0xF9,0x77,0x1C,0x50,0x66,0x8E,0x48,0xA8,0x34,0xF0,0x81,0xDD, + 0x5B,0x5A,0xD4,0xA6,0x13,0x89,0x60,0x46,0x05,0x65,0x57,0x2C, + 0x1E,0x94,0x57,0x3C,0x3E,0x38,0xA6,0xFE,0x7B,0x03,0x7D,0x16, + 0x46,0xF6,0xB3,0x21,0x3C,0x44,0xF1,0xF1,0x90,0xCE,0x40,0x93, + 0x4B,0xE6,0xD6,0x0E,0x20,0x85,0xDA,0x9B,0x3F,0x5C,0x1F,0xDB, + }; +static unsigned char dh768_g[]={ + 0x02, + }; + +DH *get_dh768() + { + DH *dh; + + if ((dh=DH_new()) == NULL) return(NULL); + dh->p=BN_bin2bn(dh768_p,sizeof(dh768_p),NULL); + dh->g=BN_bin2bn(dh768_g,sizeof(dh768_g),NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + return(NULL); + return(dh); + } +/* +-----BEGIN DH PARAMETERS----- +MGYCYQCzlXTOC/2rw1ObC/1usmRkAt3/LnfrDWzOBCyOWqeWRVSmL7z5dxxQZo5I +qDTwgd1bWtSmE4lgRgVlVywelFc8Pjim/nsDfRZG9rMhPETx8ZDOQJNL5tYOIIXa +mz9cH9sCAQI= +-----END DH PARAMETERS----- +*/ +static unsigned char dh1024_p[]={ + 0xC1,0xD8,0x9C,0x90,0xB1,0x58,0x7C,0xE1,0x56,0x70,0xD7,0x61, + 0x6C,0x00,0xE6,0xE7,0x99,0x04,0x9F,0x86,0xD9,0xB4,0x11,0x09, + 0x23,0x18,0xAA,0x19,0xCA,0x49,0x7C,0xA8,0x9D,0xF7,0x43,0x3A, + 0xAF,0xC3,0x1F,0x0E,0xAE,0xBB,0xF2,0xEA,0x5B,0x62,0xA1,0x5F, + 0x7C,0x26,0xA8,0xB4,0x5D,0x2A,0x25,0xAB,0x88,0x70,0x27,0x06, + 0xD0,0xF5,0x01,0xD9,0x6A,0x1F,0x48,0x2D,0x9C,0xEC,0xFE,0xA8, + 0x45,0x97,0x1D,0xC0,0x8A,0xFF,0xE5,0xE1,0x79,0xDF,0x85,0x31, + 0xFC,0x58,0x91,0x35,0xE8,0xC7,0xDA,0x55,0x7B,0xAA,0xDD,0xC2, + 0x0A,0x94,0x34,0xF7,0xB4,0x4A,0x91,0x3B,0x1E,0x16,0x89,0x2A, + 0x04,0x47,0x5D,0xE9,0x42,0x47,0x5E,0x30,0x61,0xE8,0x42,0xC1, + 0x23,0xC7,0x97,0x78,0x63,0x36,0x9D,0x3B, + }; +static unsigned char dh1024_g[]={ + 0x02, + }; + +DH *get_dh1024() + { + DH *dh; + + if ((dh=DH_new()) == NULL) return(NULL); + dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL); + dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + return(NULL); + return(dh); + } +/* +-----BEGIN DH PARAMETERS----- +MIGHAoGBAMHYnJCxWHzhVnDXYWwA5ueZBJ+G2bQRCSMYqhnKSXyonfdDOq/DHw6u +u/LqW2KhX3wmqLRdKiWriHAnBtD1AdlqH0gtnOz+qEWXHcCK/+Xhed+FMfxYkTXo +x9pVe6rdwgqUNPe0SpE7HhaJKgRHXelCR14wYehCwSPHl3hjNp07AgEC +-----END DH PARAMETERS----- +*/ +static unsigned char dh1536_p[]={ + 0xDA,0x68,0x25,0x7F,0x9D,0xB5,0x3F,0x42,0x05,0xBC,0x79,0x65, + 0x6F,0x19,0x6A,0x6F,0x70,0x11,0x91,0xF2,0x08,0x48,0x2B,0xE2, + 0x0C,0x15,0xD9,0x31,0xE7,0x3A,0x50,0x32,0x9F,0xFB,0xD6,0x56, + 0xFA,0xB4,0xA9,0x5F,0x22,0x17,0x52,0x72,0x2C,0xE3,0x5D,0xA1, + 0xA8,0xEF,0x16,0x42,0x35,0xC6,0xD9,0x64,0xC1,0xB3,0xB3,0x4C, + 0x09,0x90,0xF4,0x49,0xEF,0xDE,0x64,0x99,0xFF,0x3C,0x37,0x0A, + 0x91,0xA4,0x9E,0x38,0x27,0xF2,0x96,0x13,0x1E,0x15,0xA2,0x52, + 0xF1,0x54,0x0C,0xED,0x5C,0x38,0xC4,0xEC,0xFF,0xE2,0xFA,0x0A, + 0x41,0xBB,0x48,0x5D,0xD3,0x54,0xA1,0xEB,0xBD,0x1F,0x68,0xED, + 0x2A,0x49,0x7F,0x68,0x52,0xB3,0xA0,0x77,0x3E,0x19,0xFB,0x44, + 0xCD,0x4B,0x21,0x3E,0x3B,0xBA,0xF6,0xA2,0x36,0x37,0xE5,0xFA, + 0x95,0xB0,0x7D,0x7B,0x58,0x96,0xC4,0xC9,0xC0,0xCF,0xD9,0x3F, + 0xA3,0x42,0x0B,0xD7,0xBE,0x1A,0xA8,0xB5,0x57,0x58,0xF4,0x04, + 0x97,0x54,0xB0,0x59,0x23,0x5F,0x98,0x09,0x90,0xC0,0x49,0x85, + 0x40,0x23,0x2D,0x21,0x3E,0xB0,0x07,0x06,0x07,0x32,0xFB,0xB9, + 0x91,0x40,0x92,0x09,0xED,0x07,0x80,0x05,0x14,0x5B,0xC1,0x9B, + }; +static unsigned char dh1536_g[]={ + 0x02, + }; + +DH *get_dh1536() + { + DH *dh; + + if ((dh=DH_new()) == NULL) return(NULL); + dh->p=BN_bin2bn(dh1536_p,sizeof(dh1536_p),NULL); + dh->g=BN_bin2bn(dh1536_g,sizeof(dh1536_g),NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + return(NULL); + return(dh); + } +/* +-----BEGIN DH PARAMETERS----- +MIHHAoHBANpoJX+dtT9CBbx5ZW8Zam9wEZHyCEgr4gwV2THnOlAyn/vWVvq0qV8i +F1JyLONdoajvFkI1xtlkwbOzTAmQ9Env3mSZ/zw3CpGknjgn8pYTHhWiUvFUDO1c +OMTs/+L6CkG7SF3TVKHrvR9o7SpJf2hSs6B3Phn7RM1LIT47uvaiNjfl+pWwfXtY +lsTJwM/ZP6NCC9e+Gqi1V1j0BJdUsFkjX5gJkMBJhUAjLSE+sAcGBzL7uZFAkgnt +B4AFFFvBmwIBAg== +-----END DH PARAMETERS----- +*/ +static unsigned char dh2048_p[]={ + 0xD0,0xE6,0xFF,0x1F,0x39,0xE0,0xCC,0x85,0xAC,0xA4,0xE6,0xDD, + 0x06,0xE5,0x2D,0xBF,0xEA,0x64,0x2E,0xC7,0x99,0x8A,0x0F,0xCB, + 0x3C,0x9D,0xEE,0xAC,0x61,0xFF,0x69,0x31,0x71,0xFE,0x2F,0x7B, + 0x65,0x95,0xA0,0xA4,0x59,0xB8,0xE3,0x66,0x5B,0x3F,0xD8,0x42, + 0x99,0x4F,0x09,0x44,0xC5,0x8D,0x8B,0x5D,0x16,0xAA,0x05,0x6E, + 0x8B,0x11,0x59,0x1F,0xD7,0x11,0x84,0x87,0x4D,0xBE,0xBB,0xBA, + 0x9A,0xF0,0xC3,0xE2,0x0E,0xB8,0x0F,0xFD,0x08,0xB1,0x48,0x98, + 0xDE,0x89,0xDA,0x00,0x15,0x04,0xA4,0x51,0xBE,0x5B,0x60,0x0A, + 0x0E,0x20,0xAC,0xC5,0x83,0x5D,0xC4,0x0F,0xA3,0x8E,0x11,0x66, + 0x2C,0xD3,0x61,0x5F,0x16,0x83,0xAA,0xCF,0x52,0x9C,0x7D,0x75, + 0xEA,0xCA,0x67,0xA3,0xAB,0x58,0x9F,0x67,0x17,0xA0,0x54,0x3A, + 0x2B,0xCA,0xB5,0x03,0x7E,0x50,0xBD,0x99,0x1E,0xEF,0xB2,0x8F, + 0xB4,0xFB,0xD2,0x2D,0x6A,0xA9,0xA2,0xC0,0xD4,0xD2,0x68,0x6C, + 0x21,0x71,0x78,0x75,0x82,0x4C,0xD8,0xE8,0x2C,0x0B,0xC9,0x3F, + 0xF6,0xF0,0x64,0xD9,0x6E,0x76,0xCB,0xBB,0x99,0xFB,0xBC,0x15, + 0x54,0x7B,0x7F,0x97,0x36,0x8F,0x0B,0x1C,0xFF,0xDD,0x28,0x99, + 0xE5,0x3A,0xAD,0xCD,0x84,0xAB,0xA1,0xEF,0xB2,0x21,0xEA,0xD6, + 0x49,0x22,0x6A,0x30,0x6A,0x63,0x2E,0x52,0x79,0xCF,0xBC,0xC2, + 0xB6,0x2E,0xA5,0x5D,0xB3,0xDA,0xC2,0xDD,0x02,0xEA,0x26,0x2F, + 0x3B,0x0A,0x12,0xBB,0xA2,0xEF,0x2B,0xFA,0xCC,0x25,0x63,0x1B, + 0xC3,0x00,0x18,0x8F,0x36,0xB7,0x30,0x5A,0x55,0x1A,0xE0,0x12, + 0xA1,0xD2,0x9C,0x93, + }; +static unsigned char dh2048_g[]={ + 0x02, + }; + +DH *get_dh2048() + { + DH *dh; + + if ((dh=DH_new()) == NULL) return(NULL); + dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL); + dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + return(NULL); + return(dh); + } +/* +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA0Ob/HzngzIWspObdBuUtv+pkLseZig/LPJ3urGH/aTFx/i97ZZWg +pFm442ZbP9hCmU8JRMWNi10WqgVuixFZH9cRhIdNvru6mvDD4g64D/0IsUiY3ona +ABUEpFG+W2AKDiCsxYNdxA+jjhFmLNNhXxaDqs9SnH116spno6tYn2cXoFQ6K8q1 +A35QvZke77KPtPvSLWqposDU0mhsIXF4dYJM2OgsC8k/9vBk2W52y7uZ+7wVVHt/ +lzaPCxz/3SiZ5TqtzYSroe+yIerWSSJqMGpjLlJ5z7zCti6lXbPawt0C6iYvOwoS +u6LvK/rMJWMbwwAYjza3MFpVGuASodKckwIBAg== +-----END DH PARAMETERS----- +*/ diff -urN proftpd-1.2.6rc1.orig/include/tlsutil.h proftpd-1.2.6rc1-tls/include/tlsutil.h --- proftpd-1.2.6rc1.orig/include/tlsutil.h Thu Jan 1 01:00:00 1970 +++ proftpd-1.2.6rc1-tls/include/tlsutil.h Mon Jun 10 11:56:48 2002 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1999 - 2002 Peter 'Luna' Runestig + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifi- + * cation, are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright no- + * tice, this list of conditions and the following disclaimer in the do- + * cumentation and/or other materials provided with the distribution. + * + * o The names of the contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 LI- + * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN- + * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV- + * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI- + * LITY, 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 _TLSUTIL_H_ +#define _TLSUTIL_H_ + +extern int tls_on_data; +extern int tls_on_ctrl; +extern int tls_implicit; +extern int tls_no_verify; +extern int tls_dont_request_cert; +extern int tls_required; +extern int tls_init_error; +extern char *tls_rsa_key_file; +extern char *tls_rsa_cert_file; +extern char *tls_dsa_key_file; +extern char *tls_dsa_cert_file; +extern char *tls_crl_file; +extern char *tls_dhparam_file; +extern char *tls_cipher_list; + +int tls_init(void); +int tls_accept(conn_t *conn, int data_connection); +void tls_cleanup(void); +void tls_close_session(SSL *ssl); +int tls_recv(int s, void *buf, size_t len, int flags); +int tls_send(int s, const void *msg, size_t len, int flags); +ssize_t tls_read(SSL *ssl, void *buf, size_t count); +ssize_t tls_write(SSL *ssl, const void *buf, size_t count); +int tls_pending(SSL *ssl); +void tls_optarg(char *optarg); +char *tls_userid_from_client_cert(); +int tls_is_user_valid(char *user); +void tls_set_file_defaults(void); +int tls_setup_session_cache(void); + + +#endif diff -urN proftpd-1.2.6rc1.orig/modules/mod_auth.c proftpd-1.2.6rc1-tls/modules/mod_auth.c --- proftpd-1.2.6rc1.orig/modules/mod_auth.c Thu Jun 27 09:31:54 2002 +++ proftpd-1.2.6rc1-tls/modules/mod_auth.c Wed Jul 3 11:04:48 2002 @@ -67,6 +67,12 @@ return 0; } +#ifdef TLS +static int tls_logged_in = 0; +MODRET cmd_pass(cmd_rec *cmd); +#include "tlsutil.h" +#endif + /* check_auth is hooked into the main server's auth_hook function, * so that we can deny all commands until authentication is complete. */ @@ -173,6 +179,11 @@ char *cpw = NULL; config_rec *c; +#ifdef TLS + if (tls_logged_in) + return 0; +#endif + if (conf) { c = find_config(conf,CONF_PARAM,"UserPassword",FALSE); @@ -1015,6 +1026,12 @@ if(c && c->subset) resolve_anonymous_dirs(c->subset); +#if TLS + if (tls_logged_in) + log_auth(LOG_NOTICE, "USER %s: TLS/X509 authentication login successful.", + origuser); + else +#endif /* TLS */ log_auth(LOG_NOTICE, "%s %s: Login successful.", (c != NULL) ? "ANON" : "USER", origuser); @@ -1573,6 +1590,9 @@ config_rec *c; char *user, *origuser; int failnopwprompt = 0, aclp, i; +#ifdef TLS + char *tls_user = NULL; +#endif if(logged_in) return ERROR_MSG(cmd,R_503,"You are already logged in!"); @@ -1580,6 +1600,12 @@ if(cmd->argc < 2) return ERROR_MSG(cmd,R_500,"'USER': command requires a parameter."); +#ifdef TLS + if (tls_required && !tls_on_ctrl) + return ERROR_MSG(cmd, R_534, + "Server policy denies USER command on insecure connection."); +#endif + user = cmd->arg; remove_config(cmd->server->conf, C_USER, FALSE); @@ -1652,6 +1678,15 @@ if(c && user && get_param_int(c->subset, "AnonRequirePassword", FALSE) != 1) nopass++; +#ifdef TLS + tls_user = tls_userid_from_client_cert(); + if ((tls_user && !strcmp(user, tls_user)) || tls_is_user_valid(user)) { + /* user is X509-authenticated */ + tls_logged_in = 1; + return cmd_pass(cmd); + } +#endif + if(nopass) add_response(R_331, "Anonymous login ok, send your complete email " "address as your password."); @@ -1680,7 +1715,8 @@ char *display = NULL; char *user, *grantmsg; int res = 0; - + char *reply_code = R_230; + if(logged_in) return ERROR_MSG(cmd, R_503, "You are already logged in!"); @@ -1695,6 +1731,10 @@ _auth_check_count(cmd, user); +#ifdef TLS + if (tls_logged_in) + reply_code = R_232; +#endif if((res = _setup_environment(cmd->tmp_pool,user,cmd->arg)) == 1) { add_config_param_set(&cmd->server->conf,"authenticated",1,(void*)1); set_auth_check(NULL); @@ -1713,21 +1753,21 @@ "DisplayLogin", FALSE); if(display) - core_display_file(R_230, display, NULL); + core_display_file(reply_code, display, NULL); if ((grantmsg = (char *)get_param_ptr((session.anon_config ? session.anon_config->subset : cmd->server->conf), "AccessGrantMsg",FALSE)) != NULL) { grantmsg = sreplace(cmd->tmp_pool, grantmsg, "%u", user, NULL); - add_response(R_230, "%s", grantmsg); + add_response(reply_code, "%s", grantmsg); } else { if (session.flags & SF_ANON) add_response(R_230, "Anonymous access granted, restrictions apply."); else - add_response(R_230, "User %s logged in.", user); + add_response(reply_code, "User %s logged in.", user); } logged_in = 1; diff -urN proftpd-1.2.6rc1.orig/modules/mod_tls.c proftpd-1.2.6rc1-tls/modules/mod_tls.c --- proftpd-1.2.6rc1.orig/modules/mod_tls.c Thu Jan 1 01:00:00 1970 +++ proftpd-1.2.6rc1-tls/modules/mod_tls.c Mon Jun 10 11:56:48 2002 @@ -0,0 +1,483 @@ +/* + * ProFTPD - FTP server daemon + * Copyright (c) 1997, 1998 Public Flood Software + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ +/* + * AUTH/TLS module for ProFTPD, based on the mod_sample.c file. + * + * Copyright (c) 2000 - 2002 Peter 'Luna' Runestig + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifi- + * cation, are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright no- + * tice, this list of conditions and the following disclaimer in the do- + * cumentation and/or other materials provided with the distribution. + * + * o The names of the contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 LI- + * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN- + * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV- + * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI- + * LITY, 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 "conf.h" +#include +#include "tlsutil.h" + +extern session_t session; + +#define CHECK_TLS_INIT_ERROR() if (tls_init_error) { \ + char errmsg[256]; \ + snprintf(errmsg, sizeof(errmsg), \ + "Local error code %d was returned from tls_init()", \ + tls_init_error); \ + return ERROR_MSG(cmd, R_431, errmsg); } + +/* This sample configuration directive handler will get called + * whenever the "FooBarDirective" directive is encountered in the + * configuration file. + */ + +MODRET set_rsacertfile(cmd_rec *cmd) +{ + config_rec *c; + + /* The CHECK_ARGS macro checks the number of arguments passed to the + * directive against what we want. Note that this is *one* less than + * cmd->argc, because cmd->argc includes cmd->argv[0] (the directive + * itself). If CHECK_ARGS fails, a generic error is sent to the user + */ + CHECK_ARGS(cmd, 1); + + /* The CHECK_CONF macro makes sure that this directive is not being + * "used" in the wrong context (i.e. if the directive is only available + * or applicable inside certain contexts). In this case, we are allowing + * the directive inside of and , but nowhere else. + * If this macro fails a generic error is logged and the handler aborts. + */ + CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL); + + /* add_config_param adds a configuration paramater to our current + * configuration context. + */ + c = add_config_param_str("TlsRsaCertFile", 1, cmd->argv[1]); + + /* By adding the CF_MERGEDOWN flag to the parameter we just created + * we are telling proftpd that this parameter should be copied and + * "merged" into all "lower" contexts until it either hits a + * parameter w/ the same name or bottoms out. + * + * Example _without_ CF_MERGEDOWN: + * + * + * |----------\ + * + * | - FooBarDirective <------- Config places it here + * |-----------\ + * <------- Doesn't apply here + * |-------------\ + * <--- Or here..... + * + * Now, if we specify CF_MERGDOWN, the tree ends up looking like: + * + * + * |----------\ + * + * | - FooBarDirective <------- Config places it here + * |-----------\ + * <------- Now, it DOES apply here + * | - FooBarDirective + * |-------------\ + * <-------- And here ... + * | - FooBarDirective + * + */ + c->flags |= CF_MERGEDOWN; + + /* Tell proftpd that we handled the request w/ no problems. + */ + return HANDLED(cmd); +} + +MODRET set_rsakeyfile(cmd_rec *cmd) +{ + config_rec *c; + + CHECK_ARGS(cmd, 1); + CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL); + + c = add_config_param_str("TlsRsaKeyFile", 1, cmd->argv[1]); + c->flags |= CF_MERGEDOWN; + return HANDLED(cmd); +} + +MODRET set_dsacertfile(cmd_rec *cmd) +{ + config_rec *c; + + CHECK_ARGS(cmd, 1); + CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL); + + c = add_config_param_str("TlsDsaCertFile", 1, cmd->argv[1]); + c->flags |= CF_MERGEDOWN; + return HANDLED(cmd); +} + +MODRET set_dsakeyfile(cmd_rec *cmd) +{ + config_rec *c; + + CHECK_ARGS(cmd, 1); + CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL); + + c = add_config_param_str("TlsDsaKeyFile", 1, cmd->argv[1]); + c->flags |= CF_MERGEDOWN; + return HANDLED(cmd); +} + +MODRET set_crlfile(cmd_rec *cmd) +{ + config_rec *c; + + CHECK_ARGS(cmd, 1); + CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL); + + c = add_config_param_str("TlsCrlFile", 1, cmd->argv[1]); + c->flags |= CF_MERGEDOWN; + return HANDLED(cmd); +} + +MODRET set_dhparamfile(cmd_rec *cmd) +{ + config_rec *c; + + CHECK_ARGS(cmd, 1); + CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL); + + c = add_config_param_str("TlsDhParamFile", 1, cmd->argv[1]); + c->flags |= CF_MERGEDOWN; + return HANDLED(cmd); +} + +MODRET set_cipherlist(cmd_rec *cmd) +{ + config_rec *c; + + CHECK_ARGS(cmd, 1); + CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL); + + c = add_config_param_str("TlsCipherList", 1, cmd->argv[1]); + c->flags |= CF_MERGEDOWN; + return HANDLED(cmd); +} + +MODRET set_no_verify(cmd_rec *cmd) +{ + config_rec *c; + int b; + + CHECK_ARGS(cmd, 1); + CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL); + + if ((b = get_boolean(cmd, 1)) == -1) + CONF_ERROR(cmd, "expected boolean argument."); + c = add_config_param("TlsCertsOk", 1, (void *) b); + c->flags |= CF_MERGEDOWN; + return HANDLED(cmd); +} + +MODRET set_dont_request_cert(cmd_rec *cmd) +{ + config_rec *c; + int b; + + CHECK_ARGS(cmd, 1); + CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL); + + if ((b = get_boolean(cmd, 1)) == -1) + CONF_ERROR(cmd, "expected boolean argument."); + c = add_config_param("TlsDontRequestCert", 1, (void *) b); + c->flags |= CF_MERGEDOWN; + return HANDLED(cmd); +} + +MODRET set_required(cmd_rec *cmd) +{ + config_rec *c; + int b; + + CHECK_ARGS(cmd, 1); + CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL); + + if ((b = get_boolean(cmd, 1)) == -1) + CONF_ERROR(cmd, "expected boolean argument."); + c = add_config_param("TlsRequired", 1, (void *) b); + c->flags |= CF_MERGEDOWN; + return HANDLED(cmd); +} + +MODRET set_implicit(cmd_rec *cmd) +{ + config_rec *c; + int b; + + CHECK_ARGS(cmd, 1); + CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL); + + if ((b = get_boolean(cmd, 1)) == -1) + CONF_ERROR(cmd, "expected boolean argument."); + c = add_config_param("TlsImplicit", 1, (void *) b); + c->flags |= CF_MERGEDOWN; + return HANDLED(cmd); +} + +MODRET cmd_auth(cmd_rec *cmd) +{ + char *cp; + + if (tls_implicit) + return ERROR_MSG(cmd, R_504, "The AUTH command is not supported on an implicit TLS connection"); + if (cmd->argc < 2) + return ERROR_MSG(cmd, R_504, "The AUTH command needs at least one argument"); + + /* convert to upper case */ + cp = cmd->argv[1]; + while (*cp) { + *cp = toupper(*cp); + cp++; + } + + if (!strcmp(cmd->argv[1], "TLS") || !strcmp(cmd->argv[1], "TLS-C")) { + CHECK_TLS_INIT_ERROR(); + send_response("234", "AUTH TLS successful"); + if (tls_accept(session.c, FALSE)) { + /* exit if we fail */ + send_response_async(R_421, + "Failed TLS negotiation on control channel, disconnected"); + main_exit((void*) LOG_ERR, + "Failed TLS negotiation on control channel, disconnected.", + (void*) 0, NULL); + } + } + else if (!strcmp(cmd->argv[1], "SSL") || !strcmp(cmd->argv[1], "TLS-P")) { + CHECK_TLS_INIT_ERROR(); + send_response("234", "AUTH SSL successful"); + if (tls_accept(session.c, FALSE)) { + /* exit if we fail */ + send_response_async(R_421, + "Failed TLS negotiation on control channel, disconnected"); + main_exit((void*) LOG_ERR, + "Failed TLS negotiation on control channel, disconnected.", + (void*) 0, NULL); + } + tls_on_data = 1; + } + else { + char errmsg[255]; + snprintf(errmsg, sizeof(errmsg), "AUTH %s unsupported", cmd->argv[1]); + return ERROR_MSG(cmd, R_504, errmsg); + } + + return HANDLED(cmd); +} + +static int pbsz_ok = 0; + +MODRET cmd_pbsz(cmd_rec *cmd) +{ + if (cmd->argc < 2) + return ERROR_MSG(cmd, R_501, "PBSZ command needs at least one argument"); + if (!tls_on_ctrl) + return ERROR_MSG(cmd, R_503, "You can't issue PBSZ on an insecure control connection"); + + /* we expect "PBSZ 0" */ + CHECK_TLS_INIT_ERROR(); + if (!strcmp(cmd->argv[1], "0")) + send_response("200", "PBSZ 0 successful"); + else + send_response("200", "PBSZ=0 successful"); + pbsz_ok = 1; + + return HANDLED(cmd); +} + +MODRET cmd_prot(cmd_rec *cmd) +{ + if (cmd->argc < 2) + return ERROR_MSG(cmd, R_504, "PROT command needs at least one argument"); + if (!pbsz_ok) + return ERROR_MSG(cmd, R_503, "You must issue the PBSZ command prior to PROT"); + + /* only PROT C or PROT P is valid in respect to SSL/TLS */ + if (!strcmp(cmd->argv[1], "C")) { + CHECK_TLS_INIT_ERROR(); + send_response("200", "Protection set to Clear"); + tls_on_data = 0; + } + else if (!strcmp(cmd->argv[1], "P")) { + CHECK_TLS_INIT_ERROR(); + send_response("200", "Protection set to Private"); + tls_on_data = 1; + } + else if (!strcmp(cmd->argv[1], "S") || !strcmp(cmd->argv[1], "E")) { + char errmsg[255]; + snprintf(errmsg, sizeof(errmsg), "PROT %s unsupported", cmd->argv[1]); + return ERROR_MSG(cmd, R_536, errmsg); + } + else { + char errmsg[255]; + snprintf(errmsg, sizeof(errmsg), "PROT %s unsupported", cmd->argv[1]); + return ERROR_MSG(cmd, R_504, errmsg); + } + + return HANDLED(cmd); +} + +/* There are three tables which act as the "glue" between proftpd and + * a module. None of the tables are _required_ (however having none would + * make the module fairly useless). + */ + +/* The first table is the "configuration directive" table. It specifies + * handler routines in the module which will be used during configuration + * file parsing. + */ + +static conftable mod_tls_config[] = { + { "TlsRsaCertFile", set_rsacertfile, NULL }, + { "TlsRsaKeyFile", set_rsakeyfile, NULL }, + { "TlsDsaCertFile", set_dsacertfile, NULL }, + { "TlsDsaKeyFile", set_dsakeyfile, NULL }, + { "TlsCrlFile", set_crlfile, NULL }, + { "TlsDhParamFile", set_dhparamfile, NULL }, + { "TlsCipherList", set_cipherlist, NULL }, + { "TlsCertsOk", set_no_verify, NULL }, + { "TlsDontRequestCert", set_dont_request_cert, NULL }, + { "TlsRequired", set_required, NULL }, + { "TlsImplicit", set_implicit, NULL }, + { NULL , NULL, NULL} +}; + +/* Each module can supply up to two initialization routines (via + * the module structure at the bottom of this file). The first + * init function is called immediately after the module is loaded, + * while the second is called after proftpd is connected to a client, + * and the main proftpd server (if not in inetd mode) has forked off. + * The second init function's purpose is to let the module perform + * any necessary work once a client is connected and proftpd is ready + * to service the new client. In inetd mode, the "child init" function + * will be called immediately after proftpd is loaded, because proftpd + * is _always_ in "child mode" when run from inetd. Note that both + * of these initialization routines are optional. If you don't need + * them (or only need one), simply set the function pointer to NULL + * in the module structure. + */ + +static int mod_tls_init() +{ + return 0; +} + +#define PROCESS_PARAM_STR(x, y) { \ + char *str = (char *) get_param_ptr(CURRENT_CONF, x, FALSE); \ + if (str) { \ + if (y) \ + free(y); \ + y = strdup(str); \ + } \ +} + +#define PROCESS_PARAM_INT(x, y) { \ + long i = get_param_int(CURRENT_CONF, x, FALSE); \ + if (i != -1) \ + y = i; \ +} + +static int mod_tls_child_init() +{ + PROCESS_PARAM_STR("TlsRsaCertFile", tls_rsa_cert_file); + PROCESS_PARAM_STR("TlsRsaKeyFile", tls_rsa_key_file); + PROCESS_PARAM_STR("TlsDsaCertFile", tls_dsa_cert_file); + PROCESS_PARAM_STR("TlsDsaKeyFile", tls_dsa_key_file); + PROCESS_PARAM_STR("TlsCrlFile", tls_crl_file); + PROCESS_PARAM_STR("TlsDhParamFile", tls_dhparam_file); + PROCESS_PARAM_STR("TlsCipherList", tls_cipher_list); + PROCESS_PARAM_INT("TlsCertsOk", tls_no_verify); + PROCESS_PARAM_INT("TlsDontRequestCert", tls_dont_request_cert); + PROCESS_PARAM_INT("TlsRequired", tls_required); + PROCESS_PARAM_INT("TlsImplicit", tls_implicit); + + return tls_init_error = tls_init(); +} + +/* command table ... + * first : command "type" (see the doc/API for more info) + * + * second : command "name", or the actual null-terminated ascii text + * sent by a client (in uppercase) for this command. see + * include/ftp.h for macros which define all rfced FTP protocol + * commands. Can also be the special macro C_ANY, which receives + * ALL commands. + * + * third : command "group" (used for access control via Limit directives), + * this can be either G_DIRS (for commands related to directory + * listing), G_READ (for commands related to reading files), + * G_WRITE (for commands related to file writing), or the + * special G_NONE for those commands against which the + * special will not be applied. + * + * fourth : function pointer to your handler + * + * fifth : TRUE if the command cannot be used before authentication + * (via USER/PASS), otherwise FALSE. + * + * sixth : TRUE if the command can be sent during a file transfer + * (note: as of 1.1.5, this is obsolete) + * + */ + +cmdtable mod_tls_commands[] = { + { CMD, "AUTH", G_NONE, cmd_auth, FALSE, FALSE }, + { CMD, "PBSZ", G_NONE, cmd_pbsz, FALSE, FALSE }, + { CMD, "PROT", G_NONE, cmd_prot, FALSE, FALSE }, + { 0, NULL } +}; + +module tls_module = { + NULL,NULL, /* Always NULL */ + 0x20, /* API Version 2.0 */ + "tls", + mod_tls_config, /* Configuration handler table */ + mod_tls_commands, /* Command handler table */ + NULL, /* No authentication handler table */ + mod_tls_init, /* Initialization function */ + mod_tls_child_init /* Post-fork "child mode" init */ +}; diff -urN proftpd-1.2.6rc1.orig/sample-configurations/basic.conf proftpd-1.2.6rc1-tls/sample-configurations/basic.conf --- proftpd-1.2.6rc1.orig/sample-configurations/basic.conf Sun Oct 18 04:24:41 1998 +++ proftpd-1.2.6rc1-tls/sample-configurations/basic.conf Wed Jul 3 14:49:19 2002 @@ -3,10 +3,37 @@ # and a single anonymous login. It assumes that you have a user/group # "nobody" and "ftp" for normal operation and anon. -ServerName "ProFTPD Default Installation" +ServerName "ProFTPD-TLS Default Installation" +# ServerType is either "standalone" or "inetd" ServerType standalone DefaultServer on +# If you want .message files to work with browsers, you probably +# want to uncomment the next line +#MultilineRFC2228 on + +# These are the TLS related options, default values +#TlsRsaCertFile ftpd-rsa.pem +#TlsRsaKeyFile ftpd-rsa-key.pem +#TlsDsaCertFile ftpd-dsa.pem +#TlsDsaKeyFile ftpd-dsa-key.pem +#TlsCrlFile ftpd-crl.pem +#TlsDhParamFile ftpd-dhparam.pem +#TlsCipherList ALL:!ADH +#TlsRequired off +# don't verify any peer certificates +#TlsCertsOk off +# Some ftp clients (e.g. SmartFTP) uses a broken SSL/TLS implementation that +# aborts the SSL/TLS handshake, if the server sends a "CertificateRequest" and +# the client don't have any certificate. This behaviour violates both the SSLv3 +# and TLSv1 spec (it's actually old SSLv2 behaviour). To be able to use those +# clients without client certs, you must set the following option to "on". +#TlsDontRequestCert off +# Set the following to "on" if you want to use implicit SSL/TLS. It's not the +# recommended way do to SSL/TLS ftp, but some user's want it anyway. Remember +# to make proftpd listen to the proper ``ftps'' port also. +#TlsImplicit off + # Port 21 is the standard FTP port. Port 21 # Umask 022 is a good standard umask to prevent new dirs and files diff -urN proftpd-1.2.6rc1.orig/src/data.c proftpd-1.2.6rc1-tls/src/data.c --- proftpd-1.2.6rc1.orig/src/data.c Tue Jul 2 19:01:47 2002 +++ proftpd-1.2.6rc1-tls/src/data.c Wed Jul 3 10:54:31 2002 @@ -41,6 +41,11 @@ #include #endif /* HAVE_SYS_UIO_H */ +#ifdef TLS +#include +#include "tlsutil.h" +#endif + /* local macro */ #define MODE_STRING (session.flags & (SF_ASCII|SF_ASCII_OVERRIDE) ? \ @@ -199,6 +204,18 @@ */ send_response(R_150, "FILE: %s", reason); } +#ifdef TLS + /* start TLS handshake if appropriate */ + if (tls_on_data) + if (tls_accept(c, TRUE)) { + /* exit if we fail */ + send_response_async(R_421, + "Failed TLS negotiation on data channel, disconnected"); + main_exit((void*) LOG_ERR, + "Failed TLS negotiation on data channel, disconnected.", (void*) 0, + NULL); + } +#endif return 0; } @@ -289,6 +306,18 @@ send_response(R_150, "FILE: %s", reason); } +#ifdef TLS + /* start TLS handshake if appropriate */ + if (tls_on_data) + if (tls_accept(c, TRUE)) { + /* exit if we fail */ + send_response_async(R_421, + "Failed TLS negotiation on data channel, disconnected"); + main_exit((void*) LOG_ERR, + "Failed TLS negotiation on data channel, disconnected.", (void*) 0, + NULL); + } +#endif inet_close(session.pool,session.d); inet_setnonblock(session.pool,session.d); session.d = c; diff -urN proftpd-1.2.6rc1.orig/src/io.c proftpd-1.2.6rc1-tls/src/io.c --- proftpd-1.2.6rc1.orig/src/io.c Tue Jul 2 19:01:47 2002 +++ proftpd-1.2.6rc1-tls/src/io.c Wed Jul 3 11:10:46 2002 @@ -27,6 +27,11 @@ #include +#ifdef TLS +#include +#include "tlsutil.h" +#endif + #ifndef IAC #define IAC 255 #endif @@ -102,6 +107,9 @@ f->fd = fd; f->mode = mode; +#ifdef TLS + f->tls_session = NULL; +#endif return f; } @@ -116,6 +124,11 @@ res = close(f->fd); f->fd = -1; +#ifdef TLS + /* only close the READ IOFILE since they come in pairs with the same SSL */ + if (f->mode == IO_READ) + tls_close_session(f->tls_session); +#endif destroy_pool(f->pool); return res; @@ -248,6 +261,12 @@ tv.tv_sec = ((f->flags & IO_INTR) ? f->restart_secs : 60); tv.tv_usec = 0; +#ifdef TLS + /* check if there some data "hidden" left in the OpenSSL system */ + if (tls_pending(f->tls_session)) + res = 1; + else +#endif res = select(f->fd + 1,rfds,wfds,NULL,&tv); switch(res) { case -1: @@ -305,6 +324,11 @@ do { run_schedule(); handle_signals(); +#ifdef TLS + if (f->tls_session) + written = tls_write(f->tls_session,buf,size); + else +#endif written = write(f->fd,buf,size); } while(written == -1 && errno == EINTR); break; @@ -361,6 +385,11 @@ while(size) { do { handle_signals(); +#ifdef TLS + if (f->tls_session) + written = tls_write(f->tls_session,buf,size); + else +#endif written = write(f->fd, buf, size); } while (written == -1 && errno == EINTR); @@ -414,6 +443,11 @@ do { run_schedule(); handle_signals(); +#ifdef TLS + if (f->tls_session) + bread = tls_read(f->tls_session,buf,size); + else +#endif bread = read(f->fd, buf, size); } while(bread == -1 && errno == EINTR); break; diff -urN proftpd-1.2.6rc1.orig/src/main.c proftpd-1.2.6rc1-tls/src/main.c --- proftpd-1.2.6rc1.orig/src/main.c Fri Jun 28 20:43:17 2002 +++ proftpd-1.2.6rc1-tls/src/main.c Wed Jul 3 11:46:08 2002 @@ -71,6 +71,11 @@ #include "privs.h" +#ifdef TLS +#include +#include "tlsutil.h" +#endif + /* From mod_core.c */ extern int core_display_file(const char *numeric, const char *fn, const char *fs); @@ -647,6 +652,12 @@ void end_login(int exitcode) { end_login_noexit(); +#ifdef TLS + if (session.c) + tls_close_session(session.c->inf->tls_session); + if (is_master) + tls_cleanup(); +#endif _exit(exitcode); } @@ -1593,6 +1604,21 @@ inet_ntoa(*session.c->remote_ipaddr), session.c->remote_port); +#ifdef TLS + /* start TLS handshake if we use implicit TLS */ + if (tls_implicit) { + if (tls_accept(conn, FALSE)) { + /* exit if we fail */ + send_response_async(R_421, + "Failed TLS negotiation on control channel, disconnected"); + main_exit((void*) LOG_ERR, + "Failed TLS negotiation on control channel, disconnected.", + (void*) 0, NULL); + } else + tls_on_data = 1; + } +#endif + /* xfer_set_data_port(conn->local_ipaddr,conn->local_port-1); */ cmd_loop(serv,conn); } diff -urN proftpd-1.2.6rc1.orig/src/tlsutil.c proftpd-1.2.6rc1-tls/src/tlsutil.c --- proftpd-1.2.6rc1.orig/src/tlsutil.c Thu Jan 1 01:00:00 1970 +++ proftpd-1.2.6rc1-tls/src/tlsutil.c Thu Jul 11 19:53:59 2002 @@ -0,0 +1,889 @@ +/* + * Copyright (c) 1999 - 2002 Peter 'Luna' Runestig + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifi- + * cation, are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright no- + * tice, this list of conditions and the following disclaimer in the do- + * cumentation and/or other materials provided with the distribution. + * + * o The names of the contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 LI- + * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN- + * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV- + * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI- + * LITY, 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 lint +static char copyright[] = +"@(#) Copyright (c) Peter 'Luna' Runestig 1999 - 2002 .\n"; +#endif /* not lint */ + +/* ProFTPD special includes */ +#include "conf.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tls_dh.h" +#include "io.h" +#include "inet.h" + +#if OPENSSL_VERSION_NUMBER < 0x00905100 +/* ASN1_BIT_STRING_cmp was renamed in 0.9.5 */ +#define M_ASN1_BIT_STRING_cmp ASN1_BIT_STRING_cmp +#endif + +#define DEFRSACERTFILE "ftpd-rsa.pem" +#define DEFRSAKEYFILE "ftpd-rsa-key.pem" +#define DEFDSACERTFILE "ftpd-dsa.pem" +#define DEFDSAKEYFILE "ftpd-dsa-key.pem" +#define DEFCRLFILE "ftpd-crl.pem" +#define DEFDHPARAMFILE "ftpd-dhparam.pem" +#define DEFAULTCIPHERLIST "ALL:!ADH" + +/* define if you want to check for OpenSSL-related memory leaks */ +/*#define DEBUG_OPENSSL_MEM*/ + +int x509_to_user(X509 *peer_cert, char *userid, int len); +static char *file_fullpath(char *fn); + +int tls_on_ctrl = 0; +int tls_on_data = 0; +int tls_implicit = 0; +int tls_init_error = 0; +int tls_no_verify = 0; +int tls_dont_request_cert = 0; +int tls_required = 0; +char *tls_rsa_key_file = NULL; +char *tls_rsa_cert_file = NULL; +char *tls_dsa_key_file = NULL; +char *tls_dsa_cert_file = NULL; +char *tls_crl_file = NULL; +char *tls_crl_dir = NULL; +char *tls_dhparam_file = NULL; +char *tls_rand_file = NULL; +char *tls_cipher_list = NULL; +static SSL *first_ssl = NULL; +static SSL_CTX *ssl_ctx = NULL; +static X509_STORE *crl_store = NULL; +static DH *tmp_dh = NULL; +static RSA *tmp_rsa = NULL; + +/* we need this so we don't mix static and malloc'ed strings */ +void tls_set_file_defaults(void) +{ + if (!tls_rsa_key_file) + tls_rsa_key_file = strdup(DEFRSAKEYFILE); + if (!tls_rsa_cert_file) + tls_rsa_cert_file = strdup(DEFRSACERTFILE); + if (!tls_dsa_key_file) + tls_dsa_key_file = strdup(DEFDSAKEYFILE); + if (!tls_dsa_cert_file) + tls_dsa_cert_file = strdup(DEFDSACERTFILE); + if (!tls_crl_file) + tls_crl_file = strdup(DEFCRLFILE); + if (!tls_crl_dir && (tls_crl_dir = malloc(strlen(X509_get_default_cert_area()) + 5))) + sprintf(tls_crl_dir, "%s/crl", X509_get_default_cert_area()); + if (!tls_dhparam_file) + tls_dhparam_file = strdup(DEFDHPARAMFILE); + if (!tls_cipher_list) + tls_cipher_list = strdup(DEFAULTCIPHERLIST); +} + +/* if we are using OpenSSL 0.9.6 or newer, we want to use X509_NAME_print_ex() + * instead of X509_NAME_oneline(). + */ +static char *x509_name_oneline(X509_NAME *n, char *buf, int len) +{ +#if OPENSSL_VERSION_NUMBER < 0x000906000 + return X509_NAME_oneline(n, buf, len); +#else + BIO *mem = BIO_new(BIO_s_mem()); + char *data = NULL; + int data_len = 0, ok; + + ok = X509_NAME_print_ex(mem, n, 0, XN_FLAG_ONELINE); + if (ok) + data_len = BIO_get_mem_data(mem, &data); + if (data) { + /* the 'data' returned is not '\0' terminated */ + if (buf) { + memcpy(buf, data, data_len < len ? data_len : len); + buf[data_len < len ? data_len : len - 1] = 0; + BIO_free(mem); + return buf; + } else { + char *b = malloc(data_len + 1); + if (b) { + memcpy(b, data, data_len); + b[data_len] = 0; + } + BIO_free(mem); + return b; + } + } else { + BIO_free(mem); + return NULL; + } +#endif /* OPENSSL_VERSION_NUMBER >= 0x000906000 */ +} + +char *tls_get_subject_name() +{ + static char name[256]; + X509 *cert; + + if ((cert = SSL_get_peer_certificate(first_ssl))) { + x509_name_oneline(X509_get_subject_name(cert), name, sizeof(name)); + X509_free(cert); + return name; + } else + return NULL; +} + +static DH *tmp_dh_cb(SSL *ssl, int is_export, int keylength) +{ + FILE *fp; + + if (!tmp_dh) { + /* first try any 'tls_dhparam_file', else use built-in dh params */ + if (tls_dhparam_file && (fp = fopen(tls_dhparam_file, "r"))) { + tmp_dh = PEM_read_DHparams(fp, NULL, NULL, NULL); + fclose(fp); + if (tmp_dh) + return tmp_dh; + } + switch (keylength) { + case 512: return tmp_dh = get_dh512(); + case 768: return tmp_dh = get_dh768(); + case 1024: return tmp_dh = get_dh1024(); + case 1536: return tmp_dh = get_dh1536(); + case 2048: return tmp_dh = get_dh2048(); + default: return tmp_dh = get_dh1024(); + } + } + else + return tmp_dh; +} + +static RSA *tmp_rsa_cb(SSL *ssl, int is_export, int keylength) +{ + if (!tmp_rsa) + tmp_rsa = RSA_generate_key(keylength, RSA_F4, NULL, NULL); + return tmp_rsa; +} + +/* check_file() expands 'file' to an existing full path or NULL if not found */ +static void check_file(char **file) +{ + char *p; + + if (*file) { + p = file_fullpath(*file); + if (p == *file) /* same pointer returned from file_fullpath() */ + return; + free(*file); + if (p) { + *file = malloc(strlen(p) + 1); + strcpy(*file, p); + } + else + *file = NULL; + } +} + +/* this one is (very much!) based on work by Ralf S. Engelschall . + * comments by Ralf. + */ +static int verify_crl(int ok, X509_STORE_CTX *ctx) +{ + X509_OBJECT obj; + X509_NAME *subject; + X509_NAME *issuer; + X509 *xs; + X509_CRL *crl; + X509_REVOKED *revoked; + X509_STORE_CTX store_ctx; + long serial; + int i, n, rc; + char *cp; + + /* + * Unless a revocation store for CRLs was created we + * cannot do any CRL-based verification, of course. + */ + if (!crl_store) + return ok; + + /* + * Determine certificate ingredients in advance + */ + xs = X509_STORE_CTX_get_current_cert(ctx); + subject = X509_get_subject_name(xs); + issuer = X509_get_issuer_name(xs); + + /* + * OpenSSL provides the general mechanism to deal with CRLs but does not + * use them automatically when verifying certificates, so we do it + * explicitly here. We will check the CRL for the currently checked + * certificate, if there is such a CRL in the store. + * + * We come through this procedure for each certificate in the certificate + * chain, starting with the root-CA's certificate. At each step we've to + * both verify the signature on the CRL (to make sure it's a valid CRL) + * and it's revocation list (to make sure the current certificate isn't + * revoked). But because to check the signature on the CRL we need the + * public key of the issuing CA certificate (which was already processed + * one round before), we've a little problem. But we can both solve it and + * at the same time optimize the processing by using the following + * verification scheme (idea and code snippets borrowed from the GLOBUS + * project): + * + * 1. We'll check the signature of a CRL in each step when we find a CRL + * through the _subject_ name of the current certificate. This CRL + * itself will be needed the first time in the next round, of course. + * But we do the signature processing one round before this where the + * public key of the CA is available. + * + * 2. We'll check the revocation list of a CRL in each step when + * we find a CRL through the _issuer_ name of the current certificate. + * This CRLs signature was then already verified one round before. + * + * This verification scheme allows a CA to revoke its own certificate as + * well, of course. + */ + + /* + * Try to retrieve a CRL corresponding to the _subject_ of + * the current certificate in order to verify it's integrity. + */ + memset((char *)&obj, 0, sizeof(obj)); + X509_STORE_CTX_init(&store_ctx, crl_store, NULL, NULL); + rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj); + X509_STORE_CTX_cleanup(&store_ctx); + crl = obj.data.crl; + if (rc > 0 && crl != NULL) { + /* + * Verify the signature on this CRL + */ + if (X509_CRL_verify(crl, X509_get_pubkey(xs)) <= 0) { + log_pri(LOG_ERR, "Invalid signature on CRL!"); + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); + X509_OBJECT_free_contents(&obj); + return 0; + } + + /* + * Check date of CRL to make sure it's not expired + */ + i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)); + if (i == 0) { + log_pri(LOG_ERR, "Found CRL has invalid nextUpdate field."); + X509_STORE_CTX_set_error(ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); + X509_OBJECT_free_contents(&obj); + return 0; + } + if (i < 0) { + log_pri(LOG_ERR, "Found CRL is expired - revoking all certificates until you get updated CRL."); + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED); + X509_OBJECT_free_contents(&obj); + return 0; + } + X509_OBJECT_free_contents(&obj); + } + + /* + * Try to retrieve a CRL corresponding to the _issuer_ of + * the current certificate in order to check for revocation. + */ + memset((char *)&obj, 0, sizeof(obj)); + X509_STORE_CTX_init(&store_ctx, crl_store, NULL, NULL); + rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj); + X509_STORE_CTX_cleanup(&store_ctx); + crl = obj.data.crl; + if (rc > 0 && crl != NULL) { + /* + * Check if the current certificate is revoked by this CRL + */ + n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); + for (i = 0; i < n; i++) { + revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); + if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(xs)) == 0) { + + serial = ASN1_INTEGER_get(revoked->serialNumber); + cp = x509_name_oneline(issuer, NULL, 0); + log_pri(LOG_ERR, "Certificate with serial %ld (0x%lX) revoked per CRL from issuer %s", + serial, serial, cp ? cp : "(ERROR)"); + if (cp) free(cp); + + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED); + X509_OBJECT_free_contents(&obj); + return 0; + } + } + X509_OBJECT_free_contents(&obj); + } + return ok; +} + +static int verify_callback(int ok, X509_STORE_CTX *ctx) +{ + /* TODO: Make up my mind on what to accept or not.*/ + /* we can configure the server to skip the peer's cert verification */ + if (tls_no_verify) + return 1; + + ok = verify_crl(ok, ctx); + if (!ok) { + switch (ctx->error) { + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + log_pri(LOG_ERR, "Error: Client's certificate is self signed."); + ok = 0; + break; + case X509_V_ERR_CERT_HAS_EXPIRED: + log_pri(LOG_ERR, "Error: Client's certificate has expired."); + ok = 0; + break; + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + log_pri(LOG_ERR, "Error: Client's certificate issuer's certificate isn't available locally."); + ok = 0; + break; + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + log_pri(LOG_ERR, "Error: Unable to verify leaf signature."); + ok = 0; + break; + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + /* XXX this is strange. we get this error for certain clients (ie Jeff's kftp) when + * all is ok. I think it's because the client is actually sending the whole CA + * cert. this must be figured out, but we let it pass for now. if the CA cert isn't + * available locally, we will fail anyway. + */ + log_pri(LOG_NOTICE, "Warning: Self signed certificate in chain."); + ok = 1; + break; + case X509_V_ERR_CERT_REVOKED: + log_pri(LOG_ERR, "Error: Certificate revoked."); + ok = 0; + break; + default: + log_pri(LOG_ERR, + "Error %d while verifying the client's certificate.", ctx->error); + ok = 0; + break; + } + } + return ok; +} + +static int seed_PRNG(void) +{ + char stackdata[1024]; + static char rand_file[300]; + FILE *fh; + +#if OPENSSL_VERSION_NUMBER >= 0x00905100 + if (RAND_status()) + return 0; /* PRNG already good seeded */ +#endif + /* if the device '/dev/urandom' is present, OpenSSL uses it by default. + * check if it's present, else we have to make random data ourselfs. + */ + if ((fh = fopen("/dev/urandom", "r"))) { + fclose(fh); + return 0; + } + /* the ftpd's rand file is (openssl-dir)/.rnd */ + sprintf(rand_file, "%s/.rnd", X509_get_default_cert_area()); + tls_rand_file = rand_file; + if (!RAND_load_file(rand_file, 1024)) { + /* no .rnd file found, create new seed */ + unsigned int c; + c = time(NULL); + RAND_seed(&c, sizeof(c)); + c = getpid(); + RAND_seed(&c, sizeof(c)); + RAND_seed(stackdata, sizeof(stackdata)); + } +#if OPENSSL_VERSION_NUMBER >= 0x00905100 + if (!RAND_status()) + return 2; /* PRNG still badly seeded */ +#endif + return 0; +} + +int tls_init(void) +{ + int err; + +#ifdef DEBUG_OPENSSL_MEM + CRYPTO_malloc_debug_init(); + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); +#endif /* DEBUG_OPENSSL_MEM */ + SSL_load_error_strings(); + SSL_library_init(); +#ifdef ZLIB + { + COMP_METHOD *cm = COMP_zlib(); + if (cm != NULL && cm->type != NID_undef) { + SSL_COMP_add_compression_method(0xe0, cm); /* Eric Young's ZLIB ID */ + } + } +#endif /* ZLIB */ + ssl_ctx = SSL_CTX_new(SSLv23_method()); + if (!ssl_ctx) { + log_pri(LOG_ERR, "SSL_CTX_new() %s", + (char *)ERR_error_string(ERR_get_error(), NULL)); + return 1; + } + SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2); + if (!tls_dont_request_cert) + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, verify_callback); + SSL_CTX_set_default_verify_paths(ssl_ctx); + /* set up session caching */ + SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_SERVER); + SSL_CTX_set_session_id_context(ssl_ctx, "1", 1); + + /* let's find out which files are available */ + tls_set_file_defaults(); +#ifdef PRIVS_ROOT + PRIVS_ROOT /* ProFTPD must regain root privs here to read the key file(s) */ +#endif + check_file(&tls_rsa_cert_file); + check_file(&tls_rsa_key_file); + check_file(&tls_dsa_cert_file); + check_file(&tls_dsa_key_file); + check_file(&tls_crl_file); + check_file(&tls_dhparam_file); + if (!tls_rsa_cert_file && !tls_dsa_cert_file) { + log_pri(LOG_ERR, "No certificate files found!"); + return 2; + } + if (!tls_rsa_key_file) + tls_rsa_key_file = tls_rsa_cert_file; + if (!tls_dsa_key_file) + tls_dsa_key_file = tls_dsa_cert_file; + + if (tls_rsa_cert_file) { + err = SSL_CTX_use_certificate_file(ssl_ctx, tls_rsa_cert_file, X509_FILETYPE_PEM); + if (err <= 0) { + log_pri(LOG_ERR, "SSL_CTX_use_certificate_file(%s) %s", tls_rsa_cert_file, + (char *)ERR_error_string(ERR_get_error(), NULL)); + return 3; + } + SSL_CTX_set_tmp_rsa_callback(ssl_ctx, tmp_rsa_cb); + } + if (tls_rsa_key_file) { + err = SSL_CTX_use_PrivateKey_file(ssl_ctx, tls_rsa_key_file, X509_FILETYPE_PEM); + if (err <= 0) { + log_pri(LOG_ERR, "SSL_CTX_use_PrivateKey_file(%s) %s", tls_rsa_key_file, + (char *)ERR_error_string(ERR_get_error(), NULL)); + return 4; + } + } + if (tls_dsa_cert_file) { + err = SSL_CTX_use_certificate_file(ssl_ctx, tls_dsa_cert_file, X509_FILETYPE_PEM); + if (err <= 0) { + log_pri(LOG_ERR, "SSL_CTX_use_certificate_file(%s) %s", tls_dsa_cert_file, + (char *)ERR_error_string(ERR_get_error(), NULL)); + return 5; + } + } + if (tls_dsa_key_file) { + err = SSL_CTX_use_PrivateKey_file(ssl_ctx, tls_dsa_key_file, X509_FILETYPE_PEM); + if (err <= 0) { + log_pri(LOG_ERR, "SSL_CTX_use_PrivateKey_file(%s) %s", tls_dsa_key_file, + (char *)ERR_error_string(ERR_get_error(), NULL)); + return 6; + } + } +#ifdef PRIVS_RELINQUISH + PRIVS_RELINQUISH /* ProFTPD dropping root privs again */ +#endif + + SSL_CTX_set_tmp_dh_callback(ssl_ctx, tmp_dh_cb); + + /* set up the CRL */ + if ((tls_crl_file || tls_crl_dir) && (crl_store = X509_STORE_new())) + X509_STORE_load_locations(crl_store, tls_crl_file, tls_crl_dir); + + if (tls_cipher_list) + SSL_CTX_set_cipher_list(ssl_ctx, tls_cipher_list); + else + log_pri(LOG_NOTICE, "NULL tls_cipher_list!"); + if (seed_PRNG()) + log_pri(LOG_NOTICE, "Wasn't able to properly seed the PRNG!"); + return 0; +} + +char *tls_userid_from_client_cert() +{ + static char cn[256]; + static char *r = cn; + static int again = 0; + int err; + X509 *client_cert; + + if (!tls_on_ctrl || !first_ssl) + return NULL; + if (again) + return r; + again = 1; + if ((client_cert = SSL_get_peer_certificate(first_ssl))) { + /* call the custom function */ + err = x509_to_user(client_cert, cn, sizeof(cn)); + X509_free(client_cert); + if (err) + return r = NULL; + else + return r; + } + else + return r = NULL; +} + +int tls_is_user_valid(char *user) +/* check if clients cert is in "user"'s ~/.tlslogin file */ +{ + char buf[512]; + int r = 0; + FILE *fp = NULL; + X509 *client_cert = NULL, *file_cert; + struct passwd *pwd; + + if (!tls_on_ctrl || !first_ssl || !user) + return 0; +#ifdef PRIVS_ROOT + PRIVS_ROOT /* ProFTPD must regain root privs here to read the .tlslogin file */ +#endif + if (!(pwd = getpwnam(user))) + goto cleanup; + snprintf(buf, sizeof(buf), "%s/.tlslogin", pwd->pw_dir); + if (!(fp = fopen(buf, "r"))) + goto cleanup; + if (!(client_cert = SSL_get_peer_certificate(first_ssl))) + goto cleanup; + while ((file_cert = PEM_read_X509(fp, NULL, NULL, NULL))) { + if (!M_ASN1_BIT_STRING_cmp(client_cert->signature, file_cert->signature)) + r = 1; + X509_free(file_cert); + if (r) break; + } + cleanup: + if (client_cert) + X509_free(client_cert); + if (fp) + fclose(fp); +#ifdef PRIVS_RELINQUISH + PRIVS_RELINQUISH /* ProFTPD dropping root privs again */ +#endif + return r; +} + +void tls_close_session(SSL *ssl) +{ + if (!ssl) + return; + SSL_shutdown(ssl); + SSL_free(ssl); +} + +int tls_accept(conn_t *conn, int data_connection) +{ + int err; + SSL *ssl; + static int logged_data_connection = 0; + + if (!ssl_ctx) { + log_pri(LOG_ERR, "tls_accept() called when ssl_ctx == NULL!"); + return 1; + } + ssl = SSL_new(ssl_ctx); + if (!ssl) { + log_pri(LOG_ERR, "SSL_new() %s", (char *)ERR_error_string(ERR_get_error(), NULL)); + return 2; + } + + if (!first_ssl) + first_ssl = ssl; + SSL_set_fd(ssl, conn->rfd); /* it works with either rfd or wfd (I hope ;-) */ + + retry: + err = SSL_accept(ssl); + if (err < 1) { + int ssl_err = SSL_get_error(ssl, err); + if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) + goto retry; + log_pri(LOG_ERR, "SSL_accept(): (%d) %s", ssl_err, + (char *)ERR_error_string(ERR_get_error(), NULL)); + tls_close_session(ssl); + return 3; + } + conn->inf->tls_session = conn->outf->tls_session = ssl; + tls_on_ctrl = 1; + + if (data_connection) { + /* only log first TLS data connection, otherwise there might be lots of logging */ + if (!logged_data_connection) { + log_pri(LOG_NOTICE, "TLS data connection using cipher %s (%d bits)", + SSL_get_cipher(ssl), SSL_get_cipher_bits(ssl, NULL)); + logged_data_connection = 1; + } + } else { + char *subject = tls_get_subject_name(); + log_pri(LOG_NOTICE, "TLS connection using cipher %s (%d bits)", + SSL_get_cipher(ssl), SSL_get_cipher_bits(ssl, NULL)); + if (subject) + log_pri(LOG_NOTICE, "Client: %s", subject); + } + return 0; +} + +void tls_cleanup(void) +{ + if (crl_store) { + X509_STORE_free(crl_store); + crl_store = NULL; + } + if (ssl_ctx) { + SSL_CTX_free(ssl_ctx); + ssl_ctx = NULL; + } + if (tmp_dh) { + DH_free(tmp_dh); + tmp_dh = NULL; + } + if (tmp_rsa) { + RSA_free(tmp_rsa); + tmp_rsa = NULL; + } + ERR_free_strings(); + ERR_remove_state(0); + EVP_cleanup(); /* release the stuff allocated by SSL_library_init() */ + if (tls_rsa_key_file) { + if (tls_rsa_key_file != tls_rsa_cert_file) + free(tls_rsa_key_file); + tls_rsa_key_file = NULL; + } + if (tls_rsa_cert_file) { + free(tls_rsa_cert_file); + tls_rsa_cert_file = NULL; + } + if (tls_dsa_key_file) { + if (tls_dsa_key_file != tls_dsa_cert_file) + free(tls_dsa_key_file); + tls_dsa_key_file = NULL; + } + if (tls_dsa_cert_file) { + free(tls_dsa_cert_file); + tls_dsa_cert_file = NULL; + } + if (tls_dhparam_file) { + free(tls_dhparam_file); + tls_dhparam_file = NULL; + } + if (tls_crl_file) { + free(tls_crl_file); + tls_crl_file = NULL; + } + if (tls_crl_dir) { + free(tls_crl_dir); + tls_crl_dir = NULL; + } + if (tls_cipher_list) { + free(tls_cipher_list); + tls_cipher_list = NULL; + } + if (tls_rand_file) + /* tls_rand_file is not malloc()'ed */ + RAND_write_file(tls_rand_file); +#ifdef DEBUG_OPENSSL_MEM + { + char fname[] = "/tmp/proftpd_memleak_XXXXXX"; + int fd; + if ((fd = mkstemp(fname)) != -1) { + FILE *f = fdopen(fd, "w"); + if (f) { + CRYPTO_mem_leaks_fp(f); + fclose(f); + } + } + } +#endif /* DEBUG_OPENSSL_MEM */ +} + +static void handle_ssl_error(int error, int line) +{ + switch (error) { + case SSL_ERROR_NONE: + return; + case SSL_ERROR_SSL: + log_pri(LOG_ERR, "Panic: SSL_ERROR_SSL on line %d!", line); + break; + case SSL_ERROR_WANT_READ: + log_pri(LOG_ERR, "Panic: SSL_ERROR_WANT_READ on line %d!", line); + break; + case SSL_ERROR_WANT_WRITE: + log_pri(LOG_ERR, "Panic: SSL_ERROR_WANT_WRITE on line %d!", line); + break; + case SSL_ERROR_WANT_X509_LOOKUP: + log_pri(LOG_ERR, "Panic: SSL_ERROR_WANT_X509_LOOKUP on line %d!", line); + break; + case SSL_ERROR_SYSCALL: + /* ProFTPD is sloppy in checking the return value/errno status from + * read()/write(), so we must double-check here so we don't generate + * unnecessary fuzz... + */ + if (errno == ECONNRESET) /* peer hung up */ + return; + log_pri(LOG_ERR, "Panic: SSL_ERROR_SYSCALL on line %d!", line); + break; + case SSL_ERROR_ZERO_RETURN: + log_pri(LOG_ERR, "Panic: SSL_ERROR_ZERO_RETURN on line %d!", line); + break; + case SSL_ERROR_WANT_CONNECT: + log_pri(LOG_ERR, "Panic: SSL_ERROR_WANT_CONNECT on line %d!", line); + break; + default: + log_pri(LOG_ERR, "Panic: SSL_ERROR %d on line %d!", error, line); + break; + } + /* if we reply something here, we might just trigger another handle_ssl_error() + * call and loop endlessly... + */ + main_exit((void*) LOG_ERR, + "Unexpected OpenSSL error, disconnected.", (void*) 0, NULL); + /* NOTREACHED */ +} + +static int select_read(int rfd) +/* timeout = 20 seconds */ +{ + fd_set rfds; + struct timeval tv; + + FD_ZERO(&rfds); + FD_SET(rfd, &rfds); + tv.tv_sec = 20; + tv.tv_usec = 0; + return select(rfd + 1, &rfds, NULL, NULL, &tv); +} + +ssize_t tls_read(SSL *ssl, void *buf, size_t count) +{ + ssize_t c; + + retry: + c = SSL_read(ssl, buf, count); + if (c < 0) { + int err = SSL_get_error(ssl, c); + /* read(2) returns only the generic error number -1 */ + c = -1; + switch (err) { + case SSL_ERROR_WANT_READ: + /* OpenSSL needs more data from the wire to finish the current block, + * so we wait a little while for it. */ + err = select_read(SSL_get_fd(ssl)); + if (err > 0) + goto retry; + else if (err == 0) + /* still missing data after timeout. simulate an EINTR and return. */ + errno = EINTR; + /* if err < 0, i.e. some error from the select(), everything is already + * in place; errno is properly set and this function returns -1. */ + break; + default: + handle_ssl_error(err, __LINE__); + break; + } + } + return c; +} + +ssize_t tls_write(SSL *ssl, const void *buf, size_t count) +{ + ssize_t c; + + c = SSL_write(ssl, buf, count); + if (c < 0) { + int err = SSL_get_error(ssl, c); + /* write(2) returns only the generic error number -1 */ + c = -1; + switch (err) { + case SSL_ERROR_WANT_WRITE: + /* simulate an EINTR in case OpenSSL wants to write more */ + errno = EINTR; + break; + default: + handle_ssl_error(err, __LINE__); + break; + } + } + return c; +} + +int tls_pending(SSL *ssl) +{ + if (ssl) + return SSL_pending(ssl); + else + return 0; +} + +char *file_fullpath(char *fn) +{ + static char fp[256]; + FILE *file; + char *dir; + + /* check if it is a full path already */ + if (strchr(fn, '/')) { + if ((file = fopen(fn, "r"))) { + fclose(file); + return fn; + } + else + return NULL; + } + /* check if it is in current dir */ + if ((file = fopen(fn, "r"))) { + fclose(file); + return fn; + } + if (!(dir = getenv(X509_get_default_cert_dir_env()))) /* $SSL_CERT_DIR */ + dir = (char *)X509_get_default_cert_dir(); + snprintf(fp, sizeof(fp), "%s/%s", dir, fn); + if ((file = fopen(fp, "r"))) { + fclose(file); + return fp; + } + dir = (char *)X509_get_default_private_dir(); + snprintf(fp, sizeof(fp), "%s/%s", dir, fn); + if ((file = fopen(fp, "r"))) { + fclose(file); + return fp; + } + return NULL; +} diff -urN proftpd-1.2.6rc1.orig/src/x509_to_user.c proftpd-1.2.6rc1-tls/src/x509_to_user.c --- proftpd-1.2.6rc1.orig/src/x509_to_user.c Thu Jan 1 01:00:00 1970 +++ proftpd-1.2.6rc1-tls/src/x509_to_user.c Mon Jun 10 11:56:48 2002 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1999, 2000 Peter 'Luna' Runestig + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifi- + * cation, are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright no- + * tice, this list of conditions and the following disclaimer in the do- + * cumentation and/or other materials provided with the distribution. + * + * o The names of the contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 LI- + * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN- + * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV- + * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI- + * LITY, 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 + +/* x509_to_user() returns 0 if valid userid in 'userid', else 1 */ +int x509_to_user(X509 *peer_cert, char *userid, int len) +{ + + if (!(peer_cert && userid)) + return 1; + + /* TODO: insert cert => userid translation code here */ + + return 1; +} diff -urN proftpd-1.2.6rc1.orig/src/x509_to_user.c.samp1 proftpd-1.2.6rc1-tls/src/x509_to_user.c.samp1 --- proftpd-1.2.6rc1.orig/src/x509_to_user.c.samp1 Thu Jan 1 01:00:00 1970 +++ proftpd-1.2.6rc1-tls/src/x509_to_user.c.samp1 Mon Jun 10 11:56:48 2002 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1999, 2000 Peter 'Luna' Runestig + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifi- + * cation, are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright no- + * tice, this list of conditions and the following disclaimer in the do- + * cumentation and/or other materials provided with the distribution. + * + * o The names of the contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 LI- + * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN- + * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV- + * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI- + * LITY, 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 + +/* sample that returns a userid in cert's subj UID */ +/* x509_to_user() returns 0 if valid userid in 'userid', else 1 */ +int x509_to_user(X509 *peer_cert, char *userid, int len) +{ + int err; + + if (!(peer_cert && userid)) + return 1; + + /* userid is in cert subject /UID */ + err = X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert), + NID_uniqueIdentifier, userid, len); + if (err > 0) + return 0; + else + return 1; +} diff -urN proftpd-1.2.6rc1.orig/src/x509_to_user.c.samp2 proftpd-1.2.6rc1-tls/src/x509_to_user.c.samp2 --- proftpd-1.2.6rc1.orig/src/x509_to_user.c.samp2 Thu Jan 1 01:00:00 1970 +++ proftpd-1.2.6rc1-tls/src/x509_to_user.c.samp2 Mon Jun 10 11:56:48 2002 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1999, 2000 Peter 'Luna' Runestig + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifi- + * cation, are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright no- + * tice, this list of conditions and the following disclaimer in the do- + * cumentation and/or other materials provided with the distribution. + * + * o The names of the contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 LI- + * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN- + * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV- + * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI- + * LITY, 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 +#include +#include +#include + +/* sample that uses SafeGossip's "Certificate Mapping Server" */ + +char *trim(char *s) +{ + while (isspace(*s)) + memmove(s, s + 1, strlen(s + 1) + 1); + while (isspace(s[strlen(s) - 1])) + s[strlen(s) - 1] = 0; + return s; +} + +/* x509_to_user() returns 0 if valid userid in 'userid', else 1 */ +int x509_to_user(X509 *peer_cert, char *userid, int len) +{ + int pin[2], pout[2], err; + FILE *pfp; + pid_t pid; + fd_set rfds; + struct timeval tv; + + if (!(peer_cert && userid)) + return 1; + + /* '/usr/sbin/authcert' reads a cert from stdin and writes the userid to stdout. */ + if (pipe(pin)) + return 1; + if (pipe(pout)) + return 1; + pid = fork(); + if (pid == -1) + return 1; + else if (pid == 0) { + /* child */ + dup2(pin[0], 0); + close(pin[0]); close(pin[1]); + dup2(pout[1], 1); + execl("/usr/sbin/authcert", "authcert", NULL); + /* normally not reached */ + exit(2); + } + + /* write PEM-formatted cert to subprocess' stdin */ + if (!(pfp = fdopen(pin[1], "w"))) + return 1; + PEM_write_X509(pfp, peer_cert); + fclose(pfp); + close(pin[0]); + + /* wait for userid from pout[0] */ + FD_ZERO(&rfds); + FD_SET(pout[0], &rfds); + tv.tv_sec = 20; + tv.tv_usec = 0; + err = select(FD_SETSIZE, &rfds, NULL, NULL, &tv); + + if (err < 1) { + close(pout[0]); close(pout[1]); + return 1; + } + err = read(pout[0], userid, len - 1); + close(pout[0]); close(pout[1]); + if (err) { + userid[err] = 0; + trim(userid); + return 0; + } + else + return 1; +}