mutt stable branch with some hacks
at master 203 lines 4.9 kB view raw
1/* 2 * Copyright (C) 2000 Manoj Kasichainula <manoj@io.com> 3 * Copyright (C) 2001,2005 Brendan Cully <brendan@kublai.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 */ 19 20#if HAVE_CONFIG_H 21# include "config.h" 22#endif 23 24#include "mutt.h" 25#include "mutt_socket.h" 26#include "mutt_tunnel.h" 27 28#include <netinet/in.h> 29#include <sys/types.h> 30#include <sys/socket.h> 31#include <sys/wait.h> 32#include <fcntl.h> 33#include <errno.h> 34 35/* -- data types -- */ 36typedef struct 37{ 38 pid_t pid; 39 int readfd; 40 int writefd; 41} TUNNEL_DATA; 42 43/* forward declarations */ 44static int tunnel_socket_open (CONNECTION*); 45static int tunnel_socket_close (CONNECTION*); 46static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len); 47static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len); 48static int tunnel_socket_poll (CONNECTION* conn); 49 50/* -- public functions -- */ 51int mutt_tunnel_socket_setup (CONNECTION *conn) 52{ 53 conn->conn_open = tunnel_socket_open; 54 conn->conn_close = tunnel_socket_close; 55 conn->conn_read = tunnel_socket_read; 56 conn->conn_write = tunnel_socket_write; 57 conn->conn_poll = tunnel_socket_poll; 58 59 return 0; 60} 61 62static int tunnel_socket_open (CONNECTION *conn) 63{ 64 TUNNEL_DATA* tunnel; 65 int pid; 66 int rc; 67 int pin[2], pout[2]; 68 int devnull; 69 70 tunnel = (TUNNEL_DATA*) safe_malloc (sizeof (TUNNEL_DATA)); 71 conn->sockdata = tunnel; 72 73 mutt_message (_("Connecting with \"%s\"..."), Tunnel); 74 75 if ((rc = pipe (pin)) == -1) 76 { 77 mutt_perror ("pipe"); 78 FREE (&conn->sockdata); 79 return -1; 80 } 81 if ((rc = pipe (pout)) == -1) 82 { 83 mutt_perror ("pipe"); 84 close (pin[0]); 85 close (pin[1]); 86 FREE (&conn->sockdata); 87 return -1; 88 } 89 90 mutt_block_signals_system (); 91 if ((pid = fork ()) == 0) 92 { 93 mutt_unblock_signals_system (0); 94 devnull = open ("/dev/null", O_RDWR); 95 if (devnull < 0 || 96 dup2 (pout[0], STDIN_FILENO) < 0 || 97 dup2 (pin[1], STDOUT_FILENO) < 0 || 98 dup2 (devnull, STDERR_FILENO) < 0) 99 _exit (127); 100 close (pin[0]); 101 close (pin[1]); 102 close (pout[0]); 103 close (pout[1]); 104 close (devnull); 105 106 /* Don't let the subprocess think it can use the controlling tty */ 107 setsid (); 108 109 execl (EXECSHELL, "sh", "-c", Tunnel, NULL); 110 _exit (127); 111 } 112 mutt_unblock_signals_system (1); 113 114 if (pid == -1) 115 { 116 mutt_perror ("fork"); 117 close (pin[0]); 118 close (pin[1]); 119 close (pout[0]); 120 close (pout[1]); 121 FREE (&conn->sockdata); 122 return -1; 123 } 124 if (close (pin[1]) < 0 || close (pout[0]) < 0) 125 mutt_perror ("close"); 126 127 fcntl (pin[0], F_SETFD, FD_CLOEXEC); 128 fcntl (pout[1], F_SETFD, FD_CLOEXEC); 129 130 tunnel->readfd = pin[0]; 131 tunnel->writefd = pout[1]; 132 tunnel->pid = pid; 133 134 conn->fd = 42; /* stupid hack */ 135 136 return 0; 137} 138 139static int tunnel_socket_close (CONNECTION* conn) 140{ 141 TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata; 142 int status; 143 144 close (tunnel->readfd); 145 close (tunnel->writefd); 146 waitpid (tunnel->pid, &status, 0); 147 if (!WIFEXITED(status) || WEXITSTATUS(status)) 148 { 149 mutt_error(_("Tunnel to %s returned error %d (%s)"), conn->account.host, 150 WEXITSTATUS(status), 151 NONULL(mutt_strsysexit(WEXITSTATUS(status)))); 152 mutt_sleep (2); 153 } 154 FREE (&conn->sockdata); 155 156 return 0; 157} 158 159static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len) 160{ 161 TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata; 162 int rc; 163 164 rc = read (tunnel->readfd, buf, len); 165 if (rc == -1) 166 { 167 mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host, 168 strerror (errno)); 169 mutt_sleep (1); 170 } 171 172 return rc; 173} 174 175static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len) 176{ 177 TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata; 178 int rc; 179 180 rc = write (tunnel->writefd, buf, len); 181 if (rc == -1) 182 { 183 mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host, 184 strerror (errno)); 185 mutt_sleep (1); 186 } 187 188 return rc; 189} 190 191static int tunnel_socket_poll (CONNECTION* conn) 192{ 193 TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata; 194 int ofd; 195 int rc; 196 197 ofd = conn->fd; 198 conn->fd = tunnel->readfd; 199 rc = raw_socket_poll (conn); 200 conn->fd = ofd; 201 202 return rc; 203}