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);
        }

Reply via email to