NeoMutt  2022-04-29-249-gaae397
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;
52};
53
57static 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
137static 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
159static 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
187static 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
204static 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;
237 conn->read = tunnel_socket_read;
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 = cs_subset_bool(NeoMutt->sub, "tunnel_is_secure");
243 if (c_tunnel_is_secure)
244 conn->ssf = 1;
245}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
char ** mutt_envlist_getlist(void)
Get the private environment.
Definition: envlist.c:169
#define EXEC_SHELL
Definition: filter.h:27
static int tunnel_socket_close(struct Connection *conn)
Close a tunnel socket - Implements Connection::close() -.
Definition: tunnel.c:204
static int tunnel_socket_open(struct Connection *conn)
Open a tunnel socket - Implements Connection::open() -.
Definition: tunnel.c:57
int raw_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block - Implements Connection::poll() -.
Definition: raw.c:324
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
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
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
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_perror(...)
Definition: logging.h:88
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:43
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
const char * mutt_str_sysexit(int err_num)
Return a string matching an error code.
Definition: string.c:166
GUI display the mailboxes in a side panel.
void mutt_sig_block_system(void)
Block signals before calling exec()
Definition: signal.c:183
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition: signal.c:207
Key value store.
#define NONULL(x)
Definition: string2.h:37
char host[128]
Server to login to.
Definition: connaccount.h:54
void * sockdata
Backend-specific socket data.
Definition: connection.h:56
int(* poll)(struct Connection *conn, time_t wait_secs)
Definition: connection.h:106
int(* write)(struct Connection *conn, const char *buf, size_t count)
Definition: connection.h:93
unsigned int ssf
Security strength factor, in bits (see notes)
Definition: connection.h:51
int(* close)(struct Connection *conn)
Definition: connection.h:117
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
int(* open)(struct Connection *conn)
Definition: connection.h:67
int fd
Socket file descriptor.
Definition: connection.h:54
int(* read)(struct Connection *conn, char *buf, size_t count)
Definition: connection.h:80
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
A network tunnel (pair of sockets)
Definition: tunnel.c:48
int fd_read
File descriptor to read from.
Definition: tunnel.c:50
pid_t pid
Process ID of tunnel program.
Definition: tunnel.c:49
int fd_write
File descriptor to write to.
Definition: tunnel.c:51
void mutt_tunnel_socket_setup(struct Connection *conn)
Sets up tunnel connection functions.
Definition: tunnel.c:233