BXA: As per US export laws, I am notifying you that I am exporting
open-source cryptographic software from the following URL:
http://deekoo.net/technocracy/yeempemp/openssl-0.9.6a-forking.tar.gz
The patch is also attached to this mail. This patch is intended for use
with the open source program YeempEMP, which does not contain any
cryptographic routines of its own. YeempEMP is published at
http://deekoo.net/technocracy/yeempemp/ .
Patch description:
Attached is a patch against OpenSSL 0.9.6a that:
- Lets s_server handle multiple simultaneous connections.
- adds a -subproc option to s_server so that it can run external apps
through the SSL tunnel.
- Makes s_client connect to the ip:port specified in the S_CLIENT_CONNECT
environment variable, so as not to display the destination for tunneled
connections in ps listings.
Known flaws: I think some unices allow processes to peek at each others'
environment variables, in which case the env var won't actually increase
privacy.
--
The preceding message does not necessarily reflect the opinions of
most major governments, deities, and corporations. However, it will as
soon as I finish reprogramming them.
diff -cr openssl-0.9.6a/apps/s_client.c openssl-0.9.6a-forking/apps/s_client.c
*** openssl-0.9.6a/apps/s_client.c Thu Apr 5 13:09:09 2001
--- openssl-0.9.6a-forking/apps/s_client.c Mon Apr 16 23:51:19 2001
***************
*** 182,187 ****
--- 182,188 ----
SSL_METHOD *meth=NULL;
BIO *sbio;
char *inrand=NULL;
+ char *connect_envvar=NULL;
#ifdef WINDOWS
struct timeval tv;
#endif
***************
*** 216,222 ****
#ifdef FIONBIO
c_nbio=0;
#endif
!
argc--;
argv++;
while (argc >= 1)
--- 217,227 ----
#ifdef FIONBIO
c_nbio=0;
#endif
! connect_envvar=getenv("S_CLIENT_CONNECT");
! if (connect_envvar)
! {
! extract_host_port(getenv("S_CLIENT_CONNECT"),&host,NULL,&port);
! }
argc--;
argv++;
while (argc >= 1)
diff -cr openssl-0.9.6a/apps/s_server.c openssl-0.9.6a-forking/apps/s_server.c
*** openssl-0.9.6a/apps/s_server.c Thu Apr 5 13:09:12 2001
--- openssl-0.9.6a-forking/apps/s_server.c Mon Apr 16 23:51:19 2001
***************
*** 60,67 ****
--- 60,71 ----
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+ #include <unistd.h>
+ #include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
+ #include <sys/wait.h>
+ #include <signal.h>
#ifdef NO_STDIO
#define APPS_WIN16
#endif
***************
*** 100,105 ****
--- 104,110 ----
#endif
static int sv_body(char *hostname, int s, unsigned char *context);
static int www_body(char *hostname, int s, unsigned char *context);
+ static int subproc_body(char *hostname, int s, unsigned char *context);
static void close_accept_socket(void );
static void sv_usage(void);
static int init_ssl_connection(SSL *s);
***************
*** 171,176 ****
--- 176,183 ----
int s_crlf=0;
static SSL_CTX *ctx=NULL;
static int www=0;
+ static char *g_subproc_short=NULL;
+ static char *g_subproc=NULL;
static BIO *bio_s_out=NULL;
static int s_debug=0;
***************
*** 244,249 ****
--- 251,257 ----
BIO_printf(bio_err," -www - Respond to a 'GET /' with a status
page\n");
BIO_printf(bio_err," -WWW - Respond to a 'GET /<path> HTTP/1.0' with
file ./<path>\n");
BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR,
LIST_SEPARATOR_CHAR);
+ BIO_printf(bio_err," -subproc - Full path to subproc to spawn.\n");
}
static int local_argc=0;
***************
*** 410,415 ****
--- 418,424 ----
int badop=0,bugs=0;
int ret=1;
int off=0;
+ int x;
int no_tmp_rsa=0,no_dhe=0,nocert=0;
int state=0;
SSL_METHOD *meth=NULL;
***************
*** 546,551 ****
--- 555,573 ----
{ no_tmp_rsa=1; }
else if (strcmp(*argv,"-no_dhe") == 0)
{ no_dhe=1; }
+ else if (strcmp(*argv,"-subproc") == 0)
+ {
+ if (--argc < 1) goto bad;
+ g_subproc = *(++argv);
+ x=strlen(g_subproc);
+ while ((x>0) && (g_subproc[x]!='/')) {
+ x--;
+ }
+ if (g_subproc[x]=='/') {
+ x++;
+ }
+ g_subproc_short = &g_subproc[x];
+ }
else if (strcmp(*argv,"-www") == 0)
{ www=1; }
else if (strcmp(*argv,"-WWW") == 0)
***************
*** 728,737 ****
SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
BIO_printf(bio_s_out,"ACCEPT\n");
! if (www)
! do_server(port,&accept_socket,www_body, context);
else
! do_server(port,&accept_socket,sv_body, context);
print_stats(bio_s_out,ctx);
ret=0;
end:
--- 750,761 ----
SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
BIO_printf(bio_s_out,"ACCEPT\n");
! if (g_subproc)
! do_server(port,&accept_socket, subproc_body, context);
! else if (www)
! do_server(port,&accept_socket, www_body, context);
else
! do_server(port,&accept_socket, sv_body, context);
print_stats(bio_s_out,ctx);
ret=0;
end:
***************
*** 1498,1503 ****
--- 1522,1882 ----
break;
}
end:
+ #if 1
+ /* make sure we re-use sessions */
+ SSL_set_shutdown(con,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
+ #else
+ /* This kills performance */
+ /* SSL_shutdown(con); A shutdown gets sent in the
+ * BIO_free_all(io) procession */
+ #endif
+
+ err:
+
+ if (ret >= 0)
+ BIO_printf(bio_s_out,"ACCEPT\n");
+
+ if (buf != NULL) OPENSSL_free(buf);
+ if (io != NULL) BIO_free_all(io);
+ /* if (ssl_bio != NULL) BIO_free(ssl_bio);*/
+ return(ret);
+ }
+
+ BIO *g_asyncpipe_bio;
+ int g_asyncpipe_fd;
+ char *g_asyncpipe_buf;
+ int g_asyncpipe_buflen;
+ void (*g_asyncpipe_oldhandler)(int);
+
+ void asyncpipe_handler(int sig)
+ {
+ fd_set selout;
+ struct timeval timeout;
+ int numread;
+ printf("Asyncpipe_handler\n");
+ FD_ZERO(&selout);
+ FD_SET(g_asyncpipe_fd,&selout);
+ timeout.tv_sec=0;
+ timeout.tv_usec=0;
+ while (select(g_asyncpipe_fd+1,&selout, NULL, NULL, &timeout)>0)
+ {
+ numread=read(g_asyncpipe_fd,&g_asyncpipe_buf[0],
+ g_asyncpipe_buflen-1);
+ BIO_write(g_asyncpipe_bio,g_asyncpipe_buf,numread);
+ FD_SET(g_asyncpipe_fd,&selout);
+ timeout.tv_sec=0;
+ timeout.tv_usec=0;
+ }
+ BIO_flush(g_asyncpipe_bio);
+ }
+
+ void setup_asyncpipe_handler(int fd, BIO *io, char *buf, int buflen)
+ {
+ struct sigaction act;
+ sigset_t set;
+ g_asyncpipe_fd=fd;
+ g_asyncpipe_bio=io;
+ g_asyncpipe_buf=buf;
+ g_asyncpipe_buflen=buflen;
+ g_asyncpipe_oldhandler=signal(SIGIO,asyncpipe_handler);
+ signal(SIGPOLL,asyncpipe_handler);
+ signal(SIGPIPE,asyncpipe_handler);
+ if (g_asyncpipe_oldhandler==SIG_ERR)
+ {
+ BIO_printf(bio_err,"Ack! Error setting signal hander.\n");
+ }
+ else {
+ if (fcntl(fd,F_SETOWN,getpid))
+ {
+ BIO_printf(bio_err,"fcntl error.\n");
+ }
+ if (fcntl(fd,F_SETFL,O_ASYNC))
+ {
+ BIO_printf(bio_err,"fcntl error.\n");
+ }
+ if (fcntl(fd,F_SETFL,O_NONBLOCK))
+ {
+ BIO_printf(bio_err,"fcntl error.\n");
+ }
+ }
+ sigemptyset(&set);
+ sigaddset(&set,SIGIO);
+ sigaddset(&set,SIGPOLL);
+ sigaddset(&set,SIGPIPE);
+ sigprocmask(SIG_UNBLOCK,&set,NULL);
+ }
+
+ void pipe_stdout(int fd, SSL *con, char *buf, int buflen)
+ {
+ fd_set selout;
+ struct timeval timeout;
+ int numread;
+
+ FD_ZERO(&selout);
+ FD_SET(fd,&selout);
+ timeout.tv_sec=0;
+ timeout.tv_usec=0;
+ while (select(fd+1,&selout, NULL, NULL, &timeout)>0)
+ {
+ numread=read(fd,&buf[0],bufsize-1);
+ printf("Numread: %d\n",numread);
+ SSL_write(con,buf,numread);
+ // BIO_printf(io,"%d read\n",numread);
+ FD_SET(fd,&selout);
+ }
+ // BIO_flush(io);
+ }
+
+ static int subproc_body(char *hostname, int s, unsigned char *context)
+ {
+ char *buf=NULL;
+ char *obuf=NULL;
+ int ret=1;
+ int i,k,l,blank;
+ SSL *con;
+ BIO *io,*ssl_bio,*sbio;
+ int pipein[2];
+ int pipeout[2];
+ fd_set readfds;
+ pid_t child;
+ int numread;
+ int width;
+ struct timeval timeout;
+
+ buf=OPENSSL_malloc(bufsize);
+ obuf=OPENSSL_malloc(bufsize);
+ if (buf == NULL) return(0);
+ io=BIO_new(BIO_f_buffer());
+ ssl_bio=BIO_new(BIO_f_ssl());
+ if ((io == NULL) || (ssl_bio == NULL)) goto err;
+
+ #ifdef FIONBIO
+ if (s_nbio)
+ {
+ unsigned long sl=1;
+
+ if (!s_quiet)
+ BIO_printf(bio_err,"turning on non blocking io\n");
+ if (BIO_socket_ioctl(s,FIONBIO,&sl) < 0)
+ ERR_print_errors(bio_err);
+ }
+ #endif
+
+ /* lets make the output buffer a reasonable size */
+ if (!BIO_set_write_buffer_size(io,bufsize)) goto err;
+
+ if ((con=SSL_new(ctx)) == NULL) goto err;
+ if(context) SSL_set_session_id_context(con, context,
+ strlen((char *)context));
+
+ sbio=BIO_new_socket(s,BIO_NOCLOSE);
+ if (s_nbio_test)
+ {
+ BIO *test;
+
+ test=BIO_new(BIO_f_nbio_test());
+ sbio=BIO_push(test,sbio);
+ }
+ SSL_set_bio(con,sbio,sbio);
+ SSL_set_accept_state(con);
+
+ /* SSL_set_fd(con,s); */
+ BIO_set_ssl(ssl_bio,con,BIO_CLOSE);
+ BIO_push(io,ssl_bio);
+ #ifdef CHARSET_EBCDIC
+ io = BIO_push(BIO_new(BIO_f_ebcdic_filter()),io);
+ #endif
+
+ if (s_debug)
+ {
+ con->debug=1;
+ BIO_set_callback(SSL_get_rbio(con),bio_dump_cb);
+ BIO_set_callback_arg(SSL_get_rbio(con),bio_s_out);
+ }
+
+ blank=0;
+
+ /* Make pipe */
+ if (pipe(&pipein[0])<0) {
+ perror("pipe()");
+ ret=1;
+ goto err;
+ }
+ if (pipe(&pipeout[0])<0) {
+ perror("pipe()");
+ ret=1;
+ goto err;
+ }
+ if (fcntl(pipeout[0],F_SETFL,O_NONBLOCK)) {
+ perror("fcntl failed.");
+ ret=1;
+ goto err;
+ }
+
+ /* Fork the subproc */
+ child = fork();
+ if (child==0) {
+ dup2(pipein[0],0);
+ if (dup2(pipeout[1],1)!=1)
+ {
+ printf("dup2 stdout failed.\n");
+ }
+ execl(g_subproc,g_subproc_short,NULL);
+ perror("exec()");
+ ret=1;
+ goto err;
+ } else if (child<0) {
+ perror("fork()");
+ ret=1;
+ goto err;
+ }
+ close(pipeout[1]);
+ close(pipein[0]);
+ /* Make async using signals */
+ BIO_flush(io);
+ setup_asyncpipe_handler(pipeout[0],io,obuf,bufsize);
+ if (s>pipeout[0]) {
+ width=s+1;
+ } else
+ {
+ width=pipeout[0]+1;
+ }
+
+ for (;;)
+ {
+ int read_from_pipe;
+ int read_from_sslcon;
+
+ read_from_pipe = 0;
+ read_from_sslcon = SSL_pending(con);
+
+ if (!read_from_sslcon)
+ {
+ FD_ZERO(&readfds);
+ FD_SET(pipeout[0],&readfds);
+ FD_SET(s,&readfds);
+ /* Note: under VMS with SOCKETSHR the second parameter is
+ * currently of type (int *) whereas under other systems
+ * it is (void *) if you don't have a cast it will choke
+ * the compiler: if you do have a cast then you can either
+ * go for (int *) or (void *).
+ */
+ i=select(width,(void *)&readfds,NULL,NULL,NULL);
+ if (i <= 0) continue;
+ if (FD_ISSET(pipeout[0],&readfds))
+ read_from_pipe = 1;
+ if (FD_ISSET(s,&readfds))
+ read_from_sslcon = 1;
+ }
+ if (read_from_pipe)
+ {
+ i=read(pipeout[0], buf, bufsize/2);
+ #ifdef CHARSET_EBCDIC
+ ebcdic2ascii(buf,buf,i);
+ #endif
+ l=k=0;
+ for (;;)
+ {
+ /* should do a select for the write */
+ #ifdef RENEG
+ { static count=0; if (++count == 100) { count=0; SSL_renegotiate(con); } }
+ #endif
+ k=SSL_write(con,&(buf[l]),(unsigned int)i);
+ switch (SSL_get_error(con,k))
+ {
+ case SSL_ERROR_NONE:
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ BIO_printf(bio_s_out,"Write BLOCK\n");
+ break;
+ case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SSL:
+ BIO_printf(bio_s_out,"ERROR\n");
+ ERR_print_errors(bio_err);
+ ret=1;
+ goto err;
+ /* break; */
+ case SSL_ERROR_ZERO_RETURN:
+ BIO_printf(bio_s_out,"DONE\n");
+ ret=1;
+ goto err;
+ }
+ l+=k;
+ i-=k;
+ if (i <= 0) break;
+ }
+ }
+ if (read_from_sslcon)
+ {
+ if (!SSL_is_init_finished(con))
+ {
+ i=init_ssl_connection(con);
+
+ if (i < 0)
+ {
+ ret=0;
+ goto err;
+ }
+ else if (i == 0)
+ {
+ ret=1;
+ goto err;
+ }
+ }
+ else
+ {
+ again:
+ i=SSL_read(con,(char *)buf,bufsize);
+ switch (SSL_get_error(con,i))
+ {
+ case SSL_ERROR_NONE:
+ #ifdef CHARSET_EBCDIC
+ ascii2ebcdic(buf,buf,i);
+ #endif
+ write(pipein[1],buf,
+ (unsigned int)i);
+ if (SSL_pending(con)) goto again;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ BIO_printf(bio_s_out,"Read BLOCK\n");
+ break;
+ case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SSL:
+ BIO_printf(bio_s_out,"ERROR\n");
+ ERR_print_errors(bio_err);
+ ret=1;
+ goto err;
+ case SSL_ERROR_ZERO_RETURN:
+ BIO_printf(bio_s_out,"DONE\n");
+ ret=1;
+ goto err;
+ }
+ }
+ }
+ }
+
+ for (;;)
+ {
+ i=(int)BIO_flush(io);
+ if (i <= 0)
+ {
+ if (!BIO_should_retry(io))
+ break;
+ }
+ else
+ break;
+ }
+ end:
+ close(pipein[0]);
+ close(pipein[1]);
+ close(pipeout[0]);
+ close(pipeout[1]);
+ kill(child,SIGTERM);
+ waitpid(-1,NULL,WNOHANG);
#if 1
/* make sure we re-use sessions */
SSL_set_shutdown(con,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
diff -cr openssl-0.9.6a/apps/s_socket.c openssl-0.9.6a-forking/apps/s_socket.c
*** openssl-0.9.6a/apps/s_socket.c Thu Apr 5 13:09:12 2001
--- openssl-0.9.6a-forking/apps/s_socket.c Mon Apr 16 23:52:23 2001
***************
*** 61,66 ****
--- 61,67 ----
#include <string.h>
#include <errno.h>
#include <signal.h>
+ #include <sys/wait.h>
/* With IPv6, it looks like Digital has mixed up the proper order of
recursive header file inclusion, resulting in the compiler complaining
***************
*** 227,232 ****
--- 228,234 ----
char *name;
int accept_socket;
int i;
+ int child;
if (!init_server(&accept_socket,port)) return(0);
***************
*** 242,254 ****
SHUTDOWN(accept_socket);
return(0);
}
! i=(*cb)(name,sock, context);
! if (name != NULL) OPENSSL_free(name);
! SHUTDOWN2(sock);
! if (i < 0)
! {
! SHUTDOWN2(accept_socket);
! return(i);
}
}
}
--- 244,263 ----
SHUTDOWN(accept_socket);
return(0);
}
! child=fork();
! if (child==0) {
! i=(*cb)(name,sock, context);
! if (name != NULL) OPENSSL_free(name);
! SHUTDOWN2(sock);
! if (i < 0)
! {
! SHUTDOWN2(accept_socket);
! return(i);
! }
! exit(0);
! }
! else {
! waitpid(-1,NULL,WNOHANG);
}
}
}
***************
*** 314,319 ****
--- 323,330 ----
struct hostent *h1,*h2;
static struct sockaddr_in from;
int len;
+ char ssl_peer_envstr[64];
+ int numprinted;
/* struct linger ling; */
if (!sock_init()) return(0);
***************
*** 358,363 ****
--- 369,375 ----
*/
if (host == NULL) goto end;
+
#ifndef BIT_FIELD_LIMITS
/* I should use WSAAsyncGetHostByName() under windows */
h1=gethostbyaddr((char *)&from.sin_addr.s_addr,
***************
*** 395,400 ****
--- 407,425 ----
}
}
end:
+ numprinted=snprintf(&ssl_peer_envstr[0], 48,
+ "%d.%d.%d.%d %d",
+ from.sin_addr.s_addr&0xFF,
+ (from.sin_addr.s_addr>>8)&0xFF,
+ (from.sin_addr.s_addr>>16)&0xFF,
+ from.sin_addr.s_addr>>24,
+ from.sin_port&0xFFFF);
+ if (setenv("SSL_PEER",&ssl_peer_envstr[0],1))
+ {
+ perror("setenv");
+ return(0);
+ }
+
*sock=ret;
return(1);
}