NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
tunnel.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <errno.h>
32#include <fcntl.h>
33#include <stdbool.h>
34#include <string.h>
35#include <sys/types.h>
36#include <sys/wait.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 "connaccount.h"
43#include "connection.h"
44
49{
50 pid_t pid;
51 int fd_read;
53};
54
58static int tunnel_socket_open(struct Connection *conn)
59{
60 int pin[2] = { 0 };
61 int pout[2] = { 0 };
62
63 struct TunnelSockData *tunnel = MUTT_MEM_MALLOC(1, struct TunnelSockData);
64 conn->sockdata = tunnel;
65
66 const char *const c_tunnel = cs_subset_string(NeoMutt->sub, "tunnel");
67 mutt_message(_("Connecting with \"%s\"..."), c_tunnel);
68
69 int rc = pipe(pin);
70 if (rc == -1)
71 {
72 mutt_perror("pipe");
73 FREE(&conn->sockdata);
74 return -1;
75 }
76 rc = pipe(pout);
77 if (rc == -1)
78 {
79 mutt_perror("pipe");
80 close(pin[0]);
81 close(pin[1]);
82 FREE(&conn->sockdata);
83 return -1;
84 }
85
87 int pid = fork();
88 if (pid == 0)
89 {
92 const int fd_null = open("/dev/null", O_RDWR);
93 if ((fd_null < 0) || (dup2(pout[0], STDIN_FILENO) < 0) ||
94 (dup2(pin[1], STDOUT_FILENO) < 0) || (dup2(fd_null, STDERR_FILENO) < 0))
95 {
96 _exit(127);
97 }
98 close(pin[0]);
99 close(pin[1]);
100 close(pout[0]);
101 close(pout[1]);
102 close(fd_null);
103
104 /* Don't let the subprocess think it can use the controlling tty */
105 setsid();
106
107 execle(EXEC_SHELL, "sh", "-c", c_tunnel, NULL, NeoMutt->env);
108 _exit(127);
109 }
111
112 if (pid == -1)
113 {
114 mutt_perror("fork");
115 close(pin[0]);
116 close(pin[1]);
117 close(pout[0]);
118 close(pout[1]);
119 FREE(&conn->sockdata);
120 return -1;
121 }
122 if ((close(pin[1]) < 0) || (close(pout[0]) < 0))
123 mutt_perror("close");
124
125 // These are unlikely to fail
126 (void) fcntl(pin[0], F_SETFD, FD_CLOEXEC);
127 (void) fcntl(pout[1], F_SETFD, FD_CLOEXEC);
128
129 tunnel->fd_read = pin[0];
130 tunnel->fd_write = pout[1];
131 tunnel->pid = pid;
132
133 conn->fd = 42; /* stupid hack */
134
135 /* Note we are using ssf as a boolean in this case. See the notes in
136 * conn/connection.h */
137 const bool c_tunnel_is_secure = cs_subset_bool(NeoMutt->sub, "tunnel_is_secure");
138 if (c_tunnel_is_secure)
139 conn->ssf = 1;
140
141 return 0;
142}
143
147static int tunnel_socket_read(struct Connection *conn, char *buf, size_t count)
148{
149 struct TunnelSockData *tunnel = conn->sockdata;
150 int rc;
151
152 do
153 {
154 rc = read(tunnel->fd_read, buf, count);
155 } while (rc < 0 && errno == EINTR);
156
157 if (rc < 0)
158 {
159 mutt_error(_("Tunnel error talking to %s: %s"), conn->account.host, strerror(errno));
160 return -1;
161 }
162
163 return rc;
164}
165
169static int tunnel_socket_write(struct Connection *conn, const char *buf, size_t count)
170{
171 struct TunnelSockData *tunnel = conn->sockdata;
172 ssize_t rc;
173 size_t sent = 0;
174
175 do
176 {
177 do
178 {
179 rc = write(tunnel->fd_write, buf + sent, count - sent);
180 } while (rc < 0 && errno == EINTR);
181
182 if (rc < 0)
183 {
184 mutt_error(_("Tunnel error talking to %s: %s"), conn->account.host, strerror(errno));
185 return -1;
186 }
187
188 sent += rc;
189 } while (sent < count);
190
191 return sent;
192}
193
197static int tunnel_socket_poll(struct Connection *conn, time_t wait_secs)
198{
199 struct TunnelSockData *tunnel = conn->sockdata;
200 int ofd;
201 int rc;
202
203 ofd = conn->fd;
204 conn->fd = tunnel->fd_read;
205 rc = raw_socket_poll(conn, wait_secs);
206 conn->fd = ofd;
207
208 return rc;
209}
210
214static int tunnel_socket_close(struct Connection *conn)
215{
216 struct TunnelSockData *tunnel = conn->sockdata;
217 if (!tunnel)
218 {
219 return 0;
220 }
221
222 int status = 0;
223
224 close(tunnel->fd_read);
225 close(tunnel->fd_write);
226 waitpid(tunnel->pid, &status, 0);
227 if (!WIFEXITED(status) || WEXITSTATUS(status))
228 {
229 mutt_error(_("Tunnel to %s returned error %d (%s)"), conn->account.host,
230 WEXITSTATUS(status), NONULL(mutt_str_sysexit(WEXITSTATUS(status))));
231 }
232 FREE(&conn->sockdata);
233
234 return 0;
235}
236
244{
245 conn->open = tunnel_socket_open;
247 conn->read = tunnel_socket_read;
249 conn->poll = tunnel_socket_poll;
250}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
Shared functions that are private to Connections.
Connection Credentials.
An open network connection (socket)
Convenience wrapper for the core headers.
static int tunnel_socket_close(struct Connection *conn)
Close a tunnel socket - Implements Connection::close() -.
Definition tunnel.c:214
static int tunnel_socket_open(struct Connection *conn)
Open a tunnel socket - Implements Connection::open() -.
Definition tunnel.c:58
int raw_socket_poll(struct Connection *conn, time_t wait_secs)
Check if any data is waiting on a socket - Implements Connection::poll() -.
Definition raw.c:354
static int tunnel_socket_poll(struct Connection *conn, time_t wait_secs)
Check if any data is waiting on a socket - Implements Connection::poll() -.
Definition tunnel.c:197
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:147
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:169
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_perror(...)
Definition logging2.h:95
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:53
#define EXEC_SHELL
Default shell to use for executing commands.
Definition filter.h:30
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:173
void mutt_sig_reset_child_signals(void)
Reset ignored signals back to the default.
Definition signal.c:336
void mutt_sig_block_system(void)
Block signals before calling exec()
Definition signal.c:260
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition signal.c:284
#define NONULL(x)
Definition string2.h:44
char host[128]
Server to login to.
Definition connaccount.h:60
void * sockdata
Backend-specific socket data.
Definition connection.h:55
int(* poll)(struct Connection *conn, time_t wait_secs)
Definition connection.h:105
int(* write)(struct Connection *conn, const char *buf, size_t count)
Definition connection.h:92
unsigned int ssf
Security strength factor, in bits (see notes)
Definition connection.h:50
int(* close)(struct Connection *conn)
Definition connection.h:116
struct ConnAccount account
Account details: username, password, etc.
Definition connection.h:49
int(* open)(struct Connection *conn)
Definition connection.h:66
int fd
Socket file descriptor.
Definition connection.h:53
int(* read)(struct Connection *conn, char *buf, size_t count)
Definition connection.h:79
Container for Accounts, Notifications.
Definition neomutt.h:41
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
A network tunnel (pair of sockets)
Definition tunnel.c:49
int fd_read
File descriptor to read from.
Definition tunnel.c:51
pid_t pid
Process ID of tunnel program.
Definition tunnel.c:50
int fd_write
File descriptor to write to.
Definition tunnel.c:52
void mutt_tunnel_socket_setup(struct Connection *conn)
Sets up tunnel connection functions.
Definition tunnel.c:243