NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
tunnel.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdbool.h>
34 #include <string.h>
35 #include <sys/wait.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include "private.h"
39 #include "mutt/lib.h"
40 #include "config/lib.h"
41 #include "core/lib.h"
42 #include "lib.h"
43 
48 {
49  pid_t pid;
50  int fd_read;
51  int fd_write;
52 };
53 
57 static int tunnel_socket_open(struct Connection *conn)
58 {
59  int pin[2], pout[2];
60 
61  struct TunnelSockData *tunnel = mutt_mem_malloc(sizeof(struct TunnelSockData));
62  conn->sockdata = tunnel;
63 
64  const char *const c_tunnel = cs_subset_string(NeoMutt->sub, "tunnel");
65  mutt_message(_("Connecting with \"%s\"..."), c_tunnel);
66 
67  int rc = pipe(pin);
68  if (rc == -1)
69  {
70  mutt_perror("pipe");
71  FREE(&conn->sockdata);
72  return -1;
73  }
74  rc = pipe(pout);
75  if (rc == -1)
76  {
77  mutt_perror("pipe");
78  close(pin[0]);
79  close(pin[1]);
80  FREE(&conn->sockdata);
81  return -1;
82  }
83 
85  int pid = fork();
86  if (pid == 0)
87  {
89  const int fd_null = open("/dev/null", O_RDWR);
90  if ((fd_null < 0) || (dup2(pout[0], STDIN_FILENO) < 0) ||
91  (dup2(pin[1], STDOUT_FILENO) < 0) || (dup2(fd_null, STDERR_FILENO) < 0))
92  {
93  _exit(127);
94  }
95  close(pin[0]);
96  close(pin[1]);
97  close(pout[0]);
98  close(pout[1]);
99  close(fd_null);
100 
101  /* Don't let the subprocess think it can use the controlling tty */
102  setsid();
103 
104  execle(EXEC_SHELL, "sh", "-c", c_tunnel, NULL, mutt_envlist_getlist());
105  _exit(127);
106  }
108 
109  if (pid == -1)
110  {
111  mutt_perror("fork");
112  close(pin[0]);
113  close(pin[1]);
114  close(pout[0]);
115  close(pout[1]);
116  FREE(&conn->sockdata);
117  return -1;
118  }
119  if ((close(pin[1]) < 0) || (close(pout[0]) < 0))
120  mutt_perror("close");
121 
122  fcntl(pin[0], F_SETFD, FD_CLOEXEC);
123  fcntl(pout[1], F_SETFD, FD_CLOEXEC);
124 
125  tunnel->fd_read = pin[0];
126  tunnel->fd_write = pout[1];
127  tunnel->pid = pid;
128 
129  conn->fd = 42; /* stupid hack */
130 
131  return 0;
132 }
133 
137 static int tunnel_socket_read(struct Connection *conn, char *buf, size_t count)
138 {
139  struct TunnelSockData *tunnel = conn->sockdata;
140  int rc;
141 
142  do
143  {
144  rc = read(tunnel->fd_read, buf, count);
145  } while (rc < 0 && errno == EINTR);
146 
147  if (rc < 0)
148  {
149  mutt_error(_("Tunnel error talking to %s: %s"), conn->account.host, strerror(errno));
150  return -1;
151  }
152 
153  return rc;
154 }
155 
159 static int tunnel_socket_write(struct Connection *conn, const char *buf, size_t count)
160 {
161  struct TunnelSockData *tunnel = conn->sockdata;
162  int rc;
163  size_t sent = 0;
164 
165  do
166  {
167  do
168  {
169  rc = write(tunnel->fd_write, buf + sent, count - sent);
170  } while (rc < 0 && errno == EINTR);
171 
172  if (rc < 0)
173  {
174  mutt_error(_("Tunnel error talking to %s: %s"), conn->account.host, strerror(errno));
175  return -1;
176  }
177 
178  sent += rc;
179  } while (sent < count);
180 
181  return sent;
182 }
183 
187 static int tunnel_socket_poll(struct Connection *conn, time_t wait_secs)
188 {
189  struct TunnelSockData *tunnel = conn->sockdata;
190  int ofd;
191  int rc;
192 
193  ofd = conn->fd;
194  conn->fd = tunnel->fd_read;
195  rc = raw_socket_poll(conn, wait_secs);
196  conn->fd = ofd;
197 
198  return rc;
199 }
200 
204 static int tunnel_socket_close(struct Connection *conn)
205 {
206  struct TunnelSockData *tunnel = conn->sockdata;
207  if (!tunnel)
208  {
209  return 0;
210  }
211 
212  int status;
213 
214  close(tunnel->fd_read);
215  close(tunnel->fd_write);
216  waitpid(tunnel->pid, &status, 0);
217  if (!WIFEXITED(status) || WEXITSTATUS(status))
218  {
219  mutt_error(_("Tunnel to %s returned error %d (%s)"), conn->account.host,
220  WEXITSTATUS(status), NONULL(mutt_str_sysexit(WEXITSTATUS(status))));
221  }
222  FREE(&conn->sockdata);
223 
224  return 0;
225 }
226 
234 {
235  conn->open = tunnel_socket_open;
236  conn->close = tunnel_socket_close;
237  conn->read = tunnel_socket_read;
238  conn->write = tunnel_socket_write;
239  conn->poll = tunnel_socket_poll;
240  /* Note we are using ssf as a boolean in this case. See the notes in
241  * conn/connection.h */
242  const bool c_tunnel_is_secure =
243  cs_subset_bool(NeoMutt->sub, "tunnel_is_secure");
244  if (c_tunnel_is_secure)
245  conn->ssf = 1;
246 }
pid_t pid
Process ID of tunnel program.
Definition: tunnel.c:49
#define NONULL(x)
Definition: string2.h:37
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
unsigned int ssf
Security strength factor, in bits (see below)
Definition: connection.h:41
static int tunnel_socket_open(struct Connection *conn)
Open a tunnel socket - Implements Connection::open() -.
Definition: tunnel.c:57
#define mutt_error(...)
Definition: logging.h:88
int(* read)(struct Connection *conn, char *buf, size_t count)
Definition: connection.h:82
void mutt_sig_block_system(void)
Block signals before calling exec()
Definition: signal.c:183
int fd_read
File descriptor to read from.
Definition: tunnel.c:50
Shared functions that are private to Connections.
void * sockdata
Backend-specific socket data.
Definition: connection.h:46
#define _(a)
Definition: message.h:28
#define mutt_perror(...)
Definition: logging.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:36
#define EXEC_SHELL
Definition: filter.h:27
A network tunnel (pair of sockets)
Definition: tunnel.c:47
Convenience wrapper for the config headers.
static int tunnel_socket_write(struct Connection *conn, const char *buf, size_t count)
Write data to a tunnel socket - Implements Connection::write() -.
Definition: tunnel.c:159
int(* open)(struct Connection *conn)
Definition: connection.h:69
char host[128]
Server to login to.
Definition: connaccount.h:53
static int tunnel_socket_read(struct Connection *conn, char *buf, size_t count)
Read data from a tunnel socket - Implements Connection::read() -.
Definition: tunnel.c:137
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition: signal.c:207
Convenience wrapper for the core headers.
const char * mutt_str_sysexit(int err_num)
Return a string matching an error code.
Definition: string.c:112
int(* close)(struct Connection *conn)
Definition: connection.h:119
int fd
Socket file descriptor.
Definition: connection.h:44
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
static int tunnel_socket_close(struct Connection *conn)
Close a tunnel socket - Implements Connection::close() -.
Definition: tunnel.c:204
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
static int tunnel_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether tunnel reads would block - Implements Connection::poll() -.
Definition: tunnel.c:187
int fd_write
File descriptor to write to.
Definition: tunnel.c:51
int raw_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block - Implements Connection::poll() -.
Definition: raw.c:327
int(* poll)(struct Connection *conn, time_t wait_secs)
Definition: connection.h:108
int(* write)(struct Connection *conn, const char *buf, size_t count)
Definition: connection.h:95
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Convenience wrapper for the library headers.
void mutt_tunnel_socket_setup(struct Connection *conn)
sets up tunnel connection functions
Definition: tunnel.c:233
char ** mutt_envlist_getlist(void)
Get the private environment.
Definition: envlist.c:169