NeoMutt  2023-11-03-85-g512e01
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 "connaccount.h"
43#include "connection.h"
44#include "globals.h"
45
50{
51 pid_t pid;
52 int fd_read;
54};
55
59static int tunnel_socket_open(struct Connection *conn)
60{
61 int pin[2], pout[2];
62
63 struct TunnelSockData *tunnel = mutt_mem_malloc(sizeof(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 {
91 const int fd_null = open("/dev/null", O_RDWR);
92 if ((fd_null < 0) || (dup2(pout[0], STDIN_FILENO) < 0) ||
93 (dup2(pin[1], STDOUT_FILENO) < 0) || (dup2(fd_null, STDERR_FILENO) < 0))
94 {
95 _exit(127);
96 }
97 close(pin[0]);
98 close(pin[1]);
99 close(pout[0]);
100 close(pout[1]);
101 close(fd_null);
102
103 /* Don't let the subprocess think it can use the controlling tty */
104 setsid();
105
106 execle(EXEC_SHELL, "sh", "-c", c_tunnel, NULL, EnvList);
107 _exit(127);
108 }
110
111 if (pid == -1)
112 {
113 mutt_perror("fork");
114 close(pin[0]);
115 close(pin[1]);
116 close(pout[0]);
117 close(pout[1]);
118 FREE(&conn->sockdata);
119 return -1;
120 }
121 if ((close(pin[1]) < 0) || (close(pout[0]) < 0))
122 mutt_perror("close");
123
124 fcntl(pin[0], F_SETFD, FD_CLOEXEC);
125 fcntl(pout[1], F_SETFD, FD_CLOEXEC);
126
127 tunnel->fd_read = pin[0];
128 tunnel->fd_write = pout[1];
129 tunnel->pid = pid;
130
131 conn->fd = 42; /* stupid hack */
132
133 /* Note we are using ssf as a boolean in this case. See the notes in
134 * conn/connection.h */
135 const bool c_tunnel_is_secure = cs_subset_bool(NeoMutt->sub, "tunnel_is_secure");
136 if (c_tunnel_is_secure)
137 conn->ssf = 1;
138
139 return 0;
140}
141
145static int tunnel_socket_read(struct Connection *conn, char *buf, size_t count)
146{
147 struct TunnelSockData *tunnel = conn->sockdata;
148 int rc;
149
150 do
151 {
152 rc = read(tunnel->fd_read, buf, count);
153 } while (rc < 0 && errno == EINTR);
154
155 if (rc < 0)
156 {
157 mutt_error(_("Tunnel error talking to %s: %s"), conn->account.host, strerror(errno));
158 return -1;
159 }
160
161 return rc;
162}
163
167static int tunnel_socket_write(struct Connection *conn, const char *buf, size_t count)
168{
169 struct TunnelSockData *tunnel = conn->sockdata;
170 int rc;
171 size_t sent = 0;
172
173 do
174 {
175 do
176 {
177 rc = write(tunnel->fd_write, buf + sent, count - sent);
178 } while (rc < 0 && errno == EINTR);
179
180 if (rc < 0)
181 {
182 mutt_error(_("Tunnel error talking to %s: %s"), conn->account.host, strerror(errno));
183 return -1;
184 }
185
186 sent += rc;
187 } while (sent < count);
188
189 return sent;
190}
191
195static int tunnel_socket_poll(struct Connection *conn, time_t wait_secs)
196{
197 struct TunnelSockData *tunnel = conn->sockdata;
198 int ofd;
199 int rc;
200
201 ofd = conn->fd;
202 conn->fd = tunnel->fd_read;
203 rc = raw_socket_poll(conn, wait_secs);
204 conn->fd = ofd;
205
206 return rc;
207}
208
212static int tunnel_socket_close(struct Connection *conn)
213{
214 struct TunnelSockData *tunnel = conn->sockdata;
215 if (!tunnel)
216 {
217 return 0;
218 }
219
220 int status;
221
222 close(tunnel->fd_read);
223 close(tunnel->fd_write);
224 waitpid(tunnel->pid, &status, 0);
225 if (!WIFEXITED(status) || WEXITSTATUS(status))
226 {
227 mutt_error(_("Tunnel to %s returned error %d (%s)"), conn->account.host,
228 WEXITSTATUS(status), NONULL(mutt_str_sysexit(WEXITSTATUS(status))));
229 }
230 FREE(&conn->sockdata);
231
232 return 0;
233}
234
242{
243 conn->open = tunnel_socket_open;
245 conn->read = tunnel_socket_read;
247 conn->poll = tunnel_socket_poll;
248}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
Convenience wrapper for the config headers.
Connection Credentials.
An open network connection (socket)
Convenience wrapper for the core headers.
#define EXEC_SHELL
Definition: filter.h:27
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:83
static int tunnel_socket_close(struct Connection *conn)
Close a tunnel socket - Implements Connection::close() -.
Definition: tunnel.c:212
static int tunnel_socket_open(struct Connection *conn)
Open a tunnel socket - Implements Connection::open() -.
Definition: tunnel.c:59
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:337
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:195
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:145
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:167
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_perror(...)
Definition: logging2.h:93
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:45
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:167
GUI display the mailboxes in a side panel.
void mutt_sig_block_system(void)
Block signals before calling exec()
Definition: signal.c:196
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition: signal.c:220
#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:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
A network tunnel (pair of sockets)
Definition: tunnel.c:50
int fd_read
File descriptor to read from.
Definition: tunnel.c:52
pid_t pid
Process ID of tunnel program.
Definition: tunnel.c:51
int fd_write
File descriptor to write to.
Definition: tunnel.c:53
void mutt_tunnel_socket_setup(struct Connection *conn)
Sets up tunnel connection functions.
Definition: tunnel.c:241