Re: sslio as a STARTTLS wrapper (was Re: sslio error description incomplete/wrong)

Scott Gifford <[email protected]>
Newsgroups gmane.comp.misc.pape.general
Message-ID <[email protected]>
Charlie Brady <[email protected]> writes:

[...]

> I'd like to do something very similar on the smtp port, with 
> smtpfront-qmail talking plain text smtp, until it sees a STARTTLS request.
> This should be possible with just a little co-operation between sslio and 
> smtpfront-qmail. If sslio leaves smtpfront-qmail with stdin and stdout 
> connected to the network socket, and doesn't itself read from or write to 
> the network, smtpfront-qmail should be able to talk plain text SMTP to the 
> network, right?

This seems like it should work.

[...]

> The main detail to flesh out is what form of IPC to use. Any suggestions? 
> Any serious flaws in my thinking?

A signal is the easiest way.  You'd essentially have:

    smtpd:
      process_starttls()
        kill(SIGUSR1,getppid());
        dup2(SSLIN_FILENO,STDIN_FILENO);
        dup2(SSLOUT_FILENO,STDOUT_FILENO);

and that would be the entire change to the newly TLS-enabled server.

One concern that one of stunnel's authors (Brian Hatch?) had was that
starting up a brand new SSL-handling program wasted processing power,
since a lot of SSL's work is initialization.  If we used a
tcpserver/tcpsvd replacement that natively understood SSL, it would
help with that concern.  The operation would essentially be:

    /* Running as root */
    initialize_ssl();
    while(accept())
      fork()
        child:
          fork()
            parent:
              chroot("/nothing");
              setgid("nobody");
              setuid("nobody");
              be_ssl_tunnel();
            child:
              setgid(g_option);
              setuid(u_option);
              exec(rest_of_args);

The child would use IPC to ask the parent to begin SSL, as in your
proposal.  Perhaps sslio can already do this; I haven't really looked
into it.

Another option I've considered is a standalone SSL daemon.  An
application that wanted TLS would connect to this daemon via a UNIX
socket and send the network file descriptors, then receive back the
decrypted ends of an SSL connection:

  smtpd:
    case STARTTLS:
      s = socket(...)
      connect(s, AF_UNIX, getenv(TLS_SOCKET),...)
      sendfd(s,STDIN_FILENO);
      sendfd(s,STDOUT_FILENO);
      newfd = recvfd(s);
      dup2(newfd, STDIN_FILENO);
      newfd = recvfd(s);
      dup2(newfd, STDIN_FILENO);

This lets a single SSL daemon handle multiple services, which saves
resources.  It's also the coolest of the solutions I've considered.

A third option I've used for a similar problem is to start up the TLS
proxy without executing the SMTP server.  As soon as we receive any
command besides STARTTLS, we exec the SMTP server and send the first
command on FD 3 then close it; the SMTP server reads from FD 3 until
EOF, then switches to STDIN.  If we receive STARTTLS, we start up an
encryption tunnel and then exec the SMTP server with the decrypted
ends of this.  This only works if STARTTLS is the first command, but
in practice it always is.  The advantage is that you don't have an SSL
server sitting around waiting for a signal; it just exits if it
doesn't see STARTTLS right awway.

My favorite of these is the tcpserver replacement that forks off an
SSL handler, which is activated by a signal.  This has a very clean
interface, and the persistent daemon design may be more efficient with
SSL handling than a new copy of sslio every time (though I'll admit I
don't exactly understand all of SSL's performance characteristics).

I could probably find some time to help with a project like that, or
at least to test it since the coding should be fairly minimal.

----ScottG.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.