Follows an SSL enabling diff to wu-ftpd-2.4.2-beta-18 from Academ
Consulting Services.  The original package can be retreived from
ftp://ftp.academ.com/pub/wu-ftpd/private/ The changes are mostly just a
copy of Tim Hudson's changes for BSD ftpd.  Note that here is only ftpd
server, you still need Tim's ftp client
(see ftp://ftp.psy.uq.oz.au/pub/Crypto/SSLapps/).  I made this patches
because wu-ftpd has many nice features missing in BSD ftpd, namely
per-directory permissions, guest users with personal `homes' and virtual
servers.  Mehul Patel <mehul.patel@harbinger.com> fixed a bug with PASV
mode and added a `class' to allow ssl-only clients, like this:

class local1 realssl 207.16.69.68
 
Patches for more recent versions of wuftpd-academ, if any, are on
ftp://ftp.average.org/pub/wuftp/

Note that you will need to change config and makefile sutable for your
platform by hand, adding appropriate include directory and SSL libs,
like this:

== src/makefiles/Makefile.xxx ==
IFLAGS   = ... -I/usr/local/ssl/include ...
LFLAGS   = ... -L/usr/local/ssl/lib ...
LIBES    = ... -lssl -lcrypto ...
== src/config/config.xxx ==
#define USE_SSL
====
 
You can do whatever you like with these patches except pretend that you
wrote them.

Eugene Crosser <crosser@average.org> 17 Dec 1998.
 
=================
diff -urN ../wu-ftpd-2.4.2-beta-18-ssl/src/access.c src/access.c
--- ../wu-ftpd-2.4.2-beta-18-ssl/src/access.c	Mon Jul  6 13:14:06 1998
+++ src/access.c	Thu Dec 17 04:00:05 1998
@@ -1,3 +1,17 @@
+/*
+ * The modifications to support SSLeay done by Eugene Crosser
+ * <crosser@average.org> and Mehul Patel <mehul.patel@harbinger.com>
+ * after BSD ftpd patches by Tim Hudson tjh@mincom.oz.au.
+ * The latter were mostly just pasted in.
+ *
+ * You can do whatever you like with these patches except pretend that
+ * you wrote them. 
+ *
+ * Email ssl-users-request@mincom.oz.au to get instructions on how to
+ * join the mailing list that discusses SSLeay and also these patches.
+ *
+ */
+
 /* Copyright (c) 1993, 1994  Washington University in Saint Louis
  * All rights reserved.
  *
@@ -59,7 +73,10 @@
 #if defined(SVR4) || defined(ISC)
 #include <fcntl.h>
 #endif
-
+#ifdef USE_SSL
+extern int ssl_only_flag;
+extern int ssl_secure_flag;
+#endif
 extern char remotehost[],
   remoteaddr[],
  *aclbuf;
@@ -409,6 +426,8 @@
                 log_commands = 1;
             if (!guest && !anonymous && strcasestr(ARG1, "real"))
                 log_commands = 1;
+            if (!guest && !anonymous && strcasestr(ARG1, "realssl"))
+                log_commands = 1;
         }
         if (!strcasecmp(ARG0, "transfers")) {
             set = 0;
@@ -418,6 +437,8 @@
                 set = 1;
             if (strcasestr(ARG1, "real") && !guest && !anonymous)
                 set = 1;
+            if (strcasestr(ARG1, "realssl") && !guest && !anonymous)
+                set = 1;
             if (strcasestr(ARG2, "inbound"))
                 inbound = 1;
             if (strcasestr(ARG2, "outbound"))
@@ -458,7 +479,15 @@
 
             if (guest && strcasestr(ARG1, "guest") && hostmatch(ARG[which]))
                 return (1);
-
+#ifdef USE_SSL
+            if (!guest && !anonymous && strcasestr(ARG1, "realssl") &&	
+                hostmatch(ARG[which]))
+		{
+		ssl_only_flag=1;
+		ssl_secure_flag=1;
+                return (1);
+		}
+#endif
             if (!guest && !anonymous && strcasestr(ARG1, "real") &&
                 hostmatch(ARG[which]))
                 return (1);
diff -urN ../wu-ftpd-2.4.2-beta-18-ssl/src/ftpcmd.y src/ftpcmd.y
--- ../wu-ftpd-2.4.2-beta-18-ssl/src/ftpcmd.y	Mon Jul  6 13:14:19 1998
+++ src/ftpcmd.y	Thu Dec 17 04:00:05 1998
@@ -1,4 +1,18 @@
 /*
+ * The modifications to support SSLeay done by Eugene Crosser
+ * <crosser@average.org> and Mehul Patel <mehul.patel@harbinger.com>
+ * after BSD ftpd patches by Tim Hudson tjh@mincom.oz.au.
+ * The latter were mostly just pasted in.
+ *
+ * You can do whatever you like with these patches except pretend that
+ * you wrote them. 
+ *
+ * Email ssl-users-request@mincom.oz.au to get instructions on how to
+ * join the mailing list that discusses SSLeay and also these patches.
+ *
+ */
+
+/*
  * Copyright (c) 1985, 1988 Regents of the University of California.
  * All rights reserved.
  *
@@ -102,6 +116,15 @@
 extern  char    *modenames[];
 extern  char    *formnames[];
 
+#ifdef USE_SSL
+#include "ssl_port.h"
+extern int do_ssl_start();
+extern int ssl_secure_flag;
+extern int ssl_active_flag;
+#else /* !USE_SSL */
+#define GETC getc
+#endif /* USE_SSL */
+
 static	unsigned short cliport = 0;
 static	struct in_addr cliaddr;
 static  int cmd_type;
@@ -130,8 +153,8 @@
 %}
 
 %token
-    A   B   C   E   F   I
-    L   N   P   R   S   T
+    cA   cB   cC   cE   cF   cI
+    cL   cN   cP   cR   cS   cT
 
     SP  CRLF    COMMA   STRING  NUMBER
 
@@ -142,6 +165,7 @@
     ABOR    DELE    CWD     LIST    NLST    SITE
     STAT    HELP    NOOP    MKD     RMD     PWD
     CDUP    STOU    SMNT    SYST    SIZE    MDTM
+    AUTH
 
     UMASK   IDLE    CHMOD   GROUP   GPASS   NEWER
     MINFO   INDEX   EXEC    ALIAS   CDPATH  GROUPS
@@ -172,12 +196,24 @@
 
 cmd:        USER SP username CRLF
         = {
+#ifdef USE_SSL
+            if (ssl_secure_flag && !ssl_active_flag) {
+                reply(504,"SSL is mandatory.");
+                break;
+            }
+#endif /* USE_SSL */
             user($3);
             if (log_commands) syslog(LOG_INFO, "USER %s", $3);
             free($3);
         }
     |   PASS SP password CRLF
         = {
+#ifdef USE_SSL
+            if (ssl_secure_flag && !ssl_active_flag) {
+                reply(504,"SSL is mandatory.");
+                break;
+            }
+#endif /* USE_SSL */
             if (log_commands)
                 if (anonymous)
                     syslog(LOG_INFO, "PASS %s", $3);
@@ -287,9 +323,9 @@
             if (log_commands) syslog(LOG_INFO, "ALLO %d", $3);
             reply(202, "ALLO command ignored.");
         }
-    |   ALLO SP NUMBER SP R SP NUMBER CRLF
+    |   ALLO SP NUMBER SP cR SP NUMBER CRLF
         = {
-            if (log_commands) syslog(LOG_INFO, "ALLO %d R %d", $3, $7);
+            if (log_commands) syslog(LOG_INFO, "ALLO %d cR %d", $3, $7);
             reply(202, "ALLO command ignored.");
         }
     |   RETR check_login SP pathname CRLF
@@ -703,6 +739,21 @@
             if ($4 != NULL)
                 free($4);
         }
+    |   AUTH SP STRING CRLF
+        = {
+#ifdef USE_SSL
+            if (!strncmp((char *) $3,"SSL",3)) {
+                reply(334, "AUTH SSL OK.");
+                do_ssl_start();
+            } else {
+                reply(504,"AUTH type not supported.");
+            }
+#else /* !USE_SSL */
+            reply(500,"AUTH not supported.");
+#endif /* USE_SSL */
+            if ($3 != NULL)
+                free((char *)$3);
+        }
     |   QUIT CRLF
         = {
             if (log_commands) syslog(LOG_INFO, "QUIT");
@@ -785,85 +836,85 @@
 	}
     ;
 
-form_code:  N
+form_code:  cN
     = {
         $$ = FORM_N;
     }
-    |   T
+    |   cT
     = {
         $$ = FORM_T;
     }
-    |   C
+    |   cC
     = {
         $$ = FORM_C;
     }
     ;
 
-type_code:  A
+type_code:  cA
     = {
         cmd_type = TYPE_A;
         cmd_form = FORM_N;
     }
-    |   A SP form_code
+    |   cA SP form_code
     = {
         cmd_type = TYPE_A;
         cmd_form = $3;
     }
-    |   E
+    |   cE
     = {
         cmd_type = TYPE_E;
         cmd_form = FORM_N;
     }
-    |   E SP form_code
+    |   cE SP form_code
     = {
         cmd_type = TYPE_E;
         cmd_form = $3;
     }
-    |   I
+    |   cI
     = {
         cmd_type = TYPE_I;
     }
-    |   L
+    |   cL
     = {
         cmd_type = TYPE_L;
         cmd_bytesz = NBBY;
     }
-    |   L SP byte_size
+    |   cL SP byte_size
     = {
         cmd_type = TYPE_L;
         cmd_bytesz = $3;
     }
     /* this is for a bug in the BBN ftp */
-    |   L byte_size
+    |   cL byte_size
     = {
         cmd_type = TYPE_L;
         cmd_bytesz = $2;
     }
     ;
 
-struct_code:    F
+struct_code:    cF
     = {
         $$ = STRU_F;
     }
-    |   R
+    |   cR
     = {
         $$ = STRU_R;
     }
-    |   P
+    |   cP
     = {
         $$ = STRU_P;
     }
     ;
 
-mode_code:  S
+mode_code:  cS
     = {
         $$ = MODE_S;
     }
-    |   B
+    |   cB
     = {
         $$ = MODE_B;
     }
-    |   C
+    |   cC
     = {
         $$ = MODE_C;
     }
@@ -1008,6 +1059,7 @@
     { "STOU", STOU, STR1, 1,    "<sp> file-name" },
     { "SIZE", SIZE, OSTR, 1,    "<sp> path-name" },
     { "MDTM", MDTM, OSTR, 1,    "<sp> path-name" },
+    { "AUTH", AUTH, STR1, 1,    "<sp> auth-type" },
     { NULL,   0,    0,    0,    0 }
 };
 
@@ -1074,21 +1126,21 @@
             tmpline[0] = '\0';
     }
 retry:
-    while ((c = getc(iop)) != EOF) {
+    while ((c = GETC(iop)) != EOF) {
         c &= 0377;
         if (c == IAC) {
-            if ((c = getc(iop)) != EOF) {
+            if ((c = GETC(iop)) != EOF) {
             c &= 0377;
             switch (c) {
             case WILL:
             case WONT:
-                c = getc(iop);
+                c = GETC(iop);
                 printf("%c%c%c", IAC, DONT, 0377&c);
                 (void) fflush(stdout);
                 continue;
             case DO:
             case DONT:
-                c = getc(iop);
+                c = GETC(iop);
                 printf("%c%c%c", IAC, WONT, 0377&c);
                 (void) fflush(stdout);
                 continue;
@@ -1339,51 +1391,51 @@
 
             case 'A':
             case 'a':
-                return (A);
+                return (cA);
 
             case 'B':
             case 'b':
-                return (B);
+                return (cB);
 
             case 'C':
             case 'c':
-                return (C);
+                return (cC);
 
             case 'E':
             case 'e':
-                return (E);
+                return (cE);
 
             case 'F':
             case 'f':
-                return (F);
+                return (cF);
 
             case 'I':
             case 'i':
-                return (I);
+                return (cI);
 
             case 'L':
             case 'l':
-                return (L);
+                return (cL);
 
             case 'N':
             case 'n':
-                return (N);
+                return (cN);
 
             case 'P':
             case 'p':
-                return (P);
+                return (cP);
 
             case 'R':
             case 'r':
-                return (R);
+                return (cR);
 
             case 'S':
             case 's':
-                return (S);
+                return (cS);
 
             case 'T':
             case 't':
-                return (T);
+                return (cT);
 
             }
             break;
diff -urN ../wu-ftpd-2.4.2-beta-18-ssl/src/ftpd.c src/ftpd.c
--- ../wu-ftpd-2.4.2-beta-18-ssl/src/ftpd.c	Mon Jul  6 13:14:25 1998
+++ src/ftpd.c	Thu Dec 17 04:00:27 1998
@@ -1,3 +1,17 @@
+/*
+ * The modifications to support SSLeay done by Eugene Crosser
+ * <crosser@average.org> and Mehul Patel <mehul.patel@harbinger.com>
+ * after BSD ftpd patches by Tim Hudson tjh@mincom.oz.au.
+ * The latter were mostly just pasted in.
+ *
+ * You can do whatever you like with these patches except pretend that
+ * you wrote them. 
+ *
+ * Email ssl-users-request@mincom.oz.au to get instructions on how to
+ * join the mailing list that discusses SSLeay and also these patches.
+ *
+ */
+
 /* Copyright (c) 1985, 1988, 1990 Regents of the University of California.
  * All rights reserved.
  *
@@ -85,6 +99,61 @@
 #include <errno.h>
 #include <string.h>
 
+#include "ssl_port.h"
+
+#ifdef USE_SSL
+
+BIO *bio_err;
+BIO *bio_log;
+SSL *ssl_data_con;
+int ssl_auto_login=0;
+
+#include "rsa.h"        /* extra ... */
+/*
+#include "asn1.h"
+*/
+#include "x509.h"
+#include "pem.h"
+#include "ssl.h"
+/*
+#include "ssl_err.h"
+*/
+
+SSL *ssl_con;
+SSL_CTX *ssl_ctx;
+int ssl_debug_flag=0;
+int ssl_only_flag=0;
+int ssl_active_flag=0;
+int ssl_secure_flag=0;
+int ssl_verify_flag=SSL_VERIFY_NONE;
+int ssl_certsok_flag=0;
+
+static char *auth_ssl_name=NULL;
+FILE *cin, *cout;
+
+int ssl_data_active_flag=0;
+
+/* for the moment this is a compile time option only --tjh */
+int ssl_encrypt_data=1;
+
+char ssl_file_path[1024];    /* don't look at that nasty value to the left */
+
+X509 *ssl_public_cert;
+RSA *ssl_private_key;
+
+static char *my_ssl_key_file=NULL;
+static char *my_ssl_cert_file=NULL;
+
+#endif /* USE_SSL */
+
+void
+#ifdef __STDC__
+pass(char *passwd);
+#else
+pass();
+#endif
+
+
 /*
  *  Arrange to use either varargs or stdargs
  *
@@ -452,7 +521,11 @@
     data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
     debug = 0;
 
+#ifdef USE_SSL
+    while ((c = getopt(argc, argv, ":aAvdlLiot:T:u:z:")) != -1) {
+#else
     while ((c = getopt(argc, argv, ":aAvdlLiot:T:u:")) != -1) {
+#endif
         switch (c) {
 
         case 'a':
@@ -516,11 +589,188 @@
             syslog(LOG_ERR, "option -%c requires an argument", optopt);
             break;
 
+#ifdef USE_SSL
+        case 'z':
+            syslog(LOG_WARNING, "SSL ENABLED");
+            if (strcmp(optarg, "debug") == 0 ) {
+                ssl_debug_flag=1;
+            }
+            if (strcmp(optarg, "ssl") == 0 ) {
+                ssl_only_flag=1;
+            }
+            if (strcmp(optarg, "secure") == 0 ) {
+                ssl_secure_flag=1;
+            }
+            if (strcmp(optarg, "certsok") == 0) {
+                ssl_certsok_flag=1;
+            }
+            if (strncmp(optarg, "verify=", strlen("verify=")) == 0 ) {
+                ssl_verify_flag=atoi(optarg+strlen("verify="));
+            }
+            if (strncmp(optarg, "cert=", strlen("cert=")) == 0 ) {
+                my_ssl_cert_file=optarg+strlen("cert=");
+            }
+            if (strncmp(optarg, "key=", strlen("key=")) == 0 ) {
+                my_ssl_key_file=optarg+strlen("key=");
+            }
+            break;
+#endif /* USE_SSL */
+
         default:
             syslog(LOG_ERR, "unknown option -%c ignored", optopt);
             break;
         }
     }
+#ifdef USE_SSL
+        /* make sure we have access to the required certificate
+        * and key files now ... before we perhaps chroot and 
+        * do the other "muck" for anon-ftp style setup ... though
+        * why we want to run SSL for anon I don't know
+        */
+
+        {
+            int i;
+           FILE *fp;
+            char *filename;
+
+            /* if we are not running in debug then any error
+             * stuff from SSL debug *must* not go down
+             * the socket (which 0,1,2 are all pointing to by
+             * default)
+             */
+#ifdef SSLEAY8
+            if (ssl_debug_flag) {
+               (void)freopen("ftpd.err","w",stderr);
+               bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
+               bio_log=BIO_new_file("ftpd.log","a");
+            } else {
+               bio_err=BIO_new(BIO_s_null());
+               bio_log=BIO_new(BIO_s_null());
+            }
+            BIO_printf(bio_err,"SSL_ERR started\n");
+            BIO_printf(bio_log,"SSL_LOG started\n");
+#else
+            if (ssl_debug_flag) {
+               (void)freopen("ftpd.err","w",stderr);
+               SSL_ERR=stderr;
+               SSL_LOG=NULL;
+                SSL_debug("ftpd.log");
+               if (SSL_LOG==NULL) {
+                   SSL_LOG=fopen("ftpd.log","w");
+                   if (SSL_LOG==NULL)
+                       SSL_LOG=stderr;
+               }
+               if (SSL_LOG!=NULL) {
+                   fprintf(SSL_LOG,"SSL_LOG started\n");
+                   fflush(SSL_LOG);
+               }
+               if (SSL_ERR!=NULL) {
+                   fprintf(SSL_ERR,"SSL_ERR started\n");
+                   fflush(SSL_ERR);
+               }
+            } else {
+                /* disable all the debug and trace */
+               SSL_LOG=SSL_ERR=NULL; /**/
+            }
+#endif
+
+           SSL_load_error_strings();
+#ifdef SSLEAY8
+           SSLeay_add_ssl_algorithms();
+#endif
+
+#ifdef SSLEAY8
+           ssl_ctx=SSL_CTX_new(SSLv23_server_method());
+#else
+           ssl_ctx=SSL_CTX_new();
+#endif
+
+           /* I really should syslog any of the following
+            * errors but I haven't bothered at this stage
+            * as that can wait
+            */
+#ifdef SSLEAY8
+            if (!SSL_CTX_set_default_verify_paths(ssl_ctx)) {
+               fprintf(stderr,"ftpd: cannot set default path via SSL_CTX_set_default_verify_paths\n");
+#else
+            if (!X509_set_default_verify_paths(ssl_ctx->cert)) {
+               fprintf(stderr,"ftpd: cannot set default path via X509_set_default_verify_paths\n");
+#endif
+               fflush(stderr);
+               sleep(1);
+               exit(1);
+            }
+
+#if 0
+            sprintf(ssl_file_path,"%s/%s",X509_get_default_cert_dir(),
+                        "ftpd.cert");
+#endif
+
+            sprintf(ssl_file_path,"%s/%s",X509_get_default_cert_dir(),
+                        "ftpd.pem");
+
+           filename=my_ssl_cert_file==NULL?ssl_file_path:my_ssl_cert_file;
+           fp=fopen(filename,"r");
+           if (fp==NULL) {
+               fprintf(stderr,"ftpd: cannot open public cert file \"%s\"\n",filename);
+               fflush(stderr);
+               exit(1);
+           }
+
+           ssl_public_cert=X509_new();
+           if (PEM_read_X509(fp,&ssl_public_cert,NULL)==NULL) {
+               fprintf(stderr,"ftpd: error reading public cert - %s\n",
+                                ERR_error_string(ERR_get_error(),NULL));
+               fflush(stderr);
+               exit(1);
+           }
+           fclose(fp);
+
+#ifdef SSLEAY8
+           BIO_printf(bio_log,"ftpd: got public cert\n");
+#else
+           if (ssl_debug_flag) {
+               fprintf(SSL_LOG,"ftpd: got public cert\n");
+               fflush(SSL_LOG);
+           }
+#endif
+
+#if 0
+            sprintf(ssl_file_path,"%s/private/%s",X509_get_default_cert_area(),
+                        "ftpd.key");
+#endif
+
+            sprintf(ssl_file_path,"%s/%s",X509_get_default_cert_dir(),
+                        "ftpd.pem");
+
+           filename=my_ssl_key_file==NULL?ssl_file_path:my_ssl_key_file;
+           fp=fopen(filename,"r");
+           if (fp==NULL) {
+               fprintf(stderr,"ftpd: cannot open private key file \"%s\"\n",filename);
+               fflush(stderr);
+               exit(1);
+           }
+
+           ssl_private_key=RSA_new();
+           if (PEM_read_RSAPrivateKey(fp,&ssl_private_key,NULL)==0) {
+               fprintf(stderr,"ftpd: error reading private key - %s\n",
+                       ERR_error_string(ERR_get_error(),NULL));
+               fflush(stderr);
+               exit(1);
+           }
+           fclose(fp);
+
+#ifdef SSLEAY8
+           BIO_printf(bio_log,"ftpd: got private key\n");
+#else
+           if (ssl_debug_flag) {
+               fprintf(SSL_LOG,"ftpd: got private key\n");
+               fflush(SSL_LOG);
+           }
+#endif
+
+        }
+#endif /* USE_SSL */
     (void) freopen(_PATH_DEVNULL, "w", stderr);
 
     /* Checking for random signals ... */
@@ -1286,6 +1536,13 @@
 	if (use_accessfile)		/* see above.  _H*/
             acl_setfunctions();
 
+#ifdef  USE_SSL
+    if (pw && good_ssl_user(name)) {
+	askpasswd = 1;
+	ssl_auto_login = 1;
+	pass("xxx");
+    } else
+#endif /* USE_SSL */
 #ifdef	BSD_AUTH
     if ((cp = start_auth(auth, name, pw)) != NULL) {
 	char *s;
@@ -1469,7 +1726,11 @@
     else
         dolreplies = 1;
 /* ******** REGULAR/GUEST USER PASSWORD PROCESSING ********** */
-    if (!anonymous) {    /* "ftp" is only account allowed no password */
+    if (!anonymous
+#ifdef USE_SSL
+             && !ssl_auto_login
+#endif
+                  ) {    /* "ftp" is only account allowed no password */
         if (*passwd == '-')
             passwd++;
 #ifdef BSD_AUTH
@@ -2011,6 +2272,13 @@
 #else
     send_data(fin, dout, BUFSIZ);
 #endif
+#ifdef USE_SSL
+    if (ssl_data_active_flag && (ssl_data_con!=NULL)) {
+        SSL_free(ssl_data_con);
+        ssl_data_active_flag=0;
+        ssl_data_con=NULL;
+    }
+#endif /* USE_SSL */
     (void) fclose(dout);
 
   dolog:
@@ -2438,7 +2706,7 @@
 #ifdef _AIX42
 	(void) sprintf(sizebuf, " (%lld bytes)", size);
 #else
-	(void) sprintf(sizebuf, " (%d bytes)", size);
+	(void) sprintf(sizebuf, " (%ld bytes)", size);
 #endif
 #endif
     else
@@ -2472,9 +2740,9 @@
 #endif
             (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) {
 #else      
-        alarm(120);
+
         s = accept(pdata, (struct sockaddr *) &from, &fromlen);
-        alarm(0);
+
         if (s < 0) {
 #endif
             reply(425, "Can't open data connection.");
@@ -2500,8 +2768,73 @@
                 anonymous ? guestpw : pw->pw_name, remotehost, remoteaddr,
                 dataaddr, name, sizebuf);
         }
+#ifdef USE_SSL
+		/* time to negotiate SSL on the data connection ...
+		 * do this via SSL_accept (as we are still the server
+		 * even though things are started around the other way)
+		 * 
+		 * note: we really *must* make sure the session stuff
+		 *       is copied correctly as we cannot afford a full
+		 *       SSL negotiation for each data socket!
+		 */
+		/* TODO XXXX fill in the blanks :-)
+		 */
+		ssl_data_active_flag=0;
+		if (ssl_active_flag && ssl_encrypt_data) {
+		    /* do SSL */
+
+		    reply(150, "Opening %s mode SSL data connection for %s%s.",
+			 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+
+		    if (ssl_data_con!=NULL) {
+		      SSL_free(ssl_data_con);
+		      ssl_data_con=NULL;
+		    }
+		    ssl_data_con=(SSL *)SSL_new(ssl_ctx);
+
+		    /* copy session details ... */
+		    SSL_copy_session_id(ssl_data_con,ssl_con);
+
+		    /* for 0.5.2 - want to change the timeout value etc ... */
+
+		    SSL_set_fd(ssl_data_con,pdata);
+		    SSL_set_verify(ssl_data_con,ssl_verify_flag,NULL);
+
+		    /* if is "safe" to read ahead */
+		    /* SSL_set_read_ahead(ssl_data_con,1); /**/
+
+		    if (ssl_debug_flag)
+			BIO_printf(bio_err,"===>START SSL_accept on DATA\n");
+
+		    if (SSL_accept(ssl_data_con)<=0) {
+			static char errbuf[1024];
+
+			sprintf(errbuf,"ftpd: SSL_accept DATA error %s\n",
+				    ERR_error_string(ERR_get_error(),NULL));
+			perror_reply(425, errbuf);
+			/* abort time methinks ... */
+			fclose(file);
+			return NULL;
+		    } else {
+
+			if (ssl_debug_flag) {
+			    BIO_printf(bio_err,"[SSL DATA Cipher %s]\n",
+					    SSL_get_cipher(ssl_con));
+			}
+			ssl_data_active_flag=1;
+		    }
+
+		    if (ssl_debug_flag)
+			BIO_printf(bio_err,"===>DONE SSL_accept on DATA\n");
+
+		} else {
+		    reply(150, "Opening %s mode data connection for %s%s.",
+			type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+		}
+#else /* !USE_SSL */
         reply(150, "Opening %s mode data connection for %s%s.",
               type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+#endif /* USE_SSL */
         return (fdopen(pdata, mode));
     }
     if (data >= 0) {
@@ -2525,9 +2858,9 @@
         return (NULL);
     }
     data = fileno(file);
-    while (connect(data, (struct sockaddr *) &data_dest,
-                   sizeof(data_dest)) < 0) {
-        if ((errno == EADDRINUSE || errno == EINTR) && retry < swaitmax) {
+	while (connect(data, (struct sockaddr *)&data_dest,
+	    sizeof (data_dest)) < 0) {
+		if (errno == EADDRINUSE && retry < swaitmax) {
             sleep((unsigned) swaitint);
             retry += swaitint;
             continue;
@@ -2537,8 +2870,71 @@
         data = -1;
         return (NULL);
     }
+#ifdef USE_SSL
+        /* time to negotiate SSL on the data connection ...
+	 * do this via SSL_accept (as we are still the server
+	 * even though things are started around the other way)
+	 * 
+	 * note: we really *must* make sure the session stuff
+	 *       is copied correctly as we cannot afford a full
+	 *       SSL negotiation for each data socket!
+	 */
+	/* TODO XXXX fill in the blanks :-)
+	 */
+	ssl_data_active_flag=0;
+	if (ssl_active_flag && ssl_encrypt_data) {
+	    /* do SSL */
+
+	    reply(150, "Opening %s mode SSL data connection for %s%s.",
+		 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+
+	    if (ssl_data_con!=NULL) {
+	      SSL_free(ssl_data_con);
+	      ssl_data_con=NULL;
+	    }
+	    ssl_data_con=(SSL *)SSL_new(ssl_ctx);
+
+            /* copy session details ... */
+	    SSL_copy_session_id(ssl_data_con,ssl_con);
+
+	    /* for 0.5.2 - want to change the timeout value etc ... */
+
+	    SSL_set_fd(ssl_data_con,data);
+	    SSL_set_verify(ssl_data_con,ssl_verify_flag,NULL);
+
+	    /* if is "safe" to read ahead */
+            /* SSL_set_read_ahead(ssl_data_con,1); /**/
+
+	    if (ssl_debug_flag)
+		BIO_printf(bio_err,"===>START SSL_accept on DATA\n");
+
+	    if (SSL_accept(ssl_data_con)<=0) {
+                static char errbuf[1024];
+
+	        sprintf(errbuf,"ftpd: SSL_accept DATA error %s\n",
+			    ERR_error_string(ERR_get_error(),NULL));
+		perror_reply(425, errbuf);
+		/* abort time methinks ... */
+		fclose(file);
+		return NULL;
+	    } else {
+		if (ssl_debug_flag)
+		    BIO_printf(bio_err,"[SSL DATA Cipher %s]\n",
+			            SSL_get_cipher(ssl_con));
+		ssl_data_active_flag=1;
+	    }
+
+	    if (ssl_debug_flag) 
+		BIO_printf(bio_err,"===>DONE SSL_accept on DATA\n");
+
+	} else {
     reply(150, "Opening %s mode data connection for %s%s.",
           type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+	}
+#else /* !USE_SSL */
+	reply(150, "Opening %s mode data connection for %s%s.",
+	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+#endif /* USE_SSL */
     return (file);
 }
 
@@ -2582,12 +2978,12 @@
             if (c == '\n') {
                 if (ferror(outstr))
                     goto data_err;
-                (void) putc('\r', outstr);
+                (void) DATAPUTC('\r', outstr);
             }
-            (void) putc(c, outstr);
+            (void) DATAPUTC(c, outstr);
         }
 	alarm(0);
-        fflush(outstr);
+        DATAFLUSH(outstr);
         transflag = 0;
         if (ferror(instr))
             goto file_err;
@@ -2606,6 +3002,15 @@
         netfd = fileno(outstr);
         filefd = fileno(instr);
 	alarm((unsigned)timeout);
+#ifdef USE_SSL
+	if (ssl_data_active_flag) {
+	    while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
+		SSL_write(ssl_data_con, buf, cnt) == cnt) {
+		    alarm((unsigned)timeout);
+		    byte_count += cnt;
+		}
+	} else
+#endif /* USE_SSL */
         while ((cnt = read(filefd, buf, (u_int) blksize)) > 0 &&
                write(netfd, buf, cnt) == cnt){
 	  alarm((unsigned)timeout);
@@ -2680,6 +3085,15 @@
         netfd = fileno(instr);
         filefd = fileno(outstr);
 	alarm((unsigned)timeout);
+#ifdef USE_SSL
+	if (ssl_data_active_flag) {
+	    while ((cnt = SSL_read(ssl_data_con,buf,sizeof buf)) > 0 &&
+		   (write(fileno(outstr), buf, cnt) == cnt)) {
+		byte_count += cnt;
+		alarm((unsigned)timeout);
+	    }
+	} else 
+#endif /* !USE_SSL */
         while ((cnt = read(netfd, buf, BUFSIZ)) > 0 &&
                write(filefd, buf, cnt) == cnt){
             byte_count += cnt;
@@ -2702,7 +3116,7 @@
 
     case TYPE_A:
 	alarm((unsigned)timeout);
-        while ((c = getc(instr)) != EOF) {
+        while ((c = DATAGETC(instr)) != EOF) {
             if (++byte_count % 4096 == 0)
                alarm((unsigned)timeout);
             if (c == '\n')
@@ -2711,7 +3125,7 @@
                 if (ferror(outstr))
                     goto file_err;
 		alarm((unsigned)timeout);
-                if ((c = getc(instr)) != '\n') {
+                if ((c = DATAGETC(instr)) != '\n') {
                     (void) putc('\r', outstr);
                     if (c == EOF) /* null byte fix, noid@cyborg.larc.nasa.gov */
                         goto contin2;
@@ -2906,8 +3320,18 @@
    * the wrapped text to the client.
    */
 
+#ifdef USE_SSL
+  if (ssl_active_flag) {
+    SSL_write(ssl_con,buf,strlen(buf));
+    SSL_write(ssl_con,"\r\n",2);
+  } else {
+    printf("%s\r\n", buf); /* and send it to the client */
+    fflush(stdout);
+  }
+#else /* !USE_SSL */
   printf("%s\r\n", buf); /* and send it to the client */
   fflush(stdout);
+#endif /* USE_SSL */
 }
 
 void
@@ -3650,6 +4074,15 @@
                     goto globfree;
                 transflag++;
             }
+#ifdef USE_SSL
+	    if (ssl_data_active_flag) {
+                SSL_write(ssl_data_con, dirname, strlen(dirname));
+                if (type == TYPE_A)
+                    SSL_write(ssl_data_con, "\r\n", 2);
+                else
+                    SSL_write(ssl_data_con, "\n", 1);
+            } else
+#endif
             fprintf(dout, "%s%s\n", dirname,
                     type == TYPE_A ? "\r" : "");
             byte_count += strlen(dirname) + 1;
@@ -3693,12 +4126,31 @@
                     }
                     transflag++;
                 }
-                if (nbuf[0] == '.' && nbuf[1] == '/')
+                if (nbuf[0] == '.' && nbuf[1] == '/') {
+#ifdef USE_SSL
+                    if (ssl_data_active_flag) {
+                        SSL_write(ssl_data_con, &nbuf[2], strlen(&nbuf[2]));
+                        if (type == TYPE_A)
+                            SSL_write(ssl_data_con, "\r\n", 2);
+                        else
+                            SSL_write(ssl_data_con, "\n", 1);
+                    } else
+#endif
                     fprintf(dout, "%s%s\n", &nbuf[2],
                             type == TYPE_A ? "\r" : "");
+		} else {
+#ifdef USE_SSL
+                    if (ssl_data_active_flag) {
+                        SSL_write(ssl_data_con, nbuf, strlen(nbuf));
+                        if (type == TYPE_A)
+                            SSL_write(ssl_data_con, "\r\n", 2);
                 else
+                            SSL_write(ssl_data_con, "\n", 1);
+                    } else
+#endif
                     fprintf(dout, "%s%s\n", nbuf,
                             type == TYPE_A ? "\r" : "");
+                }
                 byte_count += strlen(nbuf) + 1;
             }
         }
@@ -3714,8 +4166,16 @@
         reply(226, "Transfer complete.");
 
     transflag = 0;
-    if (dout != NULL)
+    if (dout != NULL) {
+#ifdef USE_SSL
+        if (ssl_data_active_flag && (ssl_data_con!=NULL)) {
+            SSL_free(ssl_data_con);
+            ssl_data_active_flag=0;
+            ssl_data_con=NULL;
+        }
+#endif /* USE_SSL */
         (void) fclose(dout);
+    }
     data = -1;
     pdata = -1;
 globfree:
@@ -4032,3 +4492,253 @@
     return -1;
 }
 #endif /* ULTRIX_AUTH */
+
+#ifdef USE_SSL
+
+static int verify_callback();
+
+do_ssl_start()
+{
+    static char errstr[1024];
+
+#ifdef SSLEAY8
+    BIO_printf(bio_log,"do_ssl_start triggered\n");
+#else
+    if (ssl_debug_flag && (SSL_LOG!=NULL)) {
+       fprintf(SSL_LOG,"do_ssl_start triggered\n");
+       fflush(SSL_LOG);
+    }
+#endif
+
+    /* do the SSL stuff now ... before we play with pty's */
+    ssl_con=(SSL *)SSL_new(ssl_ctx);
+
+    /* we are working with stdin (inetd based) by default */
+    SSL_set_fd(ssl_con,0);
+
+    if (SSL_use_RSAPrivateKey(ssl_con,ssl_private_key)==0) {
+        sprintf(errstr,"ftpd: SSL_use_RSAPrivateKey %s",ERR_error_string(ERR_get_error(),NULL));
+       perror_reply(421, errstr);
+       dologout(1);
+    }
+
+    if (SSL_use_certificate(ssl_con,ssl_public_cert)==0) {
+        sprintf(errstr,"ftpd: SSL_use_certificate %s",ERR_error_string(ERR_get_error(),NULL));
+       perror_reply(421, errstr);
+       dologout(1);
+    }
+
+    SSL_set_verify(ssl_con,ssl_verify_flag,
+           ssl_certsok_flag ? verify_callback : NULL);
+
+    if (SSL_accept(ssl_con)<=0) {
+       sprintf(errstr,"ftpd: SSL_accept %s",ERR_error_string(ERR_get_error(),NULL));
+
+       perror_reply(421, errstr);
+       dologout(1);
+
+       SSL_free(ssl_con);
+       ssl_con=NULL;
+
+       /* we will probably want to know this sort of stuff ...
+        * at least for the moment I'd like to keep track of
+        * who is using SSL - later I will probably make this
+        * just a debug option and only log after the user has
+        * actually connected --tjh
+        */
+       if (logging)
+           syslog(LOG_NOTICE, "SSL FAILED WITH %s", remotehost);
+
+    } else {
+       ssl_active_flag=1;
+
+       if (logging)
+            if (auth_ssl_name)
+                syslog(LOG_NOTICE, "SSL SUCCEEDED WITH %s as %s", remotehost,
+                    auth_ssl_name);
+            else
+                syslog(LOG_NOTICE, "SSL SUCCEEDED WITH %s", remotehost);
+    }
+
+    /* ssl_fprintf calls require that this be null to test
+     * for being an ssl stream
+     */
+    if (!ssl_active_flag) {
+       if (ssl_con!=NULL)
+         SSL_free(ssl_con);
+       ssl_con=NULL;
+    }
+
+    return 0;
+
+}
+
+/* we really shouldn't have code like this! --tjh */
+int 
+ssl_getc(SSL *ssl_con)
+{
+    char onebyte;
+
+    if (SSL_read(ssl_con,&onebyte,1)!=1)
+      return -1;
+    else {
+#ifdef SSLEAY8
+       BIO_printf(bio_log,"ssl_getc: SSL_read %d (%c) ",
+			onebyte & 0xff,isprint(onebyte)?onebyte:'.');
+#else
+       if (ssl_debug_flag && (SSL_LOG!=NULL)) {
+           fprintf(SSL_LOG,"ssl_getc: SSL_read %d (%c) ",onebyte & 0xff,isprint(onebyte)?onebyte:'.');
+           fflush(SSL_LOG);
+       }
+#endif
+       return onebyte & 0xff;
+    }
+}
+
+
+/* got back to this an implemented some rather "simple" buffering */
+static char putc_buf[BUFSIZ];
+static int putc_buf_pos=0;
+
+int ssl_putc_flush(SSL *ssl_con)
+{
+    if (putc_buf_pos>0) {
+       if (SSL_write(ssl_con,putc_buf,putc_buf_pos)!=putc_buf_pos) {
+#ifdef SSLEAY8
+           BIO_printf(bio_log,"ssl_putc_flush: WRITE FAILED\n");
+#else
+           if (ssl_debug_flag && (SSL_LOG!=NULL)) {
+               fprintf(SSL_LOG,"ssl_putc_flush: WRITE FAILED\n");
+               fflush(SSL_LOG);
+           }
+#endif
+           putc_buf_pos=0;
+           return -1;
+       }
+    }
+    putc_buf_pos=0;
+    return 0;
+}
+
+int 
+ssl_putc(SSL *ssl_con,int oneint)
+{
+    char onebyte;
+
+    onebyte = oneint & 0xff;
+
+    /* make sure there is space */
+    if (putc_buf_pos>=BUFSIZ) 
+       if (ssl_putc_flush(ssl_con)!=0)
+         return EOF;
+    putc_buf[putc_buf_pos++]=onebyte;
+
+    return onebyte;
+}
+
+/* we really shouldn't have code like this! --tjh */
+int 
+old_ssl_putc(SSL *ssl_con,int oneint)
+{
+    char onebyte;
+
+    onebyte = oneint & 0xff;
+
+    if (SSL_write(ssl_con,&onebyte,1)!=1)
+      return -1;
+    else {
+#ifdef SSLEAY8
+       BIO_printf(bio_log,"ssl_putc: SSL_write %d (%c) ",
+                      onebyte & 0xff,isprint(onebyte)?onebyte:'.');
+#else
+       if (ssl_debug_flag && (SSL_LOG!=NULL)) {
+           fprintf(SSL_LOG,"ssl_putc: SSL_write %d (%c) ",onebyte & 0xff,isprint(onebyte)?onebyte:'.');
+           fflush(SSL_LOG);
+       }
+#endif
+       return onebyte & 0xff;
+    }
+}
+
+static int
+verify_callback(ok, xs, xi, depth, error, dummy)
+int ok;
+char *xs, *xi;
+int depth, error;
+{
+    /*
+     * If the verification fails, then don't remember the name.  However,
+     * if we don't require a certificate, then return success which will
+     * still allow us to set up an encrypted session.
+     *
+     */
+    if (!ok) {
+       /* If we can't verify the issuer, then don't accept the name. */
+    if (depth != 0 && auth_ssl_name) {
+               free(auth_ssl_name);
+               auth_ssl_name = 0;
+       }
+       return ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT ? 0 : 1;
+     }
+     if (depth == 0)
+       auth_ssl_name =
+#ifdef SSLEAY8
+           (char *)X509_NAME_oneline(X509_get_subject_name(xs),NULL,0);
+#else
+           (char *)X509_NAME_oneline(X509_get_subject_name(xs));
+#endif
+     return ok;
+}
+
+/* return true if this auth_ssl_name is authorized to use name. */
+int
+good_ssl_user(name)
+char *name;
+{
+   FILE *user_fp;
+   char buf[2048];
+
+   if (!auth_ssl_name)
+      return 0;
+   if (!ssl_certsok_flag)
+      return 0;        /* can't happen */
+   user_fp = fopen("/etc/ssl.users", "r");
+   if (!user_fp)
+      return 0;
+   while (fgets(buf, sizeof buf, user_fp)) {
+      char *cp;
+      char *n;
+
+      /* allow for comments in the file ... always nice
+       * to be able to add a little novel in files and
+       * also disable easily --tjh
+       */
+      if (buf[0]=='#')
+         continue;
+
+      if (cp = strchr(buf, '\n'))
+         *cp = '\0';
+      cp = strchr(buf, ':');
+      if (!cp)
+         continue;
+      *cp++ = '\0';
+      if (strcasecmp(cp, auth_ssl_name) == 0) {
+         n = buf;
+         while (n) {
+             cp = strchr(n, ',');
+             if (cp)
+                 *cp++ = '\0';
+             if (!strcmp(name, n)) {
+                 fclose(user_fp);
+                 return 1;
+             }
+             n = cp;
+         }
+      }
+   }
+   fclose(user_fp);
+   return 0;
+}
+
+#endif /* USE_SSL */
+
diff -urN ../wu-ftpd-2.4.2-beta-18-ssl/src/ssl_port.h src/ssl_port.h
--- ../wu-ftpd-2.4.2-beta-18-ssl/src/ssl_port.h	Thu Jan  1 03:00:00 1970
+++ src/ssl_port.h	Thu Dec 17 04:00:05 1998
@@ -0,0 +1,66 @@
+/* ssl_port.h    - standard porting things 
+ *
+ * Slightly modified by Eugene Crosser to work with ssleay 0.8
+ *
+ * The modifications to support SSLeay were done by Tim Hudson
+ * tjh@mincom.oz.au
+ *
+ * You can do whatever you like with these patches except pretend that
+ * you wrote them. 
+ *
+ * Email ssl-users-request@mincom.oz.au to get instructions on how to
+ * join the mailing list that discusses SSLeay and also these patches.
+ *
+ */
+
+#ifndef HEADER_SSL_PORT_H
+#define HEADER_SSL_PORT_H
+
+#ifdef USE_SSL
+
+#include "crypto.h"
+#include "ssl.h"
+
+#if SSLEAY_VERSION_NUMBER >= 0x0800
+#define SSLEAY8
+#endif
+
+#include <stdio.h>
+#include "x509.h"
+extern SSL *ssl_con;
+extern int ssl_debug_flag;
+extern int ssl_only_flag;
+extern int ssl_active_flag;
+extern int ssl_verify_flag;
+extern int ssl_secure_flag;
+
+extern char *my_ssl_cert_file;
+extern char *my_ssl_key_file;
+extern int ssl_certsok_flag;
+
+#define is_ssl_fd(X,Y)    ( (SSL_get_fd((X))==0) || \
+                            (SSL_get_fd((X))==1) || \
+			    (SSL_get_fd((X))==(Y)) \
+			  )
+
+#define is_ssl_fp(X,Y)    ( ( (SSL_get_fd((X))==0) && (fileno((Y))==0) ) || \
+                            ( (SSL_get_fd((X))==1) && (fileno((Y))==1) ) || \
+			    (SSL_get_fd((X))==fileno(Y)) \
+			  )
+
+#define GETC(X)           (ssl_active_flag && (((X)==stdin)||((X)==stdin)) ? ssl_getc(ssl_con) : getc((X)) )
+
+#define DATAGETC(X)       (ssl_data_active_flag && (fileno(X)==data) ? ssl_getc(ssl_data_con) : getc((X)) )
+#define DATAPUTC(X,Y)     (ssl_data_active_flag && (fileno(Y)==data) ? ssl_putc(ssl_data_con,(X)) : putc((X),(Y)) )
+#define DATAFLUSH(X)      (ssl_data_active_flag && (fileno(X)==data) ? ssl_putc_flush(ssl_data_con) : fflush((X)) )
+
+#else
+
+#define GETC(X)           getc((X))
+#define DATAGETC(X)       getc((X))
+#define DATAPUTC(X,Y)     putc((X),(Y))
+#define DATAFLUSH(X)      fflush((X))
+
+#endif /* USE_SSL */
+
+#endif /*  HEADER_SSL_PORT_H */
