#!/usr/bin/perl -T use warnings; use strict; use Errno qw/EINTR/; use Net::SSLeay qw/die_now/; use Socket qw/INADDR_LOOPBACK AF_INET SOCK_STREAM pack_sockaddr_in SOL_SOCKET SO_REUSEADDR SHUT_RDWR/; BEGIN { Net::SSLeay::load_error_strings(); Net::SSLeay::SSLeay_add_ssl_algorithms(); Net::SSLeay::randomize(); } socket(my $S, AF_INET, SOCK_STREAM, 0) or die; setsockopt($S, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die; bind($S, pack_sockaddr_in(10143, INADDR_LOOPBACK)) or die "bind: $!\n"; listen($S, 1) or die "listen: $!"; my $CONFDIR = $ENV{HOME} =~ /\A(\p{Print}+)\z/ ? "$1/.dovecot/conf.d" : die; my $CTX = Net::SSLeay::CTX_new() or die_now("SSL_CTX_new()"); Net::SSLeay::CTX_set_mode($CTX, Net::SSLeay::MODE_ENABLE_PARTIAL_WRITE() | Net::SSLeay::MODE_ACCEPT_MOVING_WRITE_BUFFER() | Net::SSLeay::MODE_AUTO_RETRY() | # don't fail SSL_read on renegotiation Net::SSLeay::MODE_RELEASE_BUFFERS() ); Net::SSLeay::CTX_use_PrivateKey_file($CTX, "$CONFDIR/dovecot.rsa.key", &Net::SSLeay::FILETYPE_PEM) or die_now("Can't load private key: $!"); Net::SSLeay::CTX_use_certificate_file($CTX, "$CONFDIR/dovecot.rsa.crt", &Net::SSLeay::FILETYPE_PEM) or die_now("Can't load certificate: $!"); while (1) { my $sockaddr = accept(my $conn, $S) or do { next if $! == EINTR; die "accept: $!"; }; $conn->printflush("* OK IMAP4rev1 Server\r\n"); $conn->getline() =~ /\A(\S+) CAPABILITY\r\n\z/ or die; $conn->printflush("* CAPABILITY IMAP4rev1 STARTTLS\r\n"); $conn->printflush("$1 OK CAPABILITY completed\r\n"); $conn->getline() =~ /\A(\S+) STARTTLS\r\n\z/ or die; # These responses preceed the TLS handshake hence are not authenticated! $conn->print("$1 OK Begin TLS\r\n"); $conn->print("* CAPABILITY IMAP4rev1 LOGINDISABLED X-injected\r\n"); # Note: tag format must match Net::IMAP::InterIMAP->_cmd_init() $conn->printf("%06d OK CAPABILITY injected\r\n", $1+1); $conn->flush(); my $ssl = Net::SSLeay::new($CTX) or die_now("SSL_new()"); die_now("SSL_set_fd()") unless Net::SSLeay::set_fd($ssl, $conn) == 1; die_now("SSL_accept()") unless Net::SSLeay::accept($ssl); Net::SSLeay::ssl_read_CRLF($ssl) =~ /\A(\S+) CAPABILITY\r\n\z/ or die_now("SSL_read()"); Net::SSLeay::ssl_write_CRLF($ssl, "* CAPABILITY IMAP4rev1 AUTH=LOGIN\r\n$1 OK CAPABILITY completed"); Net::SSLeay::ssl_read_CRLF($ssl) =~ /\A(\S+) LOGIN .*\r\n\z/ or die_now("SSL_read()"); Net::SSLeay::ssl_write_CRLF($ssl, "$1 OK [CAPABILITY IMAP4rev1] LOGIN completed"); Net::SSLeay::free($ssl); close($conn); last; } END { Net::SSLeay::CTX_free($CTX) if defined $CTX; if (defined $S) { shutdown($S, SHUT_RDWR) or warn "shutdown: $!"; close($S) or print STDERR "close: $!\n"; } }