Follows an SSL enabling diff to wu-ftpd-2.4.2-beta-13 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.  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.

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

SSL will not work on systems without vsprintf().  If you have such
system and really need wu-ftpd+SSL, tell me, I'll fix this.

Eugene Crosser <crosser@average.org> 2 Apr 97.

=================
--- src/ftpcmd.y.orig	Mon Mar  3 12:39:54 1997
+++ src/ftpcmd.y	Wed Apr  2 17:38:21 1997
@@ -1,4 +1,17 @@
 /*
+ * The modifications to support SSLeay done by Eugene Crosser
+ * <crosser@average.org> 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.
  *
@@ -100,6 +113,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  int cmd_type;
 static  int cmd_form;
@@ -125,8 +147,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
 
@@ -137,6 +159,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
@@ -167,12 +190,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);
@@ -278,9 +313,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
@@ -685,6 +720,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");
@@ -779,85 +829,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;
     }
@@ -986,6 +1036,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 }
 };
 
@@ -1051,21 +1102,21 @@
         if (c == 0)
             tmpline[0] = '\0';
     }
-    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;
@@ -1311,51 +1362,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;
--- src/ftpd.c.orig	Mon Mar  3 12:39:56 1997
+++ src/ftpd.c	Wed Apr  2 18:34:10 1997
@@ -1,3 +1,16 @@
+/*
+ * The modifications to support SSLeay done by Eugene Crosser
+ * <crosser@average.org> 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.
  *
@@ -84,6 +97,61 @@
 #include <errno.h>
 #include <string.h>
 
+#ifdef USE_SSL
+
+#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;
+SSL *ssl_data_con;
+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;
+int ssl_auto_login=0;
+
+static char *auth_ssl_name=NULL;
+
+
+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;
+
+#include "ssl_port.h"
+
+void
+#ifdef __STDC__
+pass(char *passwd);
+#else
+pass();
+#endif
+
+#else /* !USE_SSL */
+#define DATAGETC getc
+#define DATAPUTC putc
+#define DATAFLUSH fflush
+#endif /* USE_SSL */
+
 /*
  *  Arrange to use either varargs or stdargs
  *
@@ -508,11 +576,157 @@
             syslog(LOG_ERR, "option -%c requires an argument", optopt);
             break;
 
+#ifdef USE_SSL
+        case 'z':
+            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)
+             */
+            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;
+               }
+            } else {
+                /* disable all the debug and trace */
+               SSL_LOG=SSL_ERR=NULL; /**/
+            }
+
+           if (ssl_debug_flag) {
+               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);
+               }
+           }
+
+           SSL_load_error_strings();
+
+           ssl_ctx=SSL_CTX_new();
+
+           /* I really should syslog any of the following
+            * errors but I haven't bothered at this stage
+            * as that can wait
+            */
+            if (!X509_set_default_verify_paths(ssl_ctx->cert)) {
+               fprintf(stderr,"ftpd: cannot set default path via X509_set_default_verify_paths\n");
+               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);
+
+           if (ssl_debug_flag) {
+               fprintf(SSL_LOG,"ftpd: got public cert\n");
+               fflush(SSL_LOG);
+           }
+
+#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);
+
+           if (ssl_debug_flag) {
+               fprintf(SSL_LOG,"ftpd: got private key\n");
+               fflush(SSL_LOG);
+           }
+
+        }
+#endif /* USE_SSL */
     (void) freopen(_PATH_DEVNULL, "w", stderr);
 
     /* Checking for random signals ... */
@@ -1251,13 +1465,22 @@
 	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 SKEY
-    pwok = skeyaccess(name, NULL, remotehost, remoteaddr);
-    reply(331, "%s", skey_challenge(name, pw, pwok));
+        pwok = skeyaccess(name, NULL, remotehost, remoteaddr);
+        reply(331, "%s", skey_challenge(name, pw, pwok));
 #else
-    reply(331, "Password required for %s.", name);
+        reply(331, "Password required for %s.", name);
 #endif
-    askpasswd = 1;
+        askpasswd = 1;
+    }
     /* Delay before reading passwd after first failed attempt to slow down
      * passwd-guessing programs. */
     if (login_attempts)
@@ -1391,7 +1614,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++;
         *guestpw = '\0';
@@ -1890,6 +2117,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:
@@ -2364,8 +2598,77 @@
         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 && (SSL_LOG!=NULL)) {
+       fprintf(SSL_LOG,"===>START SSL_accept on DATA\n");
+       fflush(SSL_LOG);
+        }
+
+        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 && (SSL_LOG!=NULL)) {
+           fprintf(SSL_LOG,"[SSL DATA Cipher %s]\n",
+                           SSL_get_cipher(ssl_con));
+           fflush(SSL_LOG);
+       }
+       ssl_data_active_flag=1;
+        }
+
+        if (ssl_debug_flag && (SSL_LOG!=NULL)) {
+       fprintf(SSL_LOG,"===>DONE SSL_accept on DATA\n");
+       fflush(SSL_LOG);
+        }
+
+    } 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);
 }
 
@@ -2403,11 +2706,11 @@
             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);
         }
-        fflush(outstr);
+        DATAFLUSH(outstr);
         transflag = 0;
         if (ferror(instr))
             goto file_err;
@@ -2425,6 +2728,13 @@
         }
         netfd = fileno(outstr);
         filefd = fileno(instr);
+#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)
+                    byte_count += cnt;
+        } else
+#endif /* USE_SSL */
 /* Debian fix: this seems gratuitous somehow, testing ... XXX: */
 #ifdef bogus__linux__
 	while ((cnt = read(filefd, buf, (u_int)blksize)) > 0)
@@ -2492,6 +2802,15 @@
 
     case TYPE_I:
     case TYPE_L:
+#ifdef USE_SSL
+        if (ssl_data_active_flag) {
+            while ((cnt = SSL_read(ssl_data_con,buf,sizeof buf)) > 0) {
+                if (write(fileno(outstr), buf, cnt) != cnt)
+                    goto file_err;
+                byte_count += cnt;
+            }
+        } else 
+#endif /* !USE_SSL */
         while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
             if (write(fileno(outstr), buf, cnt) != cnt)
                 goto file_err;
@@ -2508,14 +2827,14 @@
         return (-1);
 
     case TYPE_A:
-        while ((c = getc(instr)) != EOF) {
+        while ((c = DATAGETC(instr)) != EOF) {
             byte_count++;
             if (c == '\n')
                 bare_lfs++;
             while (c == '\r') {
                 if (ferror(outstr))
                     goto data_err;
-                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;
@@ -2675,6 +2994,10 @@
      va_dcl
 #endif
 {
+#ifdef USE_SSL
+    char outputbuf[2048];        /* allow for a 2k command string */
+    int outptr;
+#endif /* USE_SSL */
     VA_LOCAL_DECL
     
     VA_START(fmt); 
@@ -2682,6 +3005,31 @@
     if (autospout != NULL) {
         char *ptr = autospout;
 
+#ifdef USE_SSL
+        sprintf(outputbuf,"%d-", n);
+        outptr=strlen(outputbuf);
+        while (*ptr && (outptr < sizeof(outputbuf)-5)) {
+            if (*ptr == '\n') {
+                strcat(outputbuf+outptr,"\r\n");
+                outptr+=2;
+                if (*(++ptr))
+                    sprintf(outputbuf+outptr,"%03d-", n);
+                    outptr+=4;
+            } else {
+                outputbuf[outptr++] = *ptr++;
+            }
+        }
+        if (*(--ptr) != '\n') {
+            strcat(outputbuf+outptr,"\r\n");
+            outptr+=2;
+        }
+        if (ssl_active_flag) {
+            SSL_write(ssl_con,outputbuf,outptr);
+        } else {
+            fprintf(stdout,"%s",outputbuf);
+            fflush(stdout);
+        }
+#else /* !USE_SSL */
         printf("%d-", n);
         while (*ptr) {
             if (*ptr == '\n') {
@@ -2694,16 +3042,32 @@
         }
         if (*(--ptr) != '\n')
             printf("\r\n");
+#endif /* USE_SSL */
         if (autospout_free) {
             (void) free(autospout);
             autospout_free = 0;
         }
         autospout = 0;
     }
+#ifdef USE_SSL
+    sprintf(outputbuf, "%d ", n);
+    outptr=strlen(outputbuf);
+    vsprintf(outputbuf+outptr, fmt, ap);
+    outptr=strlen(outputbuf);
+    strcat(outputbuf+outptr,"\r\n");
+    outptr+=2;
+    if (ssl_active_flag) {
+        SSL_write(ssl_con,outputbuf,outptr);
+    } else {
+        fprintf(stdout,"%s",outputbuf);
+        fflush(stdout);
+    }
+#else /* !USE_SSL */
     printf("%d ", n);
     vprintf(fmt, ap);
     printf("\r\n");
     (void) fflush(stdout);
+#endif /* USE_SSL */
 
     if (debug) {
         char buf[BUFSIZ];
@@ -2727,16 +3091,35 @@
      va_dcl
 #endif
 {
+#ifdef USE_SSL
+    char outputbuf[2048];        /* allow for a 2k command string */
+    int outptr;
+#endif /* USE_SSL */
     VA_LOCAL_DECL
 
     VA_START(fmt);
 
     if (!dolreplies)
         return;
+#ifdef USE_SSL
+    sprintf(outputbuf, "%d-", n);
+    outptr=strlen(outputbuf);
+    vsprintf(outputbuf+outptr, fmt, ap);
+    outptr=strlen(outputbuf);
+    strcat(outputbuf+outptr,"\r\n");
+    outptr+=2;
+    if (ssl_active_flag) {
+        SSL_write(ssl_con,outputbuf,outptr);
+    } else {
+        fprintf(stdout,"%s",outputbuf);
+        fflush(stdout);
+    }
+#else /* !USE_SSL */
     printf("%d-", n);
     vprintf(fmt, ap);
     printf("\r\n");
     (void) fflush(stdout);
+#endif /* USE_SSL */
 
     if (debug) {
         char buf[BUFSIZ];
@@ -3429,7 +3812,7 @@
                     return;
                 transflag++;
             }
-            fprintf(dout, "%s%s\n", dirname,
+            FPRINTF(ssl_data_con,dout, "%s%s\n", dirname,
                     type == TYPE_A ? "\r" : "");
             byte_count += strlen(dirname) + 1;
             continue;
@@ -3473,10 +3856,10 @@
                     transflag++;
                 }
                 if (nbuf[0] == '.' && nbuf[1] == '/')
-                    fprintf(dout, "%s%s\n", &nbuf[2],
+                    FPRINTF(ssl_data_con,dout, "%s%s\n", &nbuf[2],
                             type == TYPE_A ? "\r" : "");
                 else
-                    fprintf(dout, "%s%s\n", nbuf,
+                    FPRINTF(ssl_data_con,dout, "%s%s\n", nbuf,
                             type == TYPE_A ? "\r" : "");
                 byte_count += strlen(nbuf) + 1;
             }
@@ -3492,8 +3875,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;
 }
@@ -3763,3 +4154,231 @@
     return -1;
 }
 #endif /* ULTRIX_AUTH */
+
+#ifdef USE_SSL
+
+static int verify_callback();
+
+do_ssl_start()
+{
+    static char errstr[1024];
+
+    if (ssl_debug_flag && (SSL_LOG!=NULL)) {
+       fprintf(SSL_LOG,"do_ssl_start triggered\n");
+       fflush(SSL_LOG);
+    }
+
+    /* 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 {
+       if (ssl_debug_flag && (SSL_LOG!=NULL)) {
+           fprintf(SSL_LOG,"ssl_getc: SSL_read %d (%c) ",onebyte & 0xff,isprint(onebyte)?onebyte:'.');
+           fflush(SSL_LOG);
+       }
+       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) {
+           if (ssl_debug_flag && (SSL_LOG!=NULL)) {
+               fprintf(SSL_LOG,"ssl_putc_flush: WRITE FAILED\n");
+               fflush(SSL_LOG);
+           }
+           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 {
+       if (ssl_debug_flag && (SSL_LOG!=NULL)) {
+           fprintf(SSL_LOG,"ssl_putc: SSL_write %d (%c) ",onebyte & 0xff,isprint(onebyte)?onebyte:'.');
+           fflush(SSL_LOG);
+       }
+       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 =
+           (char *)X509_NAME_oneline(X509_get_subject_name(xs));
+     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 */
+
--- ssl_port.h.orig	Wed Apr  2 17:38:22 1997
+++ ssl_port.h	Wed Apr  2 17:38:22 1997
@@ -0,0 +1,67 @@
+/* ssl_port.h    - standard porting things 
+ *
+ * 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 <stdio.h>
+#include "x509.h"
+#include "ssl.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)) \
+			  )
+
+extern int SSL_fprintf(SSL *ssl_con, FILE *fp, char *format, ... );
+
+/* this cute macro makes things much easier to handle ... */
+/* #define FPRINTF(A,X,Y,Z)    (ssl_active_flag && is_ssl_fp(ssl_con,(X))) ? SSL_fprintf(ssl_con,(Y),(Z)) : fprintf((X),(Y),(Z)) /**/
+/* #define FFLUSH(X)         (ssl_active_flag && is_ssl_fp(ssl_con,(X))) ? 1 : fflush((X)) /**/
+
+#define FPRINTF           SSL_fprintf
+#define FFLUSH(X)         (ssl_active_flag && (((X)==stdout)||((X)==stderr)) ? 1 : fflush((X)) )
+
+#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 */
