mutt_socket.c | 9 ++- mutt_socket.h | 1 + mutt_tunnel.c | 133 +++++++++------------------------------------------------ mutt_tunnel.h | 3 +- 4 files changed, 30 insertions(+), 116 deletions(-)
# HG changeset patch # User Michael Elkins <[email protected]> # Date 1360876625 0 # Branch HEAD # Node ID 3882b5ebe3d25f695059d17761706a5d3d3b3e5f # Parent 3e22d65af90a022b1502c728264dd5915e172f4b Enable support for TLS over $tunnel connections Make $tunnel a special case of raw_socket_{open,close} rather than separate callbacks so that TLS support can be layered on top. The tls_socket_* calls are hardcoded to use raw_socket_*, which did not work with tunnels. Use UNIX domain sockets rather than pipes to communicate with the $tunnel child process. This yields a single, bi-directional file descriptor that has the same interface as a AF_INET socket. diff --git a/mutt_socket.c b/mutt_socket.c --- a/mutt_socket.c +++ b/mutt_socket.c @@ -286,9 +286,7 @@ conn->next = Connections; Connections = conn; - if (Tunnel && *Tunnel) - mutt_tunnel_socket_setup (conn); - else if (account->flags & M_ACCT_SSL) + if (account->flags & M_ACCT_SSL) { #if defined(USE_SSL) if (mutt_ssl_socket_setup (conn) < 0) @@ -391,7 +389,7 @@ int raw_socket_close (CONNECTION *conn) { - return close (conn->fd); + return conn->tunnel_pid ? tunnel_socket_close(conn) : close (conn->fd); } int raw_socket_read (CONNECTION* conn, char* buf, size_t len) @@ -443,6 +441,9 @@ char *host_idna = NULL; + if (Tunnel && *Tunnel) + return tunnel_socket_open(conn); + #ifdef HAVE_GETADDRINFO /* --- IPv4/6 --- */ diff --git a/mutt_socket.h b/mutt_socket.h --- a/mutt_socket.h +++ b/mutt_socket.h @@ -40,6 +40,7 @@ int fd; int available; + pid_t tunnel_pid; struct _connection *next; diff --git a/mutt_tunnel.c b/mutt_tunnel.c --- a/mutt_tunnel.c +++ b/mutt_tunnel.c @@ -22,7 +22,6 @@ #endif #include "mutt.h" -#include "mutt_socket.h" #include "mutt_tunnel.h" #include <netinet/in.h> @@ -32,53 +31,21 @@ #include <fcntl.h> #include <errno.h> -/* -- data types -- */ -typedef struct +int tunnel_socket_open (CONNECTION *conn) { + int fd[2]; pid_t pid; - int readfd; - int writefd; -} TUNNEL_DATA; - -/* forward declarations */ -static int tunnel_socket_open (CONNECTION*); -static int tunnel_socket_close (CONNECTION*); -static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len); -static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len); -static int tunnel_socket_poll (CONNECTION* conn); - -/* -- public functions -- */ -int mutt_tunnel_socket_setup (CONNECTION *conn) -{ - conn->conn_open = tunnel_socket_open; - conn->conn_close = tunnel_socket_close; - conn->conn_read = tunnel_socket_read; - conn->conn_write = tunnel_socket_write; - conn->conn_poll = tunnel_socket_poll; - - return 0; -} - -static int tunnel_socket_open (CONNECTION *conn) -{ - TUNNEL_DATA* tunnel; - int pid; - int rc; - int pin[2], pout[2]; - - tunnel = (TUNNEL_DATA*) safe_malloc (sizeof (TUNNEL_DATA)); - conn->sockdata = tunnel; mutt_message (_("Connecting with \"%s\"..."), Tunnel); - if ((rc = pipe (pin)) == -1) + /* + * Use a UNIX domain socket rather than a pair of pipes so that the higher + * level TLS code doesn't need to be concerned with separate file descriptors + * for reading and writing. + */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0) { - mutt_perror ("pipe"); - return -1; - } - if ((rc = pipe (pout)) == -1) - { - mutt_perror ("pipe"); + mutt_perror ("socketpair"); return -1; } @@ -86,12 +53,10 @@ if ((pid = fork ()) == 0) { mutt_unblock_signals_system (0); - if (dup2 (pout[0], STDIN_FILENO) < 0 || dup2 (pin[1], STDOUT_FILENO) < 0) + if (dup2 (fd[0], STDIN_FILENO) < 0 || dup2 (fd[0], STDOUT_FILENO) < 0) _exit (127); - close (pin[0]); - close (pin[1]); - close (pout[0]); - close (pout[1]); + close(fd[0]); + close(fd[1]); close (STDERR_FILENO); /* Don't let the subprocess think it can use the controlling tty */ @@ -102,38 +67,30 @@ } mutt_unblock_signals_system (1); + /* close the child half of the pair */ + close(fd[0]); + if (pid == -1) { - close (pin[0]); - close (pin[1]); - close (pout[0]); - close (pout[1]); + close(fd[1]); mutt_perror ("fork"); return -1; } - if (close (pin[1]) < 0 || close (pout[0]) < 0) - mutt_perror ("close"); - fcntl (pin[0], F_SETFD, FD_CLOEXEC); - fcntl (pout[1], F_SETFD, FD_CLOEXEC); + fcntl (fd[1], F_SETFD, FD_CLOEXEC); - tunnel->readfd = pin[0]; - tunnel->writefd = pout[1]; - tunnel->pid = pid; - - conn->fd = 42; /* stupid hack */ + conn->fd = fd[1]; + conn->tunnel_pid = pid; return 0; } -static int tunnel_socket_close (CONNECTION* conn) +int tunnel_socket_close (CONNECTION* conn) { - TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata; int status; - close (tunnel->readfd); - close (tunnel->writefd); - waitpid (tunnel->pid, &status, 0); + close(conn->fd); + waitpid (conn->tunnel_pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status)) { mutt_error(_("Tunnel to %s returned error %d (%s)"), conn->account.host, @@ -145,49 +102,3 @@ return 0; } - -static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len) -{ - TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata; - int rc; - - rc = read (tunnel->readfd, buf, len); - if (rc == -1) - { - mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host, - strerror (errno)); - mutt_sleep (1); - } - - return rc; -} - -static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len) -{ - TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata; - int rc; - - rc = write (tunnel->writefd, buf, len); - if (rc == -1) - { - mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host, - strerror (errno)); - mutt_sleep (1); - } - - return rc; -} - -static int tunnel_socket_poll (CONNECTION* conn) -{ - TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata; - int ofd; - int rc; - - ofd = conn->fd; - conn->fd = tunnel->readfd; - rc = raw_socket_poll (conn); - conn->fd = ofd; - - return rc; -} diff --git a/mutt_tunnel.h b/mutt_tunnel.h --- a/mutt_tunnel.h +++ b/mutt_tunnel.h @@ -19,6 +19,7 @@ #include "mutt_socket.h" -int mutt_tunnel_socket_setup (CONNECTION *); +int tunnel_socket_open (CONNECTION *); +int tunnel_socket_close (CONNECTION *); #endif /* _MUTT_TUNNEL_H_ */
