Follows an SSL enabling diff to wu-ftpd-2.4.2-beta-11 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 the diff below updates only Linux configuration. You will need to change config and makefile sutable for your platform by hand. Also note that the the diff incorporates a fix for dirp->dd_fd glitch occuring with recent Linux libc. I posted it to Academ Consulting, so they *may* incorporate it in future releases. 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 12 Nov 96. ==================== diff -urN wu-ftpd-2.4.2-beta-11/src/config/config.lnx wu-ftpd-2.4.2-beta-11+SSL/src/config/config.lnx --- wu-ftpd-2.4.2-beta-11/src/config/config.lnx Mon Apr 15 09:51:40 1996 +++ wu-ftpd-2.4.2-beta-11+SSL/src/config/config.lnx Tue Nov 12 02:41:08 1996 @@ -2,7 +2,9 @@ * Linux configuration file * $Id: config.lnx,v 1.7 1996/03/15 06:26:59 sob Exp $ */ +#define USE_SSL #undef BSD +#define HAVE_DIRFD #define HAVE_DIRENT #define HAVE_FLOCK #define HAVE_FTW @@ -17,7 +19,7 @@ #define OVERWRITE #undef REGEX #define SPT_TYPE SPT_REUSEARGV -#undef SHADOW_PASSWORD +#define SHADOW_PASSWORD #define UPLOAD #undef USG #define SVR4 diff -urN wu-ftpd-2.4.2-beta-11/src/ftpcmd.y wu-ftpd-2.4.2-beta-11+SSL/src/ftpcmd.y --- wu-ftpd-2.4.2-beta-11/src/ftpcmd.y Mon Apr 15 09:51:06 1996 +++ wu-ftpd-2.4.2-beta-11+SSL/src/ftpcmd.y Tue Nov 12 12:43:12 1996 @@ -1,4 +1,17 @@ /* + * The modifications to support SSLeay done by Eugene Crosser + * 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. * @@ -101,6 +114,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; @@ -126,8 +148,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 @@ -138,6 +160,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 @@ -168,12 +191,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); @@ -280,9 +315,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 @@ -667,6 +702,21 @@ 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"); @@ -761,85 +811,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; } @@ -968,6 +1018,7 @@ { "STOU", STOU, STR1, 1, " file-name" }, { "SIZE", SIZE, OSTR, 1, " path-name" }, { "MDTM", MDTM, OSTR, 1, " path-name" }, + { "AUTH", AUTH, STR1, 1, " auth-type" }, { NULL, 0, 0, 0, 0 } }; @@ -1028,21 +1079,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; @@ -1279,51 +1330,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-11/src/ftpd.c wu-ftpd-2.4.2-beta-11+SSL/src/ftpd.c --- wu-ftpd-2.4.2-beta-11/src/ftpd.c Mon Apr 15 09:51:11 1996 +++ wu-ftpd-2.4.2-beta-11+SSL/src/ftpd.c Tue Nov 12 12:47:08 1996 @@ -1,3 +1,16 @@ +/* + * The modifications to support SSLeay done by Eugene Crosser + * 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. * @@ -80,6 +93,61 @@ #include #include +#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 * @@ -489,6 +557,32 @@ goto nextopt; } +#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: fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n", *cp); @@ -497,6 +591,126 @@ nextopt: argc--, argv++; } +#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 ... */ @@ -1123,6 +1337,13 @@ reply (331, "[%s] required for %s.", chbuff, name); else #endif +#ifdef USE_SSL + if (pw && good_ssl_user(name)) { + askpasswd = 1; + ssl_auto_login = 1; + pass("xxx"); + } else +#endif /* USE_SSL */ reply(331, "Password required for %s.", name); askpasswd = 1; /* Delay before reading passwd after first failed attempt to slow down @@ -1257,7 +1478,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 SHADOW_PASSWORD @@ -1759,6 +1984,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: @@ -2222,8 +2454,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); } @@ -2261,11 +2562,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; @@ -2283,6 +2584,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) @@ -2350,6 +2658,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; @@ -2366,14 +2683,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 == '\0' || c == EOF) goto contin2; @@ -2533,6 +2850,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); @@ -2540,6 +2861,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') { @@ -2552,16 +2898,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]; @@ -2585,16 +2947,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]; @@ -3320,8 +3701,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; } @@ -3579,3 +3968,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 */ + diff -urN wu-ftpd-2.4.2-beta-11/src/glob.c wu-ftpd-2.4.2-beta-11+SSL/src/glob.c --- wu-ftpd-2.4.2-beta-11/src/glob.c Mon Apr 15 09:51:11 1996 +++ wu-ftpd-2.4.2-beta-11+SSL/src/glob.c Tue Nov 12 01:46:45 1996 @@ -281,7 +281,11 @@ return; goto patherr2; } +#ifdef HAVE_DIRFD + if (fstat(dirfd(dirp), &stb) < 0) +#else /* HAVE_DIRFD */ if (fstat(dirp->dd_fd, &stb) < 0) +#endif /* HAVE_DIRFD */ goto patherr1; if (!isdir(stb)) { errno = ENOTDIR; diff -urN wu-ftpd-2.4.2-beta-11/src/makefiles/Makefile.lnx wu-ftpd-2.4.2-beta-11+SSL/src/makefiles/Makefile.lnx --- wu-ftpd-2.4.2-beta-11/src/makefiles/Makefile.lnx Fri Mar 15 09:26:49 1996 +++ wu-ftpd-2.4.2-beta-11+SSL/src/makefiles/Makefile.lnx Tue Nov 12 02:54:49 1996 @@ -6,10 +6,10 @@ # YACC = byacc # debian fix: YACC = bison -y -IFLAGS = -I.. -I../support -I/usr/include/bsd -LFLAGS = -L../support -s +IFLAGS = -I.. -I../support -I/usr/include/bsd -I/usr/local/ssl/include +LFLAGS = -L../support -L/usr/local/ssl/lib -s CFLAGS = -O2 -fomit-frame-pointer ${IFLAGS} ${LFLAGS} -LIBES = -lsupport -lbsd # -lshadow +LIBES = -lsupport -lbsd -lssl -lcrypto # -lshadow LIBC = /usr/lib/libc.a LINTFLAGS= LKERB = -lauth -lckrb -lkrb -ldes diff -urN wu-ftpd-2.4.2-beta-11/src/vers.c wu-ftpd-2.4.2-beta-11+SSL/src/vers.c --- wu-ftpd-2.4.2-beta-11/src/vers.c Thu Jan 1 03:00:00 1970 +++ wu-ftpd-2.4.2-beta-11+SSL/src/vers.c Tue Nov 12 12:36:09 1996 @@ -0,0 +1 @@ +char version[] = "Version wu-2.4.2-academ[BETA-11](11) Tue Nov 12 12:36:09 MSK 1996"; diff -urN wu-ftpd-2.4.2-beta-11/ssl_port.h wu-ftpd-2.4.2-beta-11+SSL/ssl_port.h --- wu-ftpd-2.4.2-beta-11/ssl_port.h Thu Jan 1 03:00:00 1970 +++ wu-ftpd-2.4.2-beta-11+SSL/ssl_port.h Tue Nov 12 02:46:14 1996 @@ -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 +#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 */ =========================