mutt stable branch with some hacks
at jcs 219 lines 5.2 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, time_t wait_secs); 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 execle (EXECSHELL, "sh", "-c", Tunnel, NULL, mutt_envlist ()); 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 do 165 { 166 rc = read (tunnel->readfd, buf, len); 167 } while (rc < 0 && errno == EINTR); 168 169 if (rc < 0) 170 { 171 mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host, 172 strerror (errno)); 173 mutt_sleep (1); 174 return -1; 175 } 176 177 return rc; 178} 179 180static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len) 181{ 182 TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata; 183 int rc; 184 size_t sent = 0; 185 186 do 187 { 188 do 189 { 190 rc = write (tunnel->writefd, buf + sent, len - sent); 191 } while (rc < 0 && errno == EINTR); 192 193 if (rc < 0) 194 { 195 mutt_error (_("Tunnel error talking to %s: %s"), conn->account.host, 196 strerror (errno)); 197 mutt_sleep (1); 198 return -1; 199 } 200 201 sent += rc; 202 } while (sent < len); 203 204 return sent; 205} 206 207static int tunnel_socket_poll (CONNECTION* conn, time_t wait_secs) 208{ 209 TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata; 210 int ofd; 211 int rc; 212 213 ofd = conn->fd; 214 conn->fd = tunnel->readfd; 215 rc = raw_socket_poll (conn, wait_secs); 216 conn->fd = ofd; 217 218 return rc; 219}