blob: e607acd08429d8b9ad6b801ac690bbb8434eef93 [file] [log] [blame]
djm@openbsd.org1a660792018-07-31 03:07:24 +00001/* $OpenBSD: mux.c,v 1.75 2018/07/31 03:07:24 djm Exp $ */
Damien Millerb1cbfa22008-05-19 16:00:08 +10002/*
3 * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* ssh session multiplexing support */
19
Darren Tucker2fb66ca2008-06-13 04:49:33 +100020/*
21 * TODO:
Damien Millere1537f92010-01-26 13:26:22 +110022 * - Better signalling from master to slave, especially passing of
Darren Tucker2fb66ca2008-06-13 04:49:33 +100023 * error messages
Damien Millere1537f92010-01-26 13:26:22 +110024 * - Better fall-back from mux slave error to new connection.
25 * - ExitOnForwardingFailure
26 * - Maybe extension mechanisms for multi-X11/multi-agent forwarding
27 * - Support ~^Z in mux slaves.
28 * - Inspect or control sessions in master.
29 * - If we ever support the "signal" channel request, send signals on
30 * sessions in master.
Darren Tucker2fb66ca2008-06-13 04:49:33 +100031 */
32
Damien Millere1537f92010-01-26 13:26:22 +110033#include "includes.h"
34
Damien Millerb1cbfa22008-05-19 16:00:08 +100035#include <sys/types.h>
Damien Millerb1cbfa22008-05-19 16:00:08 +100036#include <sys/stat.h>
37#include <sys/socket.h>
38#include <sys/un.h>
39
40#include <errno.h>
41#include <fcntl.h>
42#include <signal.h>
43#include <stdarg.h>
44#include <stddef.h>
45#include <stdlib.h>
46#include <stdio.h>
47#include <string.h>
48#include <unistd.h>
Darren Tuckerce38d822008-06-07 06:25:15 +100049#ifdef HAVE_PATHS_H
Damien Millerb1cbfa22008-05-19 16:00:08 +100050#include <paths.h>
Darren Tuckerce38d822008-06-07 06:25:15 +100051#endif
Damien Millerb1cbfa22008-05-19 16:00:08 +100052
Damien Millere1537f92010-01-26 13:26:22 +110053#ifdef HAVE_POLL_H
54#include <poll.h>
55#else
56# ifdef HAVE_SYS_POLL_H
57# include <sys/poll.h>
58# endif
59#endif
60
Damien Millera7058ec2008-05-20 08:57:06 +100061#ifdef HAVE_UTIL_H
62# include <util.h>
63#endif
64
Damien Millerb1cbfa22008-05-19 16:00:08 +100065#include "openbsd-compat/sys-queue.h"
66#include "xmalloc.h"
67#include "log.h"
68#include "ssh.h"
Damien Miller388f6fc2010-05-21 14:57:35 +100069#include "ssh2.h"
Damien Millerb1cbfa22008-05-19 16:00:08 +100070#include "pathnames.h"
71#include "misc.h"
72#include "match.h"
markus@openbsd.orgf4608a72018-07-09 21:18:10 +000073#include "sshbuf.h"
Damien Millerb1cbfa22008-05-19 16:00:08 +100074#include "channels.h"
75#include "msg.h"
76#include "packet.h"
77#include "monitor_fdpass.h"
78#include "sshpty.h"
markus@openbsd.org5467fbc2018-07-11 18:53:29 +000079#include "sshkey.h"
Damien Millerb1cbfa22008-05-19 16:00:08 +100080#include "readconf.h"
81#include "clientloop.h"
markus@openbsd.org8d057842016-09-30 09:19:13 +000082#include "ssherr.h"
Damien Millerb1cbfa22008-05-19 16:00:08 +100083
84/* from ssh.c */
85extern int tty_flag;
86extern Options options;
87extern int stdin_null_flag;
88extern char *host;
Darren Tucker8ec4fd82009-10-07 08:39:57 +110089extern int subsystem_flag;
markus@openbsd.orgcecee2d2018-07-09 21:03:30 +000090extern struct sshbuf *command;
Damien Millere1537f92010-01-26 13:26:22 +110091extern volatile sig_atomic_t quit_pending;
Damien Millerb1cbfa22008-05-19 16:00:08 +100092
Darren Tucker2fb66ca2008-06-13 04:49:33 +100093/* Context for session open confirmation callback */
94struct mux_session_confirm_ctx {
Damien Millere1537f92010-01-26 13:26:22 +110095 u_int want_tty;
96 u_int want_subsys;
97 u_int want_x_fwd;
98 u_int want_agent_fwd;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +000099 struct sshbuf *cmd;
Darren Tucker2fb66ca2008-06-13 04:49:33 +1000100 char *term;
101 struct termios tio;
102 char **env;
Damien Millerd530f5f2010-05-21 14:57:10 +1000103 u_int rid;
Darren Tucker2fb66ca2008-06-13 04:49:33 +1000104};
105
Damien Miller357610d2014-07-18 15:04:10 +1000106/* Context for stdio fwd open confirmation callback */
107struct mux_stdio_confirm_ctx {
108 u_int rid;
109};
110
Damien Miller388f6fc2010-05-21 14:57:35 +1000111/* Context for global channel callback */
112struct mux_channel_confirm_ctx {
113 u_int cid; /* channel id */
114 u_int rid; /* request id */
115 int fid; /* forward id */
116};
117
Damien Millerb1cbfa22008-05-19 16:00:08 +1000118/* fd to control socket */
119int muxserver_sock = -1;
120
Damien Millere1537f92010-01-26 13:26:22 +1100121/* client request id */
122u_int muxclient_request_id = 0;
123
Damien Millerb1cbfa22008-05-19 16:00:08 +1000124/* Multiplexing control command */
125u_int muxclient_command = 0;
126
127/* Set when signalled. */
128static volatile sig_atomic_t muxclient_terminate = 0;
129
130/* PID of multiplex server */
131static u_int muxserver_pid = 0;
132
Damien Millere1537f92010-01-26 13:26:22 +1100133static Channel *mux_listener_channel = NULL;
Damien Millerb1cbfa22008-05-19 16:00:08 +1000134
Damien Millere1537f92010-01-26 13:26:22 +1100135struct mux_master_state {
136 int hello_rcvd;
137};
138
139/* mux protocol messages */
140#define MUX_MSG_HELLO 0x00000001
141#define MUX_C_NEW_SESSION 0x10000002
142#define MUX_C_ALIVE_CHECK 0x10000004
143#define MUX_C_TERMINATE 0x10000005
144#define MUX_C_OPEN_FWD 0x10000006
145#define MUX_C_CLOSE_FWD 0x10000007
146#define MUX_C_NEW_STDIO_FWD 0x10000008
Damien Miller6c3eec72011-05-05 14:16:22 +1000147#define MUX_C_STOP_LISTENING 0x10000009
markus@openbsd.org8d057842016-09-30 09:19:13 +0000148#define MUX_C_PROXY 0x1000000f
Damien Millere1537f92010-01-26 13:26:22 +1100149#define MUX_S_OK 0x80000001
150#define MUX_S_PERMISSION_DENIED 0x80000002
151#define MUX_S_FAILURE 0x80000003
152#define MUX_S_EXIT_MESSAGE 0x80000004
153#define MUX_S_ALIVE 0x80000005
154#define MUX_S_SESSION_OPENED 0x80000006
Damien Miller388f6fc2010-05-21 14:57:35 +1000155#define MUX_S_REMOTE_PORT 0x80000007
Damien Miller555f3b82011-05-15 08:48:05 +1000156#define MUX_S_TTY_ALLOC_FAIL 0x80000008
markus@openbsd.org8d057842016-09-30 09:19:13 +0000157#define MUX_S_PROXY 0x8000000f
Damien Millere1537f92010-01-26 13:26:22 +1100158
159/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */
160#define MUX_FWD_LOCAL 1
161#define MUX_FWD_REMOTE 2
162#define MUX_FWD_DYNAMIC 3
163
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000164static void mux_session_confirm(struct ssh *, int, int, void *);
165static void mux_stdio_confirm(struct ssh *, int, int, void *);
Damien Millere1537f92010-01-26 13:26:22 +1100166
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000167static int process_mux_master_hello(struct ssh *, u_int,
168 Channel *, struct sshbuf *, struct sshbuf *);
169static int process_mux_new_session(struct ssh *, u_int,
170 Channel *, struct sshbuf *, struct sshbuf *);
171static int process_mux_alive_check(struct ssh *, u_int,
172 Channel *, struct sshbuf *, struct sshbuf *);
173static int process_mux_terminate(struct ssh *, u_int,
174 Channel *, struct sshbuf *, struct sshbuf *);
175static int process_mux_open_fwd(struct ssh *, u_int,
176 Channel *, struct sshbuf *, struct sshbuf *);
177static int process_mux_close_fwd(struct ssh *, u_int,
178 Channel *, struct sshbuf *, struct sshbuf *);
179static int process_mux_stdio_fwd(struct ssh *, u_int,
180 Channel *, struct sshbuf *, struct sshbuf *);
181static int process_mux_stop_listening(struct ssh *, u_int,
182 Channel *, struct sshbuf *, struct sshbuf *);
183static int process_mux_proxy(struct ssh *, u_int,
184 Channel *, struct sshbuf *, struct sshbuf *);
Damien Millere1537f92010-01-26 13:26:22 +1100185
186static const struct {
187 u_int type;
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000188 int (*handler)(struct ssh *, u_int, Channel *,
189 struct sshbuf *, struct sshbuf *);
Damien Millere1537f92010-01-26 13:26:22 +1100190} mux_master_handlers[] = {
191 { MUX_MSG_HELLO, process_mux_master_hello },
192 { MUX_C_NEW_SESSION, process_mux_new_session },
193 { MUX_C_ALIVE_CHECK, process_mux_alive_check },
194 { MUX_C_TERMINATE, process_mux_terminate },
195 { MUX_C_OPEN_FWD, process_mux_open_fwd },
196 { MUX_C_CLOSE_FWD, process_mux_close_fwd },
197 { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd },
Damien Miller6c3eec72011-05-05 14:16:22 +1000198 { MUX_C_STOP_LISTENING, process_mux_stop_listening },
markus@openbsd.org8d057842016-09-30 09:19:13 +0000199 { MUX_C_PROXY, process_mux_proxy },
Damien Millere1537f92010-01-26 13:26:22 +1100200 { 0, NULL }
201};
202
203/* Cleanup callback fired on closure of mux slave _session_ channel */
204/* ARGSUSED */
Darren Tuckerea8342c2013-06-06 08:11:40 +1000205static void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000206mux_master_session_cleanup_cb(struct ssh *ssh, int cid, void *unused)
Damien Millere1537f92010-01-26 13:26:22 +1100207{
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000208 Channel *cc, *c = channel_by_id(ssh, cid);
Damien Millere1537f92010-01-26 13:26:22 +1100209
210 debug3("%s: entering for channel %d", __func__, cid);
211 if (c == NULL)
212 fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
213 if (c->ctl_chan != -1) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000214 if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
Damien Millere1537f92010-01-26 13:26:22 +1100215 fatal("%s: channel %d missing control channel %d",
216 __func__, c->self, c->ctl_chan);
217 c->ctl_chan = -1;
djm@openbsd.org9f532292017-09-12 06:35:31 +0000218 cc->remote_id = 0;
219 cc->have_remote_id = 0;
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000220 chan_rcvd_oclose(ssh, cc);
Damien Millere1537f92010-01-26 13:26:22 +1100221 }
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000222 channel_cancel_cleanup(ssh, c->self);
Damien Millere1537f92010-01-26 13:26:22 +1100223}
224
225/* Cleanup callback fired on closure of mux slave _control_ channel */
226/* ARGSUSED */
227static void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000228mux_master_control_cleanup_cb(struct ssh *ssh, int cid, void *unused)
Damien Millere1537f92010-01-26 13:26:22 +1100229{
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000230 Channel *sc, *c = channel_by_id(ssh, cid);
Damien Millere1537f92010-01-26 13:26:22 +1100231
232 debug3("%s: entering for channel %d", __func__, cid);
233 if (c == NULL)
234 fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
djm@openbsd.org9f532292017-09-12 06:35:31 +0000235 if (c->have_remote_id) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000236 if ((sc = channel_by_id(ssh, c->remote_id)) == NULL)
djm@openbsd.org9f532292017-09-12 06:35:31 +0000237 fatal("%s: channel %d missing session channel %u",
Damien Millere1537f92010-01-26 13:26:22 +1100238 __func__, c->self, c->remote_id);
djm@openbsd.org9f532292017-09-12 06:35:31 +0000239 c->remote_id = 0;
240 c->have_remote_id = 0;
Damien Millere1537f92010-01-26 13:26:22 +1100241 sc->ctl_chan = -1;
Damien Miller172859c2013-04-23 15:19:27 +1000242 if (sc->type != SSH_CHANNEL_OPEN &&
243 sc->type != SSH_CHANNEL_OPENING) {
Damien Millera21cdfa2010-01-28 06:26:59 +1100244 debug2("%s: channel %d: not open", __func__, sc->self);
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000245 chan_mark_dead(ssh, sc);
Damien Millera21cdfa2010-01-28 06:26:59 +1100246 } else {
Damien Miller0dac03f2010-01-30 17:36:33 +1100247 if (sc->istate == CHAN_INPUT_OPEN)
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000248 chan_read_failed(ssh, sc);
Damien Miller0dac03f2010-01-30 17:36:33 +1100249 if (sc->ostate == CHAN_OUTPUT_OPEN)
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000250 chan_write_failed(ssh, sc);
Damien Millera21cdfa2010-01-28 06:26:59 +1100251 }
Damien Millere1537f92010-01-26 13:26:22 +1100252 }
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000253 channel_cancel_cleanup(ssh, c->self);
Damien Millere1537f92010-01-26 13:26:22 +1100254}
255
256/* Check mux client environment variables before passing them to mux master. */
257static int
258env_permitted(char *env)
259{
260 int i, ret;
261 char name[1024], *cp;
262
263 if ((cp = strchr(env, '=')) == NULL || cp == env)
264 return 0;
265 ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
266 if (ret <= 0 || (size_t)ret >= sizeof(name)) {
267 error("env_permitted: name '%.100s...' too long", env);
268 return 0;
269 }
270
271 for (i = 0; i < options.num_send_env; i++)
272 if (match_pattern(name, options.send_env[i]))
273 return 1;
274
275 return 0;
276}
277
278/* Mux master protocol message handlers */
279
280static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000281process_mux_master_hello(struct ssh *ssh, u_int rid,
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000282 Channel *c, struct sshbuf *m, struct sshbuf *reply)
Damien Millere1537f92010-01-26 13:26:22 +1100283{
284 u_int ver;
285 struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000286 int r;
Damien Millere1537f92010-01-26 13:26:22 +1100287
288 if (state == NULL)
289 fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self);
290 if (state->hello_rcvd) {
291 error("%s: HELLO received twice", __func__);
292 return -1;
293 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000294 if ((r = sshbuf_get_u32(m, &ver)) != 0) {
295 error("%s: malformed message: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +1100296 return -1;
297 }
298 if (ver != SSHMUX_VER) {
299 error("Unsupported multiplexing protocol version %d "
300 "(expected %d)", ver, SSHMUX_VER);
301 return -1;
302 }
303 debug2("%s: channel %d slave version %u", __func__, c->self, ver);
304
305 /* No extensions are presently defined */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000306 while (sshbuf_len(m) > 0) {
307 char *name = NULL;
Damien Millere1537f92010-01-26 13:26:22 +1100308
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000309 if ((r = sshbuf_get_cstring(m, &name, NULL)) != 0 ||
310 (r = sshbuf_skip_string(m)) != 0) { /* value */
311 error("%s: malformed extension: %s",
312 __func__, ssh_err(r));
313 return -1;
Damien Millere1537f92010-01-26 13:26:22 +1100314 }
315 debug2("Unrecognised slave extension \"%s\"", name);
Darren Tuckera627d422013-06-02 07:31:17 +1000316 free(name);
Damien Millere1537f92010-01-26 13:26:22 +1100317 }
318 state->hello_rcvd = 1;
319 return 0;
320}
321
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000322/* Enqueue a "ok" response to the reply buffer */
323static void
324reply_ok(struct sshbuf *reply, u_int rid)
325{
326 int r;
327
328 if ((r = sshbuf_put_u32(reply, MUX_S_OK)) != 0 ||
329 (r = sshbuf_put_u32(reply, rid)) != 0)
330 fatal("%s: reply: %s", __func__, ssh_err(r));
331}
332
333/* Enqueue an error response to the reply buffer */
334static void
335reply_error(struct sshbuf *reply, u_int type, u_int rid, const char *msg)
336{
337 int r;
338
339 if ((r = sshbuf_put_u32(reply, type)) != 0 ||
340 (r = sshbuf_put_u32(reply, rid)) != 0 ||
341 (r = sshbuf_put_cstring(reply, msg)) != 0)
342 fatal("%s: reply: %s", __func__, ssh_err(r));
343}
344
Damien Millere1537f92010-01-26 13:26:22 +1100345static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000346process_mux_new_session(struct ssh *ssh, u_int rid,
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000347 Channel *c, struct sshbuf *m, struct sshbuf *reply)
Damien Millere1537f92010-01-26 13:26:22 +1100348{
349 Channel *nc;
350 struct mux_session_confirm_ctx *cctx;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000351 char *cmd, *cp;
352 u_int i, j, env_len, escape_char, window, packetmax;
353 int r, new_fd[3];
Damien Millere1537f92010-01-26 13:26:22 +1100354
355 /* Reply for SSHMUX_COMMAND_OPEN */
356 cctx = xcalloc(1, sizeof(*cctx));
357 cctx->term = NULL;
Damien Millerd530f5f2010-05-21 14:57:10 +1000358 cctx->rid = rid;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000359 cmd = NULL;
Damien Millerab523b02012-07-06 13:44:43 +1000360 cctx->env = NULL;
361 env_len = 0;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000362 if ((r = sshbuf_skip_string(m)) != 0 || /* reserved */
363 (r = sshbuf_get_u32(m, &cctx->want_tty)) != 0 ||
364 (r = sshbuf_get_u32(m, &cctx->want_x_fwd)) != 0 ||
365 (r = sshbuf_get_u32(m, &cctx->want_agent_fwd)) != 0 ||
366 (r = sshbuf_get_u32(m, &cctx->want_subsys)) != 0 ||
367 (r = sshbuf_get_u32(m, &escape_char)) != 0 ||
368 (r = sshbuf_get_cstring(m, &cctx->term, NULL)) != 0 ||
369 (r = sshbuf_get_cstring(m, &cmd, NULL)) != 0) {
Damien Millere1537f92010-01-26 13:26:22 +1100370 malf:
Darren Tuckera627d422013-06-02 07:31:17 +1000371 free(cmd);
Damien Millerab523b02012-07-06 13:44:43 +1000372 for (j = 0; j < env_len; j++)
Darren Tuckera627d422013-06-02 07:31:17 +1000373 free(cctx->env[j]);
374 free(cctx->env);
375 free(cctx->term);
376 free(cctx);
Damien Millere1537f92010-01-26 13:26:22 +1100377 error("%s: malformed message", __func__);
378 return -1;
379 }
Damien Millere1537f92010-01-26 13:26:22 +1100380
Damien Millere1537f92010-01-26 13:26:22 +1100381#define MUX_MAX_ENV_VARS 4096
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000382 while (sshbuf_len(m) > 0) {
383 if ((r = sshbuf_get_cstring(m, &cp, NULL)) != 0)
Damien Millere1537f92010-01-26 13:26:22 +1100384 goto malf;
Damien Millere1537f92010-01-26 13:26:22 +1100385 if (!env_permitted(cp)) {
Darren Tuckera627d422013-06-02 07:31:17 +1000386 free(cp);
Damien Millere1537f92010-01-26 13:26:22 +1100387 continue;
388 }
deraadt@openbsd.org657a5fb2015-04-24 01:36:00 +0000389 cctx->env = xreallocarray(cctx->env, env_len + 2,
Damien Millere1537f92010-01-26 13:26:22 +1100390 sizeof(*cctx->env));
391 cctx->env[env_len++] = cp;
392 cctx->env[env_len] = NULL;
393 if (env_len > MUX_MAX_ENV_VARS) {
394 error(">%d environment variables received, ignoring "
395 "additional", MUX_MAX_ENV_VARS);
396 break;
397 }
398 }
399
400 debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, "
401 "term \"%s\", cmd \"%s\", env %u", __func__, c->self,
402 cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd,
403 cctx->want_subsys, cctx->term, cmd, env_len);
404
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000405 if ((cctx->cmd = sshbuf_new()) == NULL)
406 fatal("%s: sshbuf_new", __func__);
407 if ((r = sshbuf_put(cctx->cmd, cmd, strlen(cmd))) != 0)
408 fatal("%s: sshbuf_put: %s", __func__, ssh_err(r));
Darren Tuckera627d422013-06-02 07:31:17 +1000409 free(cmd);
Damien Millere1537f92010-01-26 13:26:22 +1100410 cmd = NULL;
411
412 /* Gather fds from client */
413 for(i = 0; i < 3; i++) {
414 if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
415 error("%s: failed to receive fd %d from slave",
416 __func__, i);
417 for (j = 0; j < i; j++)
418 close(new_fd[j]);
419 for (j = 0; j < env_len; j++)
Darren Tuckera627d422013-06-02 07:31:17 +1000420 free(cctx->env[j]);
421 free(cctx->env);
422 free(cctx->term);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000423 sshbuf_free(cctx->cmd);
Darren Tuckera627d422013-06-02 07:31:17 +1000424 free(cctx);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000425 reply_error(reply, MUX_S_FAILURE, rid,
Damien Millere1537f92010-01-26 13:26:22 +1100426 "did not receive file descriptors");
427 return -1;
428 }
429 }
430
431 debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
432 new_fd[0], new_fd[1], new_fd[2]);
433
434 /* XXX support multiple child sessions in future */
djm@openbsd.org9f532292017-09-12 06:35:31 +0000435 if (c->have_remote_id) {
Damien Millere1537f92010-01-26 13:26:22 +1100436 debug2("%s: session already open", __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000437 reply_error(reply, MUX_S_FAILURE, rid,
438 "Multiple sessions not supported");
Damien Millere1537f92010-01-26 13:26:22 +1100439 cleanup:
440 close(new_fd[0]);
441 close(new_fd[1]);
442 close(new_fd[2]);
Darren Tuckera627d422013-06-02 07:31:17 +1000443 free(cctx->term);
Damien Millere1537f92010-01-26 13:26:22 +1100444 if (env_len != 0) {
445 for (i = 0; i < env_len; i++)
Darren Tuckera627d422013-06-02 07:31:17 +1000446 free(cctx->env[i]);
447 free(cctx->env);
Damien Millere1537f92010-01-26 13:26:22 +1100448 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000449 sshbuf_free(cctx->cmd);
Darren Tuckera627d422013-06-02 07:31:17 +1000450 free(cctx);
Damien Millere1537f92010-01-26 13:26:22 +1100451 return 0;
452 }
453
454 if (options.control_master == SSHCTL_MASTER_ASK ||
455 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
456 if (!ask_permission("Allow shared connection to %s? ", host)) {
457 debug2("%s: session refused by user", __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000458 reply_error(reply, MUX_S_PERMISSION_DENIED, rid,
459 "Permission denied");
Damien Millere1537f92010-01-26 13:26:22 +1100460 goto cleanup;
461 }
462 }
463
464 /* Try to pick up ttymodes from client before it goes raw */
465 if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
466 error("%s: tcgetattr: %s", __func__, strerror(errno));
467
468 /* enable nonblocking unless tty */
469 if (!isatty(new_fd[0]))
470 set_nonblock(new_fd[0]);
471 if (!isatty(new_fd[1]))
472 set_nonblock(new_fd[1]);
473 if (!isatty(new_fd[2]))
474 set_nonblock(new_fd[2]);
475
476 window = CHAN_SES_WINDOW_DEFAULT;
477 packetmax = CHAN_SES_PACKET_DEFAULT;
478 if (cctx->want_tty) {
479 window >>= 1;
480 packetmax >>= 1;
481 }
482
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000483 nc = channel_new(ssh, "session", SSH_CHANNEL_OPENING,
Damien Millere1537f92010-01-26 13:26:22 +1100484 new_fd[0], new_fd[1], new_fd[2], window, packetmax,
485 CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
486
487 nc->ctl_chan = c->self; /* link session -> control channel */
488 c->remote_id = nc->self; /* link control -> session channel */
djm@openbsd.org9f532292017-09-12 06:35:31 +0000489 c->have_remote_id = 1;
Damien Millere1537f92010-01-26 13:26:22 +1100490
491 if (cctx->want_tty && escape_char != 0xffffffff) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000492 channel_register_filter(ssh, nc->self,
Damien Millere1537f92010-01-26 13:26:22 +1100493 client_simple_escape_filter, NULL,
494 client_filter_cleanup,
495 client_new_escape_filter_ctx((int)escape_char));
496 }
497
498 debug2("%s: channel_new: %d linked to control channel %d",
499 __func__, nc->self, nc->ctl_chan);
500
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000501 channel_send_open(ssh, nc->self);
502 channel_register_open_confirm(ssh, nc->self, mux_session_confirm, cctx);
Damien Millerd530f5f2010-05-21 14:57:10 +1000503 c->mux_pause = 1; /* stop handling messages until open_confirm done */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000504 channel_register_cleanup(ssh, nc->self,
505 mux_master_session_cleanup_cb, 1);
Damien Millere1537f92010-01-26 13:26:22 +1100506
Damien Millerd530f5f2010-05-21 14:57:10 +1000507 /* reply is deferred, sent by mux_session_confirm */
Damien Millere1537f92010-01-26 13:26:22 +1100508 return 0;
509}
510
511static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000512process_mux_alive_check(struct ssh *ssh, u_int rid,
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000513 Channel *c, struct sshbuf *m, struct sshbuf *reply)
Damien Millere1537f92010-01-26 13:26:22 +1100514{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000515 int r;
516
Damien Millere1537f92010-01-26 13:26:22 +1100517 debug2("%s: channel %d: alive check", __func__, c->self);
518
519 /* prepare reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000520 if ((r = sshbuf_put_u32(reply, MUX_S_ALIVE)) != 0 ||
521 (r = sshbuf_put_u32(reply, rid)) != 0 ||
522 (r = sshbuf_put_u32(reply, (u_int)getpid())) != 0)
523 fatal("%s: reply: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +1100524
525 return 0;
526}
527
528static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000529process_mux_terminate(struct ssh *ssh, u_int rid,
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000530 Channel *c, struct sshbuf *m, struct sshbuf *reply)
Damien Millere1537f92010-01-26 13:26:22 +1100531{
532 debug2("%s: channel %d: terminate request", __func__, c->self);
533
534 if (options.control_master == SSHCTL_MASTER_ASK ||
535 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
536 if (!ask_permission("Terminate shared connection to %s? ",
537 host)) {
538 debug2("%s: termination refused by user", __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000539 reply_error(reply, MUX_S_PERMISSION_DENIED, rid,
540 "Permission denied");
Damien Millere1537f92010-01-26 13:26:22 +1100541 return 0;
542 }
543 }
544
545 quit_pending = 1;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000546 reply_ok(reply, rid);
Damien Millere1537f92010-01-26 13:26:22 +1100547 /* XXX exit happens too soon - message never makes it to client */
548 return 0;
549}
550
551static char *
Damien Miller7acefbb2014-07-18 14:11:24 +1000552format_forward(u_int ftype, struct Forward *fwd)
Damien Millere1537f92010-01-26 13:26:22 +1100553{
554 char *ret;
555
556 switch (ftype) {
557 case MUX_FWD_LOCAL:
558 xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d",
Damien Miller7acefbb2014-07-18 14:11:24 +1000559 (fwd->listen_path != NULL) ? fwd->listen_path :
Damien Millere1537f92010-01-26 13:26:22 +1100560 (fwd->listen_host == NULL) ?
Damien Miller7acefbb2014-07-18 14:11:24 +1000561 (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
Damien Millere1537f92010-01-26 13:26:22 +1100562 fwd->listen_host, fwd->listen_port,
Damien Miller7acefbb2014-07-18 14:11:24 +1000563 (fwd->connect_path != NULL) ? fwd->connect_path :
Damien Millere1537f92010-01-26 13:26:22 +1100564 fwd->connect_host, fwd->connect_port);
565 break;
566 case MUX_FWD_DYNAMIC:
567 xasprintf(&ret, "dynamic forward %.200s:%d -> *",
568 (fwd->listen_host == NULL) ?
Damien Miller7acefbb2014-07-18 14:11:24 +1000569 (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
Damien Millere1537f92010-01-26 13:26:22 +1100570 fwd->listen_host, fwd->listen_port);
571 break;
572 case MUX_FWD_REMOTE:
573 xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d",
Damien Miller7acefbb2014-07-18 14:11:24 +1000574 (fwd->listen_path != NULL) ? fwd->listen_path :
Damien Millere1537f92010-01-26 13:26:22 +1100575 (fwd->listen_host == NULL) ?
576 "LOCALHOST" : fwd->listen_host,
577 fwd->listen_port,
Damien Miller7acefbb2014-07-18 14:11:24 +1000578 (fwd->connect_path != NULL) ? fwd->connect_path :
Damien Millere1537f92010-01-26 13:26:22 +1100579 fwd->connect_host, fwd->connect_port);
580 break;
581 default:
582 fatal("%s: unknown forward type %u", __func__, ftype);
583 }
584 return ret;
585}
586
587static int
588compare_host(const char *a, const char *b)
589{
590 if (a == NULL && b == NULL)
591 return 1;
592 if (a == NULL || b == NULL)
593 return 0;
594 return strcmp(a, b) == 0;
595}
596
597static int
Damien Miller7acefbb2014-07-18 14:11:24 +1000598compare_forward(struct Forward *a, struct Forward *b)
Damien Millere1537f92010-01-26 13:26:22 +1100599{
600 if (!compare_host(a->listen_host, b->listen_host))
601 return 0;
Damien Miller7acefbb2014-07-18 14:11:24 +1000602 if (!compare_host(a->listen_path, b->listen_path))
603 return 0;
Damien Millere1537f92010-01-26 13:26:22 +1100604 if (a->listen_port != b->listen_port)
605 return 0;
606 if (!compare_host(a->connect_host, b->connect_host))
607 return 0;
Damien Miller7acefbb2014-07-18 14:11:24 +1000608 if (!compare_host(a->connect_path, b->connect_path))
609 return 0;
Damien Millere1537f92010-01-26 13:26:22 +1100610 if (a->connect_port != b->connect_port)
611 return 0;
612
613 return 1;
614}
615
Damien Miller388f6fc2010-05-21 14:57:35 +1000616static void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000617mux_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt)
Damien Miller388f6fc2010-05-21 14:57:35 +1000618{
619 struct mux_channel_confirm_ctx *fctx = ctxt;
620 char *failmsg = NULL;
Damien Miller7acefbb2014-07-18 14:11:24 +1000621 struct Forward *rfwd;
Damien Miller388f6fc2010-05-21 14:57:35 +1000622 Channel *c;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000623 struct sshbuf *out;
624 int r;
Damien Miller388f6fc2010-05-21 14:57:35 +1000625
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000626 if ((c = channel_by_id(ssh, fctx->cid)) == NULL) {
Damien Miller388f6fc2010-05-21 14:57:35 +1000627 /* no channel for reply */
628 error("%s: unknown channel", __func__);
629 return;
630 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000631 if ((out = sshbuf_new()) == NULL)
632 fatal("%s: sshbuf_new", __func__);
djm@openbsd.orgca430d42015-05-01 04:03:20 +0000633 if (fctx->fid >= options.num_remote_forwards ||
634 (options.remote_forwards[fctx->fid].connect_path == NULL &&
635 options.remote_forwards[fctx->fid].connect_host == NULL)) {
Damien Miller388f6fc2010-05-21 14:57:35 +1000636 xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid);
637 goto fail;
638 }
639 rfwd = &options.remote_forwards[fctx->fid];
640 debug("%s: %s for: listen %d, connect %s:%d", __func__,
641 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
Damien Miller7acefbb2014-07-18 14:11:24 +1000642 rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path :
643 rfwd->connect_host, rfwd->connect_port);
Damien Miller388f6fc2010-05-21 14:57:35 +1000644 if (type == SSH2_MSG_REQUEST_SUCCESS) {
645 if (rfwd->listen_port == 0) {
646 rfwd->allocated_port = packet_get_int();
djm@openbsd.org8312cfb2015-05-01 04:01:58 +0000647 debug("Allocated port %u for mux remote forward"
Damien Miller388f6fc2010-05-21 14:57:35 +1000648 " to %s:%d", rfwd->allocated_port,
649 rfwd->connect_host, rfwd->connect_port);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000650 if ((r = sshbuf_put_u32(out,
651 MUX_S_REMOTE_PORT)) != 0 ||
652 (r = sshbuf_put_u32(out, fctx->rid)) != 0 ||
653 (r = sshbuf_put_u32(out,
654 rfwd->allocated_port)) != 0)
655 fatal("%s: reply: %s", __func__, ssh_err(r));
djm@openbsd.org115063a2018-06-06 18:22:41 +0000656 channel_update_permission(ssh, rfwd->handle,
Darren Tucker68afb8c2011-10-02 18:59:03 +1100657 rfwd->allocated_port);
Damien Miller388f6fc2010-05-21 14:57:35 +1000658 } else {
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000659 reply_ok(out, fctx->rid);
Damien Miller388f6fc2010-05-21 14:57:35 +1000660 }
661 goto out;
662 } else {
Darren Tucker68afb8c2011-10-02 18:59:03 +1100663 if (rfwd->listen_port == 0)
djm@openbsd.org115063a2018-06-06 18:22:41 +0000664 channel_update_permission(ssh, rfwd->handle, -1);
Damien Miller7acefbb2014-07-18 14:11:24 +1000665 if (rfwd->listen_path != NULL)
666 xasprintf(&failmsg, "remote port forwarding failed for "
667 "listen path %s", rfwd->listen_path);
668 else
669 xasprintf(&failmsg, "remote port forwarding failed for "
670 "listen port %d", rfwd->listen_port);
djm@openbsd.orgca430d42015-05-01 04:03:20 +0000671
672 debug2("%s: clearing registered forwarding for listen %d, "
673 "connect %s:%d", __func__, rfwd->listen_port,
674 rfwd->connect_path ? rfwd->connect_path :
675 rfwd->connect_host, rfwd->connect_port);
676
677 free(rfwd->listen_host);
678 free(rfwd->listen_path);
679 free(rfwd->connect_host);
680 free(rfwd->connect_path);
681 memset(rfwd, 0, sizeof(*rfwd));
Damien Miller388f6fc2010-05-21 14:57:35 +1000682 }
683 fail:
684 error("%s: %s", __func__, failmsg);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000685 reply_error(out, MUX_S_FAILURE, fctx->rid, failmsg);
Darren Tuckera627d422013-06-02 07:31:17 +1000686 free(failmsg);
Damien Miller388f6fc2010-05-21 14:57:35 +1000687 out:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000688 if ((r = sshbuf_put_stringb(c->output, out)) != 0)
689 fatal("%s: sshbuf_put_stringb: %s", __func__, ssh_err(r));
690 sshbuf_free(out);
Damien Miller388f6fc2010-05-21 14:57:35 +1000691 if (c->mux_pause <= 0)
692 fatal("%s: mux_pause %d", __func__, c->mux_pause);
693 c->mux_pause = 0; /* start processing messages again */
694}
695
Damien Millere1537f92010-01-26 13:26:22 +1100696static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000697process_mux_open_fwd(struct ssh *ssh, u_int rid,
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000698 Channel *c, struct sshbuf *m, struct sshbuf *reply)
Damien Millere1537f92010-01-26 13:26:22 +1100699{
Damien Miller7acefbb2014-07-18 14:11:24 +1000700 struct Forward fwd;
Damien Millere1537f92010-01-26 13:26:22 +1100701 char *fwd_desc = NULL;
Damien Miller7acefbb2014-07-18 14:11:24 +1000702 char *listen_addr, *connect_addr;
Damien Millere1537f92010-01-26 13:26:22 +1100703 u_int ftype;
Damien Millerce986542013-07-18 16:12:44 +1000704 u_int lport, cport;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000705 int r, i, ret = 0, freefwd = 1;
Damien Millere1537f92010-01-26 13:26:22 +1100706
djm@openbsd.org45b0eb72015-08-19 23:18:26 +0000707 memset(&fwd, 0, sizeof(fwd));
708
Damien Miller7acefbb2014-07-18 14:11:24 +1000709 /* XXX - lport/cport check redundant */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000710 if ((r = sshbuf_get_u32(m, &ftype)) != 0 ||
711 (r = sshbuf_get_cstring(m, &listen_addr, NULL)) != 0 ||
712 (r = sshbuf_get_u32(m, &lport)) != 0 ||
713 (r = sshbuf_get_cstring(m, &connect_addr, NULL)) != 0 ||
714 (r = sshbuf_get_u32(m, &cport)) != 0 ||
Damien Miller7acefbb2014-07-18 14:11:24 +1000715 (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
716 (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
Damien Millere1537f92010-01-26 13:26:22 +1100717 error("%s: malformed message", __func__);
718 ret = -1;
719 goto out;
720 }
Damien Miller7acefbb2014-07-18 14:11:24 +1000721 if (*listen_addr == '\0') {
722 free(listen_addr);
723 listen_addr = NULL;
724 }
725 if (*connect_addr == '\0') {
726 free(connect_addr);
727 connect_addr = NULL;
728 }
729
730 memset(&fwd, 0, sizeof(fwd));
Damien Millerce986542013-07-18 16:12:44 +1000731 fwd.listen_port = lport;
Damien Miller7acefbb2014-07-18 14:11:24 +1000732 if (fwd.listen_port == PORT_STREAMLOCAL)
733 fwd.listen_path = listen_addr;
734 else
735 fwd.listen_host = listen_addr;
Damien Millerce986542013-07-18 16:12:44 +1000736 fwd.connect_port = cport;
Damien Miller7acefbb2014-07-18 14:11:24 +1000737 if (fwd.connect_port == PORT_STREAMLOCAL)
738 fwd.connect_path = connect_addr;
739 else
740 fwd.connect_host = connect_addr;
Damien Millere1537f92010-01-26 13:26:22 +1100741
742 debug2("%s: channel %d: request %s", __func__, c->self,
743 (fwd_desc = format_forward(ftype, &fwd)));
744
745 if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE &&
746 ftype != MUX_FWD_DYNAMIC) {
747 logit("%s: invalid forwarding type %u", __func__, ftype);
748 invalid:
Damien Miller7acefbb2014-07-18 14:11:24 +1000749 free(listen_addr);
750 free(connect_addr);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000751 reply_error(reply, MUX_S_FAILURE, rid,
752 "Invalid forwarding request");
Damien Millere1537f92010-01-26 13:26:22 +1100753 return 0;
754 }
Damien Miller7acefbb2014-07-18 14:11:24 +1000755 if (ftype == MUX_FWD_DYNAMIC && fwd.listen_path) {
756 logit("%s: streamlocal and dynamic forwards "
757 "are mutually exclusive", __func__);
758 goto invalid;
759 }
760 if (fwd.listen_port != PORT_STREAMLOCAL && fwd.listen_port >= 65536) {
Damien Millere1537f92010-01-26 13:26:22 +1100761 logit("%s: invalid listen port %u", __func__,
762 fwd.listen_port);
763 goto invalid;
764 }
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000765 if ((fwd.connect_port != PORT_STREAMLOCAL &&
766 fwd.connect_port >= 65536) ||
767 (ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE &&
768 fwd.connect_port == 0)) {
Damien Millere1537f92010-01-26 13:26:22 +1100769 logit("%s: invalid connect port %u", __func__,
770 fwd.connect_port);
771 goto invalid;
772 }
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000773 if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL &&
774 fwd.connect_path == NULL) {
Damien Millere1537f92010-01-26 13:26:22 +1100775 logit("%s: missing connect host", __func__);
776 goto invalid;
777 }
778
779 /* Skip forwards that have already been requested */
780 switch (ftype) {
781 case MUX_FWD_LOCAL:
782 case MUX_FWD_DYNAMIC:
783 for (i = 0; i < options.num_local_forwards; i++) {
784 if (compare_forward(&fwd,
785 options.local_forwards + i)) {
786 exists:
787 debug2("%s: found existing forwarding",
788 __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000789 reply_ok(reply, rid);
Damien Millere1537f92010-01-26 13:26:22 +1100790 goto out;
791 }
792 }
793 break;
794 case MUX_FWD_REMOTE:
795 for (i = 0; i < options.num_remote_forwards; i++) {
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000796 if (!compare_forward(&fwd, options.remote_forwards + i))
797 continue;
798 if (fwd.listen_port != 0)
799 goto exists;
800 debug2("%s: found allocated port", __func__);
801 if ((r = sshbuf_put_u32(reply,
802 MUX_S_REMOTE_PORT)) != 0 ||
803 (r = sshbuf_put_u32(reply, rid)) != 0 ||
804 (r = sshbuf_put_u32(reply,
805 options.remote_forwards[i].allocated_port)) != 0)
806 fatal("%s: reply: %s", __func__, ssh_err(r));
807 goto out;
Damien Millere1537f92010-01-26 13:26:22 +1100808 }
809 break;
810 }
811
812 if (options.control_master == SSHCTL_MASTER_ASK ||
813 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
814 if (!ask_permission("Open %s on %s?", fwd_desc, host)) {
815 debug2("%s: forwarding refused by user", __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000816 reply_error(reply, MUX_S_PERMISSION_DENIED, rid,
817 "Permission denied");
Damien Millere1537f92010-01-26 13:26:22 +1100818 goto out;
819 }
820 }
821
822 if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000823 if (!channel_setup_local_fwd_listener(ssh, &fwd,
Damien Miller7acefbb2014-07-18 14:11:24 +1000824 &options.fwd_opts)) {
Damien Millere1537f92010-01-26 13:26:22 +1100825 fail:
826 logit("slave-requested %s failed", fwd_desc);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000827 reply_error(reply, MUX_S_FAILURE, rid,
828 "Port forwarding failed");
Damien Millere1537f92010-01-26 13:26:22 +1100829 goto out;
830 }
831 add_local_forward(&options, &fwd);
832 freefwd = 0;
833 } else {
Damien Miller388f6fc2010-05-21 14:57:35 +1000834 struct mux_channel_confirm_ctx *fctx;
835
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000836 fwd.handle = channel_request_remote_forwarding(ssh, &fwd);
Darren Tucker68afb8c2011-10-02 18:59:03 +1100837 if (fwd.handle < 0)
Damien Millere1537f92010-01-26 13:26:22 +1100838 goto fail;
839 add_remote_forward(&options, &fwd);
Damien Miller388f6fc2010-05-21 14:57:35 +1000840 fctx = xcalloc(1, sizeof(*fctx));
841 fctx->cid = c->self;
842 fctx->rid = rid;
Damien Miller232cfb12010-06-26 09:50:30 +1000843 fctx->fid = options.num_remote_forwards - 1;
Damien Miller388f6fc2010-05-21 14:57:35 +1000844 client_register_global_confirm(mux_confirm_remote_forward,
845 fctx);
Damien Millere1537f92010-01-26 13:26:22 +1100846 freefwd = 0;
Damien Miller388f6fc2010-05-21 14:57:35 +1000847 c->mux_pause = 1; /* wait for mux_confirm_remote_forward */
848 /* delayed reply in mux_confirm_remote_forward */
849 goto out;
Damien Millere1537f92010-01-26 13:26:22 +1100850 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000851 reply_ok(reply, rid);
Damien Millere1537f92010-01-26 13:26:22 +1100852 out:
Darren Tuckera627d422013-06-02 07:31:17 +1000853 free(fwd_desc);
Damien Millere1537f92010-01-26 13:26:22 +1100854 if (freefwd) {
Darren Tuckera627d422013-06-02 07:31:17 +1000855 free(fwd.listen_host);
Damien Miller7acefbb2014-07-18 14:11:24 +1000856 free(fwd.listen_path);
Darren Tuckera627d422013-06-02 07:31:17 +1000857 free(fwd.connect_host);
Damien Miller7acefbb2014-07-18 14:11:24 +1000858 free(fwd.connect_path);
Damien Millere1537f92010-01-26 13:26:22 +1100859 }
860 return ret;
861}
862
863static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000864process_mux_close_fwd(struct ssh *ssh, u_int rid,
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000865 Channel *c, struct sshbuf *m, struct sshbuf *reply)
Damien Millere1537f92010-01-26 13:26:22 +1100866{
Damien Miller7acefbb2014-07-18 14:11:24 +1000867 struct Forward fwd, *found_fwd;
Damien Millere1537f92010-01-26 13:26:22 +1100868 char *fwd_desc = NULL;
Damien Millerf6dff7c2011-09-22 21:38:52 +1000869 const char *error_reason = NULL;
Damien Miller7acefbb2014-07-18 14:11:24 +1000870 char *listen_addr = NULL, *connect_addr = NULL;
Damien Millere1537f92010-01-26 13:26:22 +1100871 u_int ftype;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000872 int r, i, ret = 0;
Damien Millerce986542013-07-18 16:12:44 +1000873 u_int lport, cport;
Damien Millere1537f92010-01-26 13:26:22 +1100874
djm@openbsd.org45b0eb72015-08-19 23:18:26 +0000875 memset(&fwd, 0, sizeof(fwd));
876
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000877 if ((r = sshbuf_get_u32(m, &ftype)) != 0 ||
878 (r = sshbuf_get_cstring(m, &listen_addr, NULL)) != 0 ||
879 (r = sshbuf_get_u32(m, &lport)) != 0 ||
880 (r = sshbuf_get_cstring(m, &connect_addr, NULL)) != 0 ||
881 (r = sshbuf_get_u32(m, &cport)) != 0 ||
Damien Miller7acefbb2014-07-18 14:11:24 +1000882 (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
883 (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
Damien Millere1537f92010-01-26 13:26:22 +1100884 error("%s: malformed message", __func__);
885 ret = -1;
886 goto out;
887 }
888
Damien Miller7acefbb2014-07-18 14:11:24 +1000889 if (*listen_addr == '\0') {
890 free(listen_addr);
891 listen_addr = NULL;
Damien Millere1537f92010-01-26 13:26:22 +1100892 }
Damien Miller7acefbb2014-07-18 14:11:24 +1000893 if (*connect_addr == '\0') {
894 free(connect_addr);
895 connect_addr = NULL;
Damien Millere1537f92010-01-26 13:26:22 +1100896 }
897
Damien Miller7acefbb2014-07-18 14:11:24 +1000898 memset(&fwd, 0, sizeof(fwd));
899 fwd.listen_port = lport;
900 if (fwd.listen_port == PORT_STREAMLOCAL)
901 fwd.listen_path = listen_addr;
902 else
903 fwd.listen_host = listen_addr;
904 fwd.connect_port = cport;
905 if (fwd.connect_port == PORT_STREAMLOCAL)
906 fwd.connect_path = connect_addr;
907 else
908 fwd.connect_host = connect_addr;
909
Damien Millerf6dff7c2011-09-22 21:38:52 +1000910 debug2("%s: channel %d: request cancel %s", __func__, c->self,
Damien Millere1537f92010-01-26 13:26:22 +1100911 (fwd_desc = format_forward(ftype, &fwd)));
912
Damien Millerf6dff7c2011-09-22 21:38:52 +1000913 /* make sure this has been requested */
914 found_fwd = NULL;
915 switch (ftype) {
916 case MUX_FWD_LOCAL:
917 case MUX_FWD_DYNAMIC:
918 for (i = 0; i < options.num_local_forwards; i++) {
919 if (compare_forward(&fwd,
920 options.local_forwards + i)) {
921 found_fwd = options.local_forwards + i;
922 break;
923 }
924 }
925 break;
926 case MUX_FWD_REMOTE:
927 for (i = 0; i < options.num_remote_forwards; i++) {
928 if (compare_forward(&fwd,
929 options.remote_forwards + i)) {
930 found_fwd = options.remote_forwards + i;
931 break;
932 }
933 }
934 break;
935 }
Damien Millere1537f92010-01-26 13:26:22 +1100936
Damien Millerf6dff7c2011-09-22 21:38:52 +1000937 if (found_fwd == NULL)
938 error_reason = "port not forwarded";
939 else if (ftype == MUX_FWD_REMOTE) {
940 /*
941 * This shouldn't fail unless we confused the host/port
942 * between options.remote_forwards and permitted_opens.
Darren Tucker68afb8c2011-10-02 18:59:03 +1100943 * However, for dynamic allocated listen ports we need
Damien Miller7acefbb2014-07-18 14:11:24 +1000944 * to use the actual listen port.
Damien Millerf6dff7c2011-09-22 21:38:52 +1000945 */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000946 if (channel_request_rforward_cancel(ssh, found_fwd) == -1)
Damien Millerf6dff7c2011-09-22 21:38:52 +1000947 error_reason = "port not in permitted opens";
948 } else { /* local and dynamic forwards */
949 /* Ditto */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000950 if (channel_cancel_lport_listener(ssh, &fwd, fwd.connect_port,
Damien Miller7acefbb2014-07-18 14:11:24 +1000951 &options.fwd_opts) == -1)
Damien Millerf6dff7c2011-09-22 21:38:52 +1000952 error_reason = "port not found";
953 }
954
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000955 if (error_reason != NULL)
956 reply_error(reply, MUX_S_FAILURE, rid, error_reason);
957 else {
958 reply_ok(reply, rid);
Darren Tuckera627d422013-06-02 07:31:17 +1000959 free(found_fwd->listen_host);
Damien Miller7acefbb2014-07-18 14:11:24 +1000960 free(found_fwd->listen_path);
Darren Tuckera627d422013-06-02 07:31:17 +1000961 free(found_fwd->connect_host);
Damien Miller7acefbb2014-07-18 14:11:24 +1000962 free(found_fwd->connect_path);
Damien Millerf6dff7c2011-09-22 21:38:52 +1000963 found_fwd->listen_host = found_fwd->connect_host = NULL;
Damien Miller7acefbb2014-07-18 14:11:24 +1000964 found_fwd->listen_path = found_fwd->connect_path = NULL;
Damien Millerf6dff7c2011-09-22 21:38:52 +1000965 found_fwd->listen_port = found_fwd->connect_port = 0;
Damien Millerf6dff7c2011-09-22 21:38:52 +1000966 }
Damien Millere1537f92010-01-26 13:26:22 +1100967 out:
Darren Tuckera627d422013-06-02 07:31:17 +1000968 free(fwd_desc);
Damien Miller7acefbb2014-07-18 14:11:24 +1000969 free(listen_addr);
970 free(connect_addr);
Damien Millere1537f92010-01-26 13:26:22 +1100971
972 return ret;
973}
974
975static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000976process_mux_stdio_fwd(struct ssh *ssh, u_int rid,
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000977 Channel *c, struct sshbuf *m, struct sshbuf *reply)
Damien Millere1537f92010-01-26 13:26:22 +1100978{
979 Channel *nc;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000980 char *chost = NULL;
Damien Millere1537f92010-01-26 13:26:22 +1100981 u_int cport, i, j;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000982 int r, new_fd[2];
Damien Miller357610d2014-07-18 15:04:10 +1000983 struct mux_stdio_confirm_ctx *cctx;
Damien Millere1537f92010-01-26 13:26:22 +1100984
markus@openbsd.orgf4608a72018-07-09 21:18:10 +0000985 if ((r = sshbuf_skip_string(m)) != 0 || /* reserved */
986 (r = sshbuf_get_cstring(m, &chost, NULL)) != 0 ||
987 (r = sshbuf_get_u32(m, &cport)) != 0) {
Darren Tuckera627d422013-06-02 07:31:17 +1000988 free(chost);
Damien Millere1537f92010-01-26 13:26:22 +1100989 error("%s: malformed message", __func__);
990 return -1;
991 }
Damien Millere1537f92010-01-26 13:26:22 +1100992
993 debug2("%s: channel %d: request stdio fwd to %s:%u",
994 __func__, c->self, chost, cport);
995
996 /* Gather fds from client */
997 for(i = 0; i < 2; i++) {
998 if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
999 error("%s: failed to receive fd %d from slave",
1000 __func__, i);
1001 for (j = 0; j < i; j++)
1002 close(new_fd[j]);
Darren Tuckera627d422013-06-02 07:31:17 +10001003 free(chost);
Damien Millere1537f92010-01-26 13:26:22 +11001004
1005 /* prepare reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001006 reply_error(reply, MUX_S_FAILURE, rid,
Damien Millere1537f92010-01-26 13:26:22 +11001007 "did not receive file descriptors");
1008 return -1;
1009 }
1010 }
1011
1012 debug3("%s: got fds stdin %d, stdout %d", __func__,
1013 new_fd[0], new_fd[1]);
1014
1015 /* XXX support multiple child sessions in future */
djm@openbsd.org9f532292017-09-12 06:35:31 +00001016 if (c->have_remote_id) {
Damien Millere1537f92010-01-26 13:26:22 +11001017 debug2("%s: session already open", __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001018 reply_error(reply, MUX_S_FAILURE, rid,
1019 "Multiple sessions not supported");
Damien Millere1537f92010-01-26 13:26:22 +11001020 cleanup:
1021 close(new_fd[0]);
1022 close(new_fd[1]);
Darren Tuckera627d422013-06-02 07:31:17 +10001023 free(chost);
Damien Millere1537f92010-01-26 13:26:22 +11001024 return 0;
1025 }
1026
1027 if (options.control_master == SSHCTL_MASTER_ASK ||
1028 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
Damien Miller68512c02010-10-21 15:21:11 +11001029 if (!ask_permission("Allow forward to %s:%u? ",
Damien Millere1537f92010-01-26 13:26:22 +11001030 chost, cport)) {
1031 debug2("%s: stdio fwd refused by user", __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001032 reply_error(reply, MUX_S_PERMISSION_DENIED, rid,
1033 "Permission denied");
Damien Millere1537f92010-01-26 13:26:22 +11001034 goto cleanup;
1035 }
1036 }
1037
1038 /* enable nonblocking unless tty */
1039 if (!isatty(new_fd[0]))
1040 set_nonblock(new_fd[0]);
1041 if (!isatty(new_fd[1]))
1042 set_nonblock(new_fd[1]);
1043
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001044 nc = channel_connect_stdio_fwd(ssh, chost, cport, new_fd[0], new_fd[1]);
djm@openbsd.org1a660792018-07-31 03:07:24 +00001045 free(chost);
Damien Millere1537f92010-01-26 13:26:22 +11001046
1047 nc->ctl_chan = c->self; /* link session -> control channel */
1048 c->remote_id = nc->self; /* link control -> session channel */
djm@openbsd.org9f532292017-09-12 06:35:31 +00001049 c->have_remote_id = 1;
Damien Millere1537f92010-01-26 13:26:22 +11001050
1051 debug2("%s: channel_new: %d linked to control channel %d",
1052 __func__, nc->self, nc->ctl_chan);
1053
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001054 channel_register_cleanup(ssh, nc->self,
1055 mux_master_session_cleanup_cb, 1);
Damien Millere1537f92010-01-26 13:26:22 +11001056
Damien Miller357610d2014-07-18 15:04:10 +10001057 cctx = xcalloc(1, sizeof(*cctx));
1058 cctx->rid = rid;
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001059 channel_register_open_confirm(ssh, nc->self, mux_stdio_confirm, cctx);
Damien Miller357610d2014-07-18 15:04:10 +10001060 c->mux_pause = 1; /* stop handling messages until open_confirm done */
Damien Millere1537f92010-01-26 13:26:22 +11001061
Damien Miller357610d2014-07-18 15:04:10 +10001062 /* reply is deferred, sent by mux_session_confirm */
Damien Millere1537f92010-01-26 13:26:22 +11001063 return 0;
1064}
1065
Damien Miller357610d2014-07-18 15:04:10 +10001066/* Callback on open confirmation in mux master for a mux stdio fwd session. */
1067static void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001068mux_stdio_confirm(struct ssh *ssh, int id, int success, void *arg)
Damien Miller357610d2014-07-18 15:04:10 +10001069{
1070 struct mux_stdio_confirm_ctx *cctx = arg;
1071 Channel *c, *cc;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001072 struct sshbuf *reply;
1073 int r;
Damien Miller357610d2014-07-18 15:04:10 +10001074
1075 if (cctx == NULL)
1076 fatal("%s: cctx == NULL", __func__);
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001077 if ((c = channel_by_id(ssh, id)) == NULL)
Damien Miller357610d2014-07-18 15:04:10 +10001078 fatal("%s: no channel for id %d", __func__, id);
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001079 if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
Damien Miller357610d2014-07-18 15:04:10 +10001080 fatal("%s: channel %d lacks control channel %d", __func__,
1081 id, c->ctl_chan);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001082 if ((reply = sshbuf_new()) == NULL)
1083 fatal("%s: sshbuf_new", __func__);
Damien Miller357610d2014-07-18 15:04:10 +10001084
1085 if (!success) {
1086 debug3("%s: sending failure reply", __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001087 reply_error(reply, MUX_S_FAILURE, cctx->rid,
1088 "Session open refused by peer");
Damien Miller357610d2014-07-18 15:04:10 +10001089 /* prepare reply */
Damien Miller357610d2014-07-18 15:04:10 +10001090 goto done;
1091 }
1092
1093 debug3("%s: sending success reply", __func__);
1094 /* prepare reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001095 if ((r = sshbuf_put_u32(reply, MUX_S_SESSION_OPENED)) != 0 ||
1096 (r = sshbuf_put_u32(reply, cctx->rid)) != 0 ||
1097 (r = sshbuf_put_u32(reply, c->self)) != 0)
1098 fatal("%s: reply: %s", __func__, ssh_err(r));
Damien Miller357610d2014-07-18 15:04:10 +10001099
1100 done:
1101 /* Send reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001102 if ((r = sshbuf_put_stringb(cc->output, reply)) != 0)
1103 fatal("%s: sshbuf_put_stringb: %s", __func__, ssh_err(r));
1104 sshbuf_free(reply);
Damien Miller357610d2014-07-18 15:04:10 +10001105
1106 if (cc->mux_pause <= 0)
1107 fatal("%s: mux_pause %d", __func__, cc->mux_pause);
1108 cc->mux_pause = 0; /* start processing messages again */
1109 c->open_confirm_ctx = NULL;
1110 free(cctx);
1111}
1112
Damien Miller6c3eec72011-05-05 14:16:22 +10001113static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001114process_mux_stop_listening(struct ssh *ssh, u_int rid,
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001115 Channel *c, struct sshbuf *m, struct sshbuf *reply)
Damien Miller6c3eec72011-05-05 14:16:22 +10001116{
1117 debug("%s: channel %d: stop listening", __func__, c->self);
1118
1119 if (options.control_master == SSHCTL_MASTER_ASK ||
1120 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
1121 if (!ask_permission("Disable further multiplexing on shared "
1122 "connection to %s? ", host)) {
1123 debug2("%s: stop listen refused by user", __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001124 reply_error(reply, MUX_S_PERMISSION_DENIED, rid,
1125 "Permission denied");
Damien Miller6c3eec72011-05-05 14:16:22 +10001126 return 0;
1127 }
1128 }
1129
1130 if (mux_listener_channel != NULL) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001131 channel_free(ssh, mux_listener_channel);
Damien Miller6c3eec72011-05-05 14:16:22 +10001132 client_stop_mux();
Darren Tuckera627d422013-06-02 07:31:17 +10001133 free(options.control_path);
Damien Miller6c3eec72011-05-05 14:16:22 +10001134 options.control_path = NULL;
1135 mux_listener_channel = NULL;
1136 muxserver_sock = -1;
1137 }
1138
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001139 reply_ok(reply, rid);
Damien Miller6c3eec72011-05-05 14:16:22 +10001140 return 0;
1141}
1142
markus@openbsd.org8d057842016-09-30 09:19:13 +00001143static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001144process_mux_proxy(struct ssh *ssh, u_int rid,
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001145 Channel *c, struct sshbuf *m, struct sshbuf *reply)
markus@openbsd.org8d057842016-09-30 09:19:13 +00001146{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001147 int r;
1148
markus@openbsd.org8d057842016-09-30 09:19:13 +00001149 debug("%s: channel %d: proxy request", __func__, c->self);
1150
1151 c->mux_rcb = channel_proxy_downstream;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001152 if ((r = sshbuf_put_u32(reply, MUX_S_PROXY)) != 0 ||
1153 (r = sshbuf_put_u32(reply, rid)) != 0)
1154 fatal("%s: reply: %s", __func__, ssh_err(r));
markus@openbsd.org8d057842016-09-30 09:19:13 +00001155
1156 return 0;
1157}
1158
Damien Millere1537f92010-01-26 13:26:22 +11001159/* Channel callbacks fired on read/write from mux slave fd */
1160static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001161mux_master_read_cb(struct ssh *ssh, Channel *c)
Damien Millere1537f92010-01-26 13:26:22 +11001162{
1163 struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001164 struct sshbuf *in = NULL, *out = NULL;
1165 u_int type, rid, i;
1166 int r, ret = -1;
1167
1168 if ((out = sshbuf_new()) == NULL)
1169 fatal("%s: sshbuf_new", __func__);
Damien Millere1537f92010-01-26 13:26:22 +11001170
1171 /* Setup ctx and */
1172 if (c->mux_ctx == NULL) {
Damien Millerc094d1e2010-06-26 09:36:34 +10001173 state = xcalloc(1, sizeof(*state));
Damien Millere1537f92010-01-26 13:26:22 +11001174 c->mux_ctx = state;
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001175 channel_register_cleanup(ssh, c->self,
Damien Millere1537f92010-01-26 13:26:22 +11001176 mux_master_control_cleanup_cb, 0);
1177
1178 /* Send hello */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001179 if ((r = sshbuf_put_u32(out, MUX_MSG_HELLO)) != 0 ||
1180 (r = sshbuf_put_u32(out, SSHMUX_VER)) != 0)
1181 fatal("%s: reply: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001182 /* no extensions */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001183 if ((r = sshbuf_put_stringb(c->output, out)) != 0)
1184 fatal("%s: sshbuf_put_stringb: %s",
1185 __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001186 debug3("%s: channel %d: hello sent", __func__, c->self);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001187 ret = 0;
1188 goto out;
Damien Millere1537f92010-01-26 13:26:22 +11001189 }
1190
Damien Millere1537f92010-01-26 13:26:22 +11001191 /* Channel code ensures that we receive whole packets */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001192 if ((r = sshbuf_froms(c->input, &in)) != 0) {
Damien Millere1537f92010-01-26 13:26:22 +11001193 malf:
1194 error("%s: malformed message", __func__);
1195 goto out;
1196 }
Damien Millere1537f92010-01-26 13:26:22 +11001197
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001198 if ((r = sshbuf_get_u32(in, &type)) != 0)
Damien Millere1537f92010-01-26 13:26:22 +11001199 goto malf;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001200 debug3("%s: channel %d packet type 0x%08x len %zu",
1201 __func__, c->self, type, sshbuf_len(in));
Damien Millere1537f92010-01-26 13:26:22 +11001202
1203 if (type == MUX_MSG_HELLO)
1204 rid = 0;
1205 else {
1206 if (!state->hello_rcvd) {
1207 error("%s: expected MUX_MSG_HELLO(0x%08x), "
1208 "received 0x%08x", __func__, MUX_MSG_HELLO, type);
1209 goto out;
1210 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001211 if ((r = sshbuf_get_u32(in, &rid)) != 0)
Damien Millere1537f92010-01-26 13:26:22 +11001212 goto malf;
1213 }
1214
1215 for (i = 0; mux_master_handlers[i].handler != NULL; i++) {
1216 if (type == mux_master_handlers[i].type) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001217 ret = mux_master_handlers[i].handler(ssh, rid,
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001218 c, in, out);
Damien Millere1537f92010-01-26 13:26:22 +11001219 break;
1220 }
1221 }
1222 if (mux_master_handlers[i].handler == NULL) {
1223 error("%s: unsupported mux message 0x%08x", __func__, type);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001224 reply_error(out, MUX_S_FAILURE, rid, "unsupported request");
Damien Millere1537f92010-01-26 13:26:22 +11001225 ret = 0;
1226 }
1227 /* Enqueue reply packet */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001228 if (sshbuf_len(out) != 0) {
1229 if ((r = sshbuf_put_stringb(c->output, out)) != 0)
1230 fatal("%s: sshbuf_put_stringb: %s",
1231 __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001232 }
1233 out:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001234 sshbuf_free(in);
1235 sshbuf_free(out);
Damien Millere1537f92010-01-26 13:26:22 +11001236 return ret;
1237}
1238
1239void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001240mux_exit_message(struct ssh *ssh, Channel *c, int exitval)
Damien Millere1537f92010-01-26 13:26:22 +11001241{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001242 struct sshbuf *m;
Damien Millere1537f92010-01-26 13:26:22 +11001243 Channel *mux_chan;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001244 int r;
Damien Millere1537f92010-01-26 13:26:22 +11001245
Damien Millerbc02f162013-04-23 19:25:49 +10001246 debug3("%s: channel %d: exit message, exitval %d", __func__, c->self,
Damien Millere1537f92010-01-26 13:26:22 +11001247 exitval);
1248
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001249 if ((mux_chan = channel_by_id(ssh, c->ctl_chan)) == NULL)
Damien Millere1537f92010-01-26 13:26:22 +11001250 fatal("%s: channel %d missing mux channel %d",
1251 __func__, c->self, c->ctl_chan);
1252
1253 /* Append exit message packet to control socket output queue */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001254 if ((m = sshbuf_new()) == NULL)
1255 fatal("%s: sshbuf_new", __func__);
1256 if ((r = sshbuf_put_u32(m, MUX_S_EXIT_MESSAGE)) != 0 ||
1257 (r = sshbuf_put_u32(m, c->self)) != 0 ||
1258 (r = sshbuf_put_u32(m, exitval)) != 0 ||
1259 (r = sshbuf_put_stringb(mux_chan->output, m)) != 0)
1260 fatal("%s: reply: %s", __func__, ssh_err(r));
1261 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11001262}
Damien Millerb1cbfa22008-05-19 16:00:08 +10001263
Damien Miller555f3b82011-05-15 08:48:05 +10001264void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001265mux_tty_alloc_failed(struct ssh *ssh, Channel *c)
Damien Miller555f3b82011-05-15 08:48:05 +10001266{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001267 struct sshbuf *m;
Damien Miller555f3b82011-05-15 08:48:05 +10001268 Channel *mux_chan;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001269 int r;
Damien Miller555f3b82011-05-15 08:48:05 +10001270
1271 debug3("%s: channel %d: TTY alloc failed", __func__, c->self);
1272
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001273 if ((mux_chan = channel_by_id(ssh, c->ctl_chan)) == NULL)
Damien Miller555f3b82011-05-15 08:48:05 +10001274 fatal("%s: channel %d missing mux channel %d",
1275 __func__, c->self, c->ctl_chan);
1276
1277 /* Append exit message packet to control socket output queue */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001278 if ((m = sshbuf_new()) == NULL)
1279 fatal("%s: sshbuf_new", __func__);
1280 if ((r = sshbuf_put_u32(m, MUX_S_TTY_ALLOC_FAIL)) != 0 ||
1281 (r = sshbuf_put_u32(m, c->self)) != 0 ||
1282 (r = sshbuf_put_stringb(mux_chan->output, m)) != 0)
1283 fatal("%s: reply: %s", __func__, ssh_err(r));
1284 sshbuf_free(m);
Damien Miller555f3b82011-05-15 08:48:05 +10001285}
1286
Damien Millerb1cbfa22008-05-19 16:00:08 +10001287/* Prepare a mux master to listen on a Unix domain socket. */
1288void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001289muxserver_listen(struct ssh *ssh)
Damien Millerb1cbfa22008-05-19 16:00:08 +10001290{
Damien Millerb1cbfa22008-05-19 16:00:08 +10001291 mode_t old_umask;
Damien Miller603134e2010-09-24 22:07:55 +10001292 char *orig_control_path = options.control_path;
1293 char rbuf[16+1];
1294 u_int i, r;
Damien Millerf42f7682014-07-18 15:03:27 +10001295 int oerrno;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001296
1297 if (options.control_path == NULL ||
1298 options.control_master == SSHCTL_MASTER_NO)
1299 return;
1300
1301 debug("setting up multiplex master socket");
1302
Damien Miller603134e2010-09-24 22:07:55 +10001303 /*
1304 * Use a temporary path before listen so we can pseudo-atomically
1305 * establish the listening socket in its final location to avoid
1306 * other processes racing in between bind() and listen() and hitting
1307 * an unready socket.
1308 */
1309 for (i = 0; i < sizeof(rbuf) - 1; i++) {
1310 r = arc4random_uniform(26+26+10);
1311 rbuf[i] = (r < 26) ? 'a' + r :
1312 (r < 26*2) ? 'A' + r - 26 :
1313 '0' + r - 26 - 26;
1314 }
1315 rbuf[sizeof(rbuf) - 1] = '\0';
1316 options.control_path = NULL;
1317 xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf);
1318 debug3("%s: temporary control path %s", __func__, options.control_path);
1319
Damien Millerb1cbfa22008-05-19 16:00:08 +10001320 old_umask = umask(0177);
Damien Miller7acefbb2014-07-18 14:11:24 +10001321 muxserver_sock = unix_listener(options.control_path, 64, 0);
Damien Millerf42f7682014-07-18 15:03:27 +10001322 oerrno = errno;
Damien Miller7acefbb2014-07-18 14:11:24 +10001323 umask(old_umask);
1324 if (muxserver_sock < 0) {
Damien Millerf42f7682014-07-18 15:03:27 +10001325 if (oerrno == EINVAL || oerrno == EADDRINUSE) {
Darren Tuckerca19bfe2008-06-13 10:24:03 +10001326 error("ControlSocket %s already exists, "
1327 "disabling multiplexing", options.control_path);
Damien Miller603134e2010-09-24 22:07:55 +10001328 disable_mux_master:
Damien Miller60432d82011-05-15 08:34:46 +10001329 if (muxserver_sock != -1) {
1330 close(muxserver_sock);
1331 muxserver_sock = -1;
1332 }
Darren Tuckera627d422013-06-02 07:31:17 +10001333 free(orig_control_path);
1334 free(options.control_path);
Darren Tuckerca19bfe2008-06-13 10:24:03 +10001335 options.control_path = NULL;
1336 options.control_master = SSHCTL_MASTER_NO;
1337 return;
Damien Miller7acefbb2014-07-18 14:11:24 +10001338 } else {
1339 /* unix_listener() logs the error */
1340 cleanup_exit(255);
1341 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10001342 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10001343
Damien Miller603134e2010-09-24 22:07:55 +10001344 /* Now atomically "move" the mux socket into position */
1345 if (link(options.control_path, orig_control_path) != 0) {
1346 if (errno != EEXIST) {
djm@openbsd.org95687f52016-04-01 02:34:10 +00001347 fatal("%s: link mux listener %s => %s: %s", __func__,
Damien Miller603134e2010-09-24 22:07:55 +10001348 options.control_path, orig_control_path,
1349 strerror(errno));
1350 }
1351 error("ControlSocket %s already exists, disabling multiplexing",
1352 orig_control_path);
Damien Miller603134e2010-09-24 22:07:55 +10001353 unlink(options.control_path);
1354 goto disable_mux_master;
1355 }
1356 unlink(options.control_path);
Darren Tuckera627d422013-06-02 07:31:17 +10001357 free(options.control_path);
Damien Miller603134e2010-09-24 22:07:55 +10001358 options.control_path = orig_control_path;
1359
Damien Millerb1cbfa22008-05-19 16:00:08 +10001360 set_nonblock(muxserver_sock);
Damien Millere1537f92010-01-26 13:26:22 +11001361
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001362 mux_listener_channel = channel_new(ssh, "mux listener",
Damien Millere1537f92010-01-26 13:26:22 +11001363 SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1,
1364 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
Damien Miller603134e2010-09-24 22:07:55 +10001365 0, options.control_path, 1);
Damien Millere1537f92010-01-26 13:26:22 +11001366 mux_listener_channel->mux_rcb = mux_master_read_cb;
1367 debug3("%s: mux listener channel %d fd %d", __func__,
1368 mux_listener_channel->self, mux_listener_channel->sock);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001369}
1370
1371/* Callback on open confirmation in mux master for a mux client session. */
1372static void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001373mux_session_confirm(struct ssh *ssh, int id, int success, void *arg)
Damien Millerb1cbfa22008-05-19 16:00:08 +10001374{
1375 struct mux_session_confirm_ctx *cctx = arg;
1376 const char *display;
Damien Millerd530f5f2010-05-21 14:57:10 +10001377 Channel *c, *cc;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001378 int i, r;
1379 struct sshbuf *reply;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001380
1381 if (cctx == NULL)
1382 fatal("%s: cctx == NULL", __func__);
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001383 if ((c = channel_by_id(ssh, id)) == NULL)
Damien Millerb1cbfa22008-05-19 16:00:08 +10001384 fatal("%s: no channel for id %d", __func__, id);
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001385 if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
Damien Millerd530f5f2010-05-21 14:57:10 +10001386 fatal("%s: channel %d lacks control channel %d", __func__,
1387 id, c->ctl_chan);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001388 if ((reply = sshbuf_new()) == NULL)
1389 fatal("%s: sshbuf_new", __func__);
Damien Millerd530f5f2010-05-21 14:57:10 +10001390
1391 if (!success) {
1392 debug3("%s: sending failure reply", __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001393 reply_error(reply, MUX_S_FAILURE, cctx->rid,
1394 "Session open refused by peer");
Damien Millerd530f5f2010-05-21 14:57:10 +10001395 goto done;
1396 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10001397
1398 display = getenv("DISPLAY");
1399 if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
1400 char *proto, *data;
Damien Miller1ab6a512010-06-26 10:02:24 +10001401
Damien Millerb1cbfa22008-05-19 16:00:08 +10001402 /* Get reasonable local authentication information. */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001403 if (client_x11_get_proto(ssh, display, options.xauth_location,
Damien Miller1ab6a512010-06-26 10:02:24 +10001404 options.forward_x11_trusted, options.forward_x11_timeout,
djm@openbsd.orged4ce822016-01-13 23:04:47 +00001405 &proto, &data) == 0) {
1406 /* Request forwarding with authentication spoofing. */
1407 debug("Requesting X11 forwarding with authentication "
1408 "spoofing.");
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001409 x11_request_forwarding_with_spoofing(ssh, id,
1410 display, proto, data, 1);
djm@openbsd.orged4ce822016-01-13 23:04:47 +00001411 /* XXX exit_on_forward_failure */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001412 client_expect_confirm(ssh, id, "X11 forwarding",
djm@openbsd.orged4ce822016-01-13 23:04:47 +00001413 CONFIRM_WARN);
1414 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10001415 }
1416
1417 if (cctx->want_agent_fwd && options.forward_agent) {
1418 debug("Requesting authentication agent forwarding.");
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001419 channel_request_start(ssh, id, "auth-agent-req@openssh.com", 0);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001420 packet_send();
1421 }
1422
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001423 client_session2_setup(ssh, id, cctx->want_tty, cctx->want_subsys,
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001424 cctx->term, &cctx->tio, c->rfd, cctx->cmd, cctx->env);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001425
Damien Millerd530f5f2010-05-21 14:57:10 +10001426 debug3("%s: sending success reply", __func__);
1427 /* prepare reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001428 if ((r = sshbuf_put_u32(reply, MUX_S_SESSION_OPENED)) != 0 ||
1429 (r = sshbuf_put_u32(reply, cctx->rid)) != 0 ||
1430 (r = sshbuf_put_u32(reply, c->self)) != 0)
1431 fatal("%s: reply: %s", __func__, ssh_err(r));
Damien Millerd530f5f2010-05-21 14:57:10 +10001432
1433 done:
1434 /* Send reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001435 if ((r = sshbuf_put_stringb(cc->output, reply)) != 0)
1436 fatal("%s: sshbuf_put_stringb: %s", __func__, ssh_err(r));
1437 sshbuf_free(reply);
Damien Millerd530f5f2010-05-21 14:57:10 +10001438
1439 if (cc->mux_pause <= 0)
1440 fatal("%s: mux_pause %d", __func__, cc->mux_pause);
1441 cc->mux_pause = 0; /* start processing messages again */
Damien Millerb1cbfa22008-05-19 16:00:08 +10001442 c->open_confirm_ctx = NULL;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001443 sshbuf_free(cctx->cmd);
Darren Tuckera627d422013-06-02 07:31:17 +10001444 free(cctx->term);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001445 if (cctx->env != NULL) {
1446 for (i = 0; cctx->env[i] != NULL; i++)
Darren Tuckera627d422013-06-02 07:31:17 +10001447 free(cctx->env[i]);
1448 free(cctx->env);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001449 }
Darren Tuckera627d422013-06-02 07:31:17 +10001450 free(cctx);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001451}
1452
Damien Millerb1cbfa22008-05-19 16:00:08 +10001453/* ** Multiplexing client support */
1454
1455/* Exit signal handler */
1456static void
1457control_client_sighandler(int signo)
1458{
1459 muxclient_terminate = signo;
1460}
1461
1462/*
1463 * Relay signal handler - used to pass some signals from mux client to
1464 * mux master.
1465 */
1466static void
1467control_client_sigrelay(int signo)
1468{
1469 int save_errno = errno;
1470
1471 if (muxserver_pid > 1)
1472 kill(muxserver_pid, signo);
1473
1474 errno = save_errno;
1475}
1476
Damien Millerb1cbfa22008-05-19 16:00:08 +10001477static int
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001478mux_client_read(int fd, struct sshbuf *b, size_t need)
Damien Millerb1cbfa22008-05-19 16:00:08 +10001479{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001480 size_t have;
Damien Millere1537f92010-01-26 13:26:22 +11001481 ssize_t len;
1482 u_char *p;
1483 struct pollfd pfd;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001484 int r;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001485
Damien Millere1537f92010-01-26 13:26:22 +11001486 pfd.fd = fd;
1487 pfd.events = POLLIN;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001488 if ((r = sshbuf_reserve(b, need, &p)) != 0)
1489 fatal("%s: reserve: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001490 for (have = 0; have < need; ) {
1491 if (muxclient_terminate) {
1492 errno = EINTR;
1493 return -1;
1494 }
1495 len = read(fd, p + have, need - have);
1496 if (len < 0) {
1497 switch (errno) {
1498#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1499 case EWOULDBLOCK:
1500#endif
1501 case EAGAIN:
1502 (void)poll(&pfd, 1, -1);
1503 /* FALLTHROUGH */
1504 case EINTR:
1505 continue;
1506 default:
1507 return -1;
1508 }
1509 }
1510 if (len == 0) {
1511 errno = EPIPE;
1512 return -1;
1513 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001514 have += (size_t)len;
Damien Millere1537f92010-01-26 13:26:22 +11001515 }
1516 return 0;
1517}
Damien Millerb1cbfa22008-05-19 16:00:08 +10001518
Damien Millere1537f92010-01-26 13:26:22 +11001519static int
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001520mux_client_write_packet(int fd, struct sshbuf *m)
Damien Millere1537f92010-01-26 13:26:22 +11001521{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001522 struct sshbuf *queue;
Damien Millere1537f92010-01-26 13:26:22 +11001523 u_int have, need;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001524 int r, oerrno, len;
1525 const u_char *ptr;
Damien Millere1537f92010-01-26 13:26:22 +11001526 struct pollfd pfd;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001527
Damien Millere1537f92010-01-26 13:26:22 +11001528 pfd.fd = fd;
1529 pfd.events = POLLOUT;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001530 if ((queue = sshbuf_new()) == NULL)
1531 fatal("%s: sshbuf_new", __func__);
1532 if ((r = sshbuf_put_stringb(queue, m)) != 0)
1533 fatal("%s: sshbuf_put_stringb: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001534
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001535 need = sshbuf_len(queue);
1536 ptr = sshbuf_ptr(queue);
Damien Millere1537f92010-01-26 13:26:22 +11001537
1538 for (have = 0; have < need; ) {
1539 if (muxclient_terminate) {
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001540 sshbuf_free(queue);
Damien Millere1537f92010-01-26 13:26:22 +11001541 errno = EINTR;
1542 return -1;
1543 }
1544 len = write(fd, ptr + have, need - have);
1545 if (len < 0) {
1546 switch (errno) {
1547#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1548 case EWOULDBLOCK:
1549#endif
1550 case EAGAIN:
1551 (void)poll(&pfd, 1, -1);
1552 /* FALLTHROUGH */
1553 case EINTR:
1554 continue;
1555 default:
1556 oerrno = errno;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001557 sshbuf_free(queue);
Damien Millere1537f92010-01-26 13:26:22 +11001558 errno = oerrno;
1559 return -1;
1560 }
1561 }
1562 if (len == 0) {
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001563 sshbuf_free(queue);
Damien Millere1537f92010-01-26 13:26:22 +11001564 errno = EPIPE;
1565 return -1;
1566 }
1567 have += (u_int)len;
1568 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001569 sshbuf_free(queue);
Damien Millere1537f92010-01-26 13:26:22 +11001570 return 0;
1571}
1572
1573static int
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001574mux_client_read_packet(int fd, struct sshbuf *m)
Damien Millere1537f92010-01-26 13:26:22 +11001575{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001576 struct sshbuf *queue;
1577 size_t need, have;
Damien Miller633de332014-05-15 13:48:26 +10001578 const u_char *ptr;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001579 int r, oerrno;
Damien Millere1537f92010-01-26 13:26:22 +11001580
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001581 if ((queue = sshbuf_new()) == NULL)
1582 fatal("%s: sshbuf_new", __func__);
1583 if (mux_client_read(fd, queue, 4) != 0) {
Damien Millere1537f92010-01-26 13:26:22 +11001584 if ((oerrno = errno) == EPIPE)
Darren Tucker746e9062013-06-06 08:20:13 +10001585 debug3("%s: read header failed: %s", __func__,
1586 strerror(errno));
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001587 sshbuf_free(queue);
Damien Millere1537f92010-01-26 13:26:22 +11001588 errno = oerrno;
1589 return -1;
1590 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001591 need = PEEK_U32(sshbuf_ptr(queue));
1592 if (mux_client_read(fd, queue, need) != 0) {
Damien Millere1537f92010-01-26 13:26:22 +11001593 oerrno = errno;
1594 debug3("%s: read body failed: %s", __func__, strerror(errno));
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001595 sshbuf_free(queue);
Damien Millere1537f92010-01-26 13:26:22 +11001596 errno = oerrno;
1597 return -1;
1598 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001599 if ((r = sshbuf_get_string_direct(queue, &ptr, &have)) != 0 ||
1600 (r = sshbuf_put(m, ptr, have)) != 0)
1601 fatal("%s: buffer error: %s", __func__, ssh_err(r));
1602 sshbuf_free(queue);
Damien Millere1537f92010-01-26 13:26:22 +11001603 return 0;
1604}
1605
1606static int
1607mux_client_hello_exchange(int fd)
1608{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001609 struct sshbuf *m;
Damien Millere1537f92010-01-26 13:26:22 +11001610 u_int type, ver;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001611 int r, ret = -1;
Damien Millere1537f92010-01-26 13:26:22 +11001612
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001613 if ((m = sshbuf_new()) == NULL)
1614 fatal("%s: sshbuf_new", __func__);
1615 if ((r = sshbuf_put_u32(m, MUX_MSG_HELLO)) != 0 ||
1616 (r = sshbuf_put_u32(m, SSHMUX_VER)) != 0)
1617 fatal("%s: hello: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001618 /* no extensions */
1619
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001620 if (mux_client_write_packet(fd, m) != 0) {
djm@openbsd.org5b2f34a2017-06-09 06:47:13 +00001621 debug("%s: write packet: %s", __func__, strerror(errno));
1622 goto out;
1623 }
Damien Millere1537f92010-01-26 13:26:22 +11001624
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001625 sshbuf_reset(m);
Damien Millere1537f92010-01-26 13:26:22 +11001626
1627 /* Read their HELLO */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001628 if (mux_client_read_packet(fd, m) != 0) {
djm@openbsd.org5b2f34a2017-06-09 06:47:13 +00001629 debug("%s: read packet failed", __func__);
1630 goto out;
Damien Millere1537f92010-01-26 13:26:22 +11001631 }
1632
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001633 if ((r = sshbuf_get_u32(m, &type)) != 0)
1634 fatal("%s: decode type: %s", __func__, ssh_err(r));
djm@openbsd.org5b2f34a2017-06-09 06:47:13 +00001635 if (type != MUX_MSG_HELLO) {
1636 error("%s: expected HELLO (%u) received %u",
Damien Millere1537f92010-01-26 13:26:22 +11001637 __func__, MUX_MSG_HELLO, type);
djm@openbsd.org5b2f34a2017-06-09 06:47:13 +00001638 goto out;
1639 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001640 if ((r = sshbuf_get_u32(m, &ver)) != 0)
1641 fatal("%s: decode version: %s", __func__, ssh_err(r));
djm@openbsd.org5b2f34a2017-06-09 06:47:13 +00001642 if (ver != SSHMUX_VER) {
1643 error("Unsupported multiplexing protocol version %d "
Damien Millere1537f92010-01-26 13:26:22 +11001644 "(expected %d)", ver, SSHMUX_VER);
djm@openbsd.org5b2f34a2017-06-09 06:47:13 +00001645 goto out;
1646 }
Damien Millere1537f92010-01-26 13:26:22 +11001647 debug2("%s: master version %u", __func__, ver);
1648 /* No extensions are presently defined */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001649 while (sshbuf_len(m) > 0) {
1650 char *name = NULL;
Damien Millere1537f92010-01-26 13:26:22 +11001651
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001652 if ((r = sshbuf_get_cstring(m, &name, NULL)) != 0 ||
1653 (r = sshbuf_skip_string(m)) != 0) { /* value */
1654 error("%s: malformed extension: %s",
1655 __func__, ssh_err(r));
1656 goto out;
1657 }
Damien Millere1537f92010-01-26 13:26:22 +11001658 debug2("Unrecognised master extension \"%s\"", name);
Darren Tuckera627d422013-06-02 07:31:17 +10001659 free(name);
Damien Millere1537f92010-01-26 13:26:22 +11001660 }
djm@openbsd.org5b2f34a2017-06-09 06:47:13 +00001661 /* success */
1662 ret = 0;
1663 out:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001664 sshbuf_free(m);
djm@openbsd.org5b2f34a2017-06-09 06:47:13 +00001665 return ret;
Damien Millere1537f92010-01-26 13:26:22 +11001666}
1667
1668static u_int
1669mux_client_request_alive(int fd)
1670{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001671 struct sshbuf *m;
Damien Millere1537f92010-01-26 13:26:22 +11001672 char *e;
1673 u_int pid, type, rid;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001674 int r;
Damien Millere1537f92010-01-26 13:26:22 +11001675
1676 debug3("%s: entering", __func__);
1677
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001678 if ((m = sshbuf_new()) == NULL)
1679 fatal("%s: sshbuf_new", __func__);
1680 if ((r = sshbuf_put_u32(m, MUX_C_ALIVE_CHECK)) != 0 ||
1681 (r = sshbuf_put_u32(m, muxclient_request_id)) != 0)
1682 fatal("%s: request: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001683
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001684 if (mux_client_write_packet(fd, m) != 0)
Damien Millere1537f92010-01-26 13:26:22 +11001685 fatal("%s: write packet: %s", __func__, strerror(errno));
1686
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001687 sshbuf_reset(m);
Damien Millere1537f92010-01-26 13:26:22 +11001688
1689 /* Read their reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001690 if (mux_client_read_packet(fd, m) != 0) {
1691 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11001692 return 0;
1693 }
1694
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001695 if ((r = sshbuf_get_u32(m, &type)) != 0)
1696 fatal("%s: decode type: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001697 if (type != MUX_S_ALIVE) {
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001698 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
1699 fatal("%s: decode error: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001700 fatal("%s: master returned error: %s", __func__, e);
1701 }
1702
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001703 if ((r = sshbuf_get_u32(m, &rid)) != 0)
1704 fatal("%s: decode remote ID: %s", __func__, ssh_err(r));
1705 if (rid != muxclient_request_id)
Damien Millere1537f92010-01-26 13:26:22 +11001706 fatal("%s: out of sequence reply: my id %u theirs %u",
1707 __func__, muxclient_request_id, rid);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001708 if ((r = sshbuf_get_u32(m, &pid)) != 0)
1709 fatal("%s: decode PID: %s", __func__, ssh_err(r));
1710 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11001711
1712 debug3("%s: done pid = %u", __func__, pid);
1713
1714 muxclient_request_id++;
1715
1716 return pid;
1717}
1718
1719static void
1720mux_client_request_terminate(int fd)
1721{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001722 struct sshbuf *m;
Damien Millere1537f92010-01-26 13:26:22 +11001723 char *e;
1724 u_int type, rid;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001725 int r;
Damien Millere1537f92010-01-26 13:26:22 +11001726
1727 debug3("%s: entering", __func__);
1728
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001729 if ((m = sshbuf_new()) == NULL)
1730 fatal("%s: sshbuf_new", __func__);
1731 if ((r = sshbuf_put_u32(m, MUX_C_TERMINATE)) != 0 ||
1732 (r = sshbuf_put_u32(m, muxclient_request_id)) != 0)
1733 fatal("%s: request: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001734
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001735 if (mux_client_write_packet(fd, m) != 0)
Damien Millere1537f92010-01-26 13:26:22 +11001736 fatal("%s: write packet: %s", __func__, strerror(errno));
1737
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001738 sshbuf_reset(m);
Damien Millere1537f92010-01-26 13:26:22 +11001739
1740 /* Read their reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001741 if (mux_client_read_packet(fd, m) != 0) {
Damien Millere1537f92010-01-26 13:26:22 +11001742 /* Remote end exited already */
1743 if (errno == EPIPE) {
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001744 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11001745 return;
1746 }
1747 fatal("%s: read from master failed: %s",
1748 __func__, strerror(errno));
1749 }
1750
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001751 if ((r = sshbuf_get_u32(m, &type)) != 0 ||
1752 (r = sshbuf_get_u32(m, &rid)) != 0)
1753 fatal("%s: decode: %s", __func__, ssh_err(r));
1754 if (rid != muxclient_request_id)
Damien Millere1537f92010-01-26 13:26:22 +11001755 fatal("%s: out of sequence reply: my id %u theirs %u",
1756 __func__, muxclient_request_id, rid);
1757 switch (type) {
1758 case MUX_S_OK:
1759 break;
1760 case MUX_S_PERMISSION_DENIED:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001761 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
1762 fatal("%s: decode error: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001763 fatal("Master refused termination request: %s", e);
1764 case MUX_S_FAILURE:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001765 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
1766 fatal("%s: decode error: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001767 fatal("%s: termination request failed: %s", __func__, e);
1768 default:
1769 fatal("%s: unexpected response from master 0x%08x",
1770 __func__, type);
1771 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001772 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11001773 muxclient_request_id++;
1774}
1775
1776static int
Damien Miller7acefbb2014-07-18 14:11:24 +10001777mux_client_forward(int fd, int cancel_flag, u_int ftype, struct Forward *fwd)
Damien Millere1537f92010-01-26 13:26:22 +11001778{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001779 struct sshbuf *m;
Damien Millere1537f92010-01-26 13:26:22 +11001780 char *e, *fwd_desc;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001781 const char *lhost, *chost;
Damien Millere1537f92010-01-26 13:26:22 +11001782 u_int type, rid;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001783 int r;
Damien Millere1537f92010-01-26 13:26:22 +11001784
1785 fwd_desc = format_forward(ftype, fwd);
Damien Millerf6dff7c2011-09-22 21:38:52 +10001786 debug("Requesting %s %s",
1787 cancel_flag ? "cancellation of" : "forwarding of", fwd_desc);
Darren Tuckera627d422013-06-02 07:31:17 +10001788 free(fwd_desc);
Damien Millere1537f92010-01-26 13:26:22 +11001789
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001790 type = cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD;
1791 if (fwd->listen_path != NULL)
1792 lhost = fwd->listen_path;
1793 else if (fwd->listen_host == NULL)
1794 lhost = "";
1795 else if (*fwd->listen_host == '\0')
1796 lhost = "*";
1797 else
1798 lhost = fwd->listen_host;
Damien Millere1537f92010-01-26 13:26:22 +11001799
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001800 if (fwd->connect_path != NULL)
1801 chost = fwd->connect_path;
1802 else if (fwd->connect_host == NULL)
1803 chost = "";
1804 else
1805 chost = fwd->connect_host;
1806
1807 if ((m = sshbuf_new()) == NULL)
1808 fatal("%s: sshbuf_new", __func__);
1809 if ((r = sshbuf_put_u32(m, type)) != 0 ||
1810 (r = sshbuf_put_u32(m, muxclient_request_id)) != 0 ||
1811 (r = sshbuf_put_u32(m, ftype)) != 0 ||
1812 (r = sshbuf_put_cstring(m, lhost)) != 0 ||
1813 (r = sshbuf_put_u32(m, fwd->listen_port)) != 0 ||
1814 (r = sshbuf_put_cstring(m, chost)) != 0 ||
1815 (r = sshbuf_put_u32(m, fwd->connect_port)) != 0)
1816 fatal("%s: request: %s", __func__, ssh_err(r));
1817
1818 if (mux_client_write_packet(fd, m) != 0)
Damien Millere1537f92010-01-26 13:26:22 +11001819 fatal("%s: write packet: %s", __func__, strerror(errno));
1820
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001821 sshbuf_reset(m);
Damien Millere1537f92010-01-26 13:26:22 +11001822
1823 /* Read their reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001824 if (mux_client_read_packet(fd, m) != 0) {
1825 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11001826 return -1;
1827 }
1828
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001829 if ((r = sshbuf_get_u32(m, &type)) != 0 ||
1830 (r = sshbuf_get_u32(m, &rid)) != 0)
1831 fatal("%s: decode: %s", __func__, ssh_err(r));
1832 if (rid != muxclient_request_id)
Damien Millere1537f92010-01-26 13:26:22 +11001833 fatal("%s: out of sequence reply: my id %u theirs %u",
1834 __func__, muxclient_request_id, rid);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001835
Damien Millere1537f92010-01-26 13:26:22 +11001836 switch (type) {
1837 case MUX_S_OK:
1838 break;
Damien Miller388f6fc2010-05-21 14:57:35 +10001839 case MUX_S_REMOTE_PORT:
Damien Millerf6dff7c2011-09-22 21:38:52 +10001840 if (cancel_flag)
1841 fatal("%s: got MUX_S_REMOTE_PORT for cancel", __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001842 if ((r = sshbuf_get_u32(m, &fwd->allocated_port)) != 0)
1843 fatal("%s: decode port: %s", __func__, ssh_err(r));
djm@openbsd.org8312cfb2015-05-01 04:01:58 +00001844 verbose("Allocated port %u for remote forward to %s:%d",
Damien Miller388f6fc2010-05-21 14:57:35 +10001845 fwd->allocated_port,
1846 fwd->connect_host ? fwd->connect_host : "",
1847 fwd->connect_port);
1848 if (muxclient_command == SSHMUX_COMMAND_FORWARD)
djm@openbsd.orgb1d38a32015-10-15 23:51:40 +00001849 fprintf(stdout, "%i\n", fwd->allocated_port);
Damien Miller388f6fc2010-05-21 14:57:35 +10001850 break;
Damien Millere1537f92010-01-26 13:26:22 +11001851 case MUX_S_PERMISSION_DENIED:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001852 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
1853 fatal("%s: decode error: %s", __func__, ssh_err(r));
1854 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11001855 error("Master refused forwarding request: %s", e);
1856 return -1;
1857 case MUX_S_FAILURE:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001858 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
1859 fatal("%s: decode error: %s", __func__, ssh_err(r));
1860 sshbuf_free(m);
Damien Miller445c9a52011-01-14 12:01:29 +11001861 error("%s: forwarding request failed: %s", __func__, e);
Damien Millere1537f92010-01-26 13:26:22 +11001862 return -1;
1863 default:
1864 fatal("%s: unexpected response from master 0x%08x",
1865 __func__, type);
1866 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001867 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11001868
1869 muxclient_request_id++;
1870 return 0;
1871}
1872
1873static int
Damien Millerf6dff7c2011-09-22 21:38:52 +10001874mux_client_forwards(int fd, int cancel_flag)
Damien Millere1537f92010-01-26 13:26:22 +11001875{
Damien Millerf6dff7c2011-09-22 21:38:52 +10001876 int i, ret = 0;
Damien Millere1537f92010-01-26 13:26:22 +11001877
Damien Millerf6dff7c2011-09-22 21:38:52 +10001878 debug3("%s: %s forwardings: %d local, %d remote", __func__,
1879 cancel_flag ? "cancel" : "request",
Damien Millere1537f92010-01-26 13:26:22 +11001880 options.num_local_forwards, options.num_remote_forwards);
1881
1882 /* XXX ExitOnForwardingFailure */
1883 for (i = 0; i < options.num_local_forwards; i++) {
Damien Millerf6dff7c2011-09-22 21:38:52 +10001884 if (mux_client_forward(fd, cancel_flag,
Damien Millere1537f92010-01-26 13:26:22 +11001885 options.local_forwards[i].connect_port == 0 ?
1886 MUX_FWD_DYNAMIC : MUX_FWD_LOCAL,
1887 options.local_forwards + i) != 0)
Damien Millerf6dff7c2011-09-22 21:38:52 +10001888 ret = -1;
Damien Millere1537f92010-01-26 13:26:22 +11001889 }
1890 for (i = 0; i < options.num_remote_forwards; i++) {
Damien Millerf6dff7c2011-09-22 21:38:52 +10001891 if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE,
Damien Millere1537f92010-01-26 13:26:22 +11001892 options.remote_forwards + i) != 0)
Damien Millerf6dff7c2011-09-22 21:38:52 +10001893 ret = -1;
Damien Millere1537f92010-01-26 13:26:22 +11001894 }
Damien Millerf6dff7c2011-09-22 21:38:52 +10001895 return ret;
Damien Millere1537f92010-01-26 13:26:22 +11001896}
1897
1898static int
1899mux_client_request_session(int fd)
1900{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001901 struct sshbuf *m;
1902 char *e;
1903 const char *term;
1904 u_int echar, rid, sid, esid, exitval, type, exitval_seen;
Damien Millere1537f92010-01-26 13:26:22 +11001905 extern char **environ;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001906 int r, i, devnull, rawmode;
Damien Millere1537f92010-01-26 13:26:22 +11001907
1908 debug3("%s: entering", __func__);
1909
1910 if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
1911 error("%s: master alive request failed", __func__);
1912 return -1;
1913 }
1914
1915 signal(SIGPIPE, SIG_IGN);
1916
1917 if (stdin_null_flag) {
1918 if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
1919 fatal("open(/dev/null): %s", strerror(errno));
1920 if (dup2(devnull, STDIN_FILENO) == -1)
1921 fatal("dup2: %s", strerror(errno));
1922 if (devnull > STDERR_FILENO)
1923 close(devnull);
1924 }
1925
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001926 if ((term = getenv("TERM")) == NULL)
1927 term = "";
1928 echar = 0xffffffff;
1929 if (options.escape_char != SSH_ESCAPECHAR_NONE)
1930 echar = (u_int)options.escape_char;
Damien Millere1537f92010-01-26 13:26:22 +11001931
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001932 if ((m = sshbuf_new()) == NULL)
1933 fatal("%s: sshbuf_new", __func__);
1934 if ((r = sshbuf_put_u32(m, MUX_C_NEW_SESSION)) != 0 ||
1935 (r = sshbuf_put_u32(m, muxclient_request_id)) != 0 ||
1936 (r = sshbuf_put_string(m, NULL, 0)) != 0 || /* reserved */
1937 (r = sshbuf_put_u32(m, tty_flag)) != 0 ||
1938 (r = sshbuf_put_u32(m, options.forward_x11)) != 0 ||
1939 (r = sshbuf_put_u32(m, options.forward_agent)) != 0 ||
1940 (r = sshbuf_put_u32(m, subsystem_flag)) != 0 ||
1941 (r = sshbuf_put_u32(m, echar)) != 0 ||
1942 (r = sshbuf_put_cstring(m, term)) != 0 ||
1943 (r = sshbuf_put_stringb(m, command)) != 0)
1944 fatal("%s: request: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001945
djm@openbsd.org7082bb52018-06-09 03:01:12 +00001946 /* Pass environment */
Damien Millere1537f92010-01-26 13:26:22 +11001947 if (options.num_send_env > 0 && environ != NULL) {
Damien Millere1537f92010-01-26 13:26:22 +11001948 for (i = 0; environ[i] != NULL; i++) {
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001949 if (!env_permitted(environ[i]))
1950 continue;
1951 if ((r = sshbuf_put_cstring(m, environ[i])) != 0)
1952 fatal("%s: request: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001953 }
1954 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001955 for (i = 0; i < options.num_setenv; i++) {
1956 if ((r = sshbuf_put_cstring(m, options.setenv[i])) != 0)
1957 fatal("%s: request: %s", __func__, ssh_err(r));
1958 }
Damien Millere1537f92010-01-26 13:26:22 +11001959
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001960 if (mux_client_write_packet(fd, m) != 0)
Damien Millere1537f92010-01-26 13:26:22 +11001961 fatal("%s: write packet: %s", __func__, strerror(errno));
1962
1963 /* Send the stdio file descriptors */
1964 if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
1965 mm_send_fd(fd, STDOUT_FILENO) == -1 ||
1966 mm_send_fd(fd, STDERR_FILENO) == -1)
1967 fatal("%s: send fds failed", __func__);
1968
1969 debug3("%s: session request sent", __func__);
1970
1971 /* Read their reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001972 sshbuf_reset(m);
1973 if (mux_client_read_packet(fd, m) != 0) {
Damien Millere1537f92010-01-26 13:26:22 +11001974 error("%s: read from master failed: %s",
1975 __func__, strerror(errno));
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001976 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11001977 return -1;
1978 }
1979
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001980 if ((r = sshbuf_get_u32(m, &type)) != 0 ||
1981 (r = sshbuf_get_u32(m, &rid)) != 0)
1982 fatal("%s: decode: %s", __func__, ssh_err(r));
1983 if (rid != muxclient_request_id)
Damien Millere1537f92010-01-26 13:26:22 +11001984 fatal("%s: out of sequence reply: my id %u theirs %u",
1985 __func__, muxclient_request_id, rid);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001986
Damien Millere1537f92010-01-26 13:26:22 +11001987 switch (type) {
1988 case MUX_S_SESSION_OPENED:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001989 if ((r = sshbuf_get_u32(m, &sid)) != 0)
1990 fatal("%s: decode ID: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11001991 break;
1992 case MUX_S_PERMISSION_DENIED:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001993 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
1994 fatal("%s: decode error: %s", __func__, ssh_err(r));
Damien Miller445c9a52011-01-14 12:01:29 +11001995 error("Master refused session request: %s", e);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001996 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11001997 return -1;
1998 case MUX_S_FAILURE:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00001999 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
2000 fatal("%s: decode error: %s", __func__, ssh_err(r));
Damien Miller445c9a52011-01-14 12:01:29 +11002001 error("%s: session request failed: %s", __func__, e);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002002 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11002003 return -1;
2004 default:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002005 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11002006 error("%s: unexpected response from master 0x%08x",
2007 __func__, type);
2008 return -1;
2009 }
2010 muxclient_request_id++;
2011
semarie@openbsd.orgd7d2bc92015-12-26 07:46:03 +00002012 if (pledge("stdio proc tty", NULL) == -1)
2013 fatal("%s pledge(): %s", __func__, strerror(errno));
Damien Miller4626cba2016-01-08 14:24:56 +11002014 platform_pledge_mux();
semarie@openbsd.orgd7d2bc92015-12-26 07:46:03 +00002015
Damien Millere1537f92010-01-26 13:26:22 +11002016 signal(SIGHUP, control_client_sighandler);
2017 signal(SIGINT, control_client_sighandler);
2018 signal(SIGTERM, control_client_sighandler);
2019 signal(SIGWINCH, control_client_sigrelay);
2020
Damien Miller555f3b82011-05-15 08:48:05 +10002021 rawmode = tty_flag;
Damien Millere1537f92010-01-26 13:26:22 +11002022 if (tty_flag)
Damien Miller21771e22011-05-15 08:45:50 +10002023 enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
Damien Millere1537f92010-01-26 13:26:22 +11002024
2025 /*
2026 * Stick around until the controlee closes the client_fd.
2027 * Before it does, it is expected to write an exit message.
2028 * This process must read the value and wait for the closure of
2029 * the client_fd; if this one closes early, the multiplex master will
2030 * terminate early too (possibly losing data).
2031 */
2032 for (exitval = 255, exitval_seen = 0;;) {
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002033 sshbuf_reset(m);
2034 if (mux_client_read_packet(fd, m) != 0)
Damien Millere1537f92010-01-26 13:26:22 +11002035 break;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002036 if ((r = sshbuf_get_u32(m, &type)) != 0)
2037 fatal("%s: decode type: %s", __func__, ssh_err(r));
Damien Miller555f3b82011-05-15 08:48:05 +10002038 switch (type) {
2039 case MUX_S_TTY_ALLOC_FAIL:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002040 if ((r = sshbuf_get_u32(m, &esid)) != 0)
2041 fatal("%s: decode ID: %s",
2042 __func__, ssh_err(r));
2043 if (esid != sid)
Damien Miller555f3b82011-05-15 08:48:05 +10002044 fatal("%s: tty alloc fail on unknown session: "
2045 "my id %u theirs %u",
2046 __func__, sid, esid);
2047 leave_raw_mode(options.request_tty ==
2048 REQUEST_TTY_FORCE);
2049 rawmode = 0;
2050 continue;
2051 case MUX_S_EXIT_MESSAGE:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002052 if ((r = sshbuf_get_u32(m, &esid)) != 0)
2053 fatal("%s: decode ID: %s",
2054 __func__, ssh_err(r));
2055 if (esid != sid)
Damien Miller555f3b82011-05-15 08:48:05 +10002056 fatal("%s: exit on unknown session: "
2057 "my id %u theirs %u",
2058 __func__, sid, esid);
2059 if (exitval_seen)
2060 fatal("%s: exitval sent twice", __func__);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002061 if ((r = sshbuf_get_u32(m, &exitval)) != 0)
2062 fatal("%s: decode exit value: %s",
2063 __func__, ssh_err(r));
Damien Miller555f3b82011-05-15 08:48:05 +10002064 exitval_seen = 1;
2065 continue;
2066 default:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002067 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
2068 fatal("%s: decode error: %s",
2069 __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11002070 fatal("%s: master returned error: %s", __func__, e);
2071 }
Damien Millere1537f92010-01-26 13:26:22 +11002072 }
2073
2074 close(fd);
Damien Miller555f3b82011-05-15 08:48:05 +10002075 if (rawmode)
2076 leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
Damien Millere1537f92010-01-26 13:26:22 +11002077
2078 if (muxclient_terminate) {
dtucker@openbsd.org36945fa2017-09-20 05:19:00 +00002079 debug2("Exiting on signal: %s", strsignal(muxclient_terminate));
Damien Millere1537f92010-01-26 13:26:22 +11002080 exitval = 255;
2081 } else if (!exitval_seen) {
2082 debug2("Control master terminated unexpectedly");
2083 exitval = 255;
2084 } else
2085 debug2("Received exit status from master %d", exitval);
2086
2087 if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
2088 fprintf(stderr, "Shared connection to %s closed.\r\n", host);
2089
2090 exit(exitval);
2091}
2092
2093static int
markus@openbsd.org8d057842016-09-30 09:19:13 +00002094mux_client_proxy(int fd)
2095{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002096 struct sshbuf *m;
markus@openbsd.org8d057842016-09-30 09:19:13 +00002097 char *e;
2098 u_int type, rid;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002099 int r;
markus@openbsd.org8d057842016-09-30 09:19:13 +00002100
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002101 if ((m = sshbuf_new()) == NULL)
2102 fatal("%s: sshbuf_new", __func__);
2103 if ((r = sshbuf_put_u32(m, MUX_C_PROXY)) != 0 ||
2104 (r = sshbuf_put_u32(m, muxclient_request_id)) != 0)
2105 fatal("%s: request: %s", __func__, ssh_err(r));
2106 if (mux_client_write_packet(fd, m) != 0)
markus@openbsd.org8d057842016-09-30 09:19:13 +00002107 fatal("%s: write packet: %s", __func__, strerror(errno));
2108
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002109 sshbuf_reset(m);
markus@openbsd.org8d057842016-09-30 09:19:13 +00002110
2111 /* Read their reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002112 if (mux_client_read_packet(fd, m) != 0) {
2113 sshbuf_free(m);
markus@openbsd.org8d057842016-09-30 09:19:13 +00002114 return 0;
2115 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002116 if ((r = sshbuf_get_u32(m, &type)) != 0 ||
2117 (r = sshbuf_get_u32(m, &rid)) != 0)
2118 fatal("%s: decode: %s", __func__, ssh_err(r));
2119 if (rid != muxclient_request_id)
markus@openbsd.org8d057842016-09-30 09:19:13 +00002120 fatal("%s: out of sequence reply: my id %u theirs %u",
2121 __func__, muxclient_request_id, rid);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002122 if (type != MUX_S_PROXY) {
2123 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
2124 fatal("%s: decode error: %s", __func__, ssh_err(r));
2125 fatal("%s: master returned error: %s", __func__, e);
2126 }
2127 sshbuf_free(m);
markus@openbsd.org8d057842016-09-30 09:19:13 +00002128
2129 debug3("%s: done", __func__);
2130 muxclient_request_id++;
2131 return 0;
2132}
2133
2134static int
Damien Millere1537f92010-01-26 13:26:22 +11002135mux_client_request_stdio_fwd(int fd)
2136{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002137 struct sshbuf *m;
Damien Millere1537f92010-01-26 13:26:22 +11002138 char *e;
2139 u_int type, rid, sid;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002140 int r, devnull;
Damien Millere1537f92010-01-26 13:26:22 +11002141
2142 debug3("%s: entering", __func__);
2143
2144 if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
2145 error("%s: master alive request failed", __func__);
2146 return -1;
2147 }
2148
2149 signal(SIGPIPE, SIG_IGN);
2150
2151 if (stdin_null_flag) {
2152 if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
2153 fatal("open(/dev/null): %s", strerror(errno));
2154 if (dup2(devnull, STDIN_FILENO) == -1)
2155 fatal("dup2: %s", strerror(errno));
2156 if (devnull > STDERR_FILENO)
2157 close(devnull);
2158 }
2159
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002160 if ((m = sshbuf_new()) == NULL)
2161 fatal("%s: sshbuf_new", __func__);
2162 if ((r = sshbuf_put_u32(m, MUX_C_NEW_STDIO_FWD)) != 0 ||
2163 (r = sshbuf_put_u32(m, muxclient_request_id)) != 0 ||
2164 (r = sshbuf_put_string(m, NULL, 0)) != 0 || /* reserved */
2165 (r = sshbuf_put_cstring(m, options.stdio_forward_host)) != 0 ||
2166 (r = sshbuf_put_u32(m, options.stdio_forward_port)) != 0)
2167 fatal("%s: request: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11002168
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002169 if (mux_client_write_packet(fd, m) != 0)
Damien Millere1537f92010-01-26 13:26:22 +11002170 fatal("%s: write packet: %s", __func__, strerror(errno));
2171
2172 /* Send the stdio file descriptors */
2173 if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
2174 mm_send_fd(fd, STDOUT_FILENO) == -1)
2175 fatal("%s: send fds failed", __func__);
2176
semarie@openbsd.orgb91926a2015-12-03 17:00:18 +00002177 if (pledge("stdio proc tty", NULL) == -1)
2178 fatal("%s pledge(): %s", __func__, strerror(errno));
Damien Miller4626cba2016-01-08 14:24:56 +11002179 platform_pledge_mux();
semarie@openbsd.orgb91926a2015-12-03 17:00:18 +00002180
Damien Millere1537f92010-01-26 13:26:22 +11002181 debug3("%s: stdio forward request sent", __func__);
2182
2183 /* Read their reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002184 sshbuf_reset(m);
Damien Millere1537f92010-01-26 13:26:22 +11002185
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002186 if (mux_client_read_packet(fd, m) != 0) {
Damien Millere1537f92010-01-26 13:26:22 +11002187 error("%s: read from master failed: %s",
2188 __func__, strerror(errno));
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002189 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11002190 return -1;
2191 }
2192
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002193 if ((r = sshbuf_get_u32(m, &type)) != 0 ||
2194 (r = sshbuf_get_u32(m, &rid)) != 0)
2195 fatal("%s: decode: %s", __func__, ssh_err(r));
2196 if (rid != muxclient_request_id)
Damien Millere1537f92010-01-26 13:26:22 +11002197 fatal("%s: out of sequence reply: my id %u theirs %u",
2198 __func__, muxclient_request_id, rid);
2199 switch (type) {
2200 case MUX_S_SESSION_OPENED:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002201 if ((r = sshbuf_get_u32(m, &sid)) != 0)
2202 fatal("%s: decode ID: %s", __func__, ssh_err(r));
Damien Millere1537f92010-01-26 13:26:22 +11002203 debug("%s: master session id: %u", __func__, sid);
2204 break;
2205 case MUX_S_PERMISSION_DENIED:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002206 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
2207 fatal("%s: decode error: %s", __func__, ssh_err(r));
2208 sshbuf_free(m);
Damien Miller445c9a52011-01-14 12:01:29 +11002209 fatal("Master refused stdio forwarding request: %s", e);
Damien Millere1537f92010-01-26 13:26:22 +11002210 case MUX_S_FAILURE:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002211 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
2212 fatal("%s: decode error: %s", __func__, ssh_err(r));
2213 sshbuf_free(m);
Damien Miller357610d2014-07-18 15:04:10 +10002214 fatal("Stdio forwarding request failed: %s", e);
Damien Millere1537f92010-01-26 13:26:22 +11002215 default:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002216 sshbuf_free(m);
Damien Millere1537f92010-01-26 13:26:22 +11002217 error("%s: unexpected response from master 0x%08x",
2218 __func__, type);
2219 return -1;
2220 }
2221 muxclient_request_id++;
2222
2223 signal(SIGHUP, control_client_sighandler);
2224 signal(SIGINT, control_client_sighandler);
2225 signal(SIGTERM, control_client_sighandler);
2226 signal(SIGWINCH, control_client_sigrelay);
2227
2228 /*
2229 * Stick around until the controlee closes the client_fd.
2230 */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002231 sshbuf_reset(m);
2232 if (mux_client_read_packet(fd, m) != 0) {
Damien Millere1537f92010-01-26 13:26:22 +11002233 if (errno == EPIPE ||
2234 (errno == EINTR && muxclient_terminate != 0))
2235 return 0;
2236 fatal("%s: mux_client_read_packet: %s",
2237 __func__, strerror(errno));
2238 }
2239 fatal("%s: master returned unexpected message %u", __func__, type);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002240}
2241
Damien Miller6c3eec72011-05-05 14:16:22 +10002242static void
2243mux_client_request_stop_listening(int fd)
2244{
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002245 struct sshbuf *m;
Damien Miller6c3eec72011-05-05 14:16:22 +10002246 char *e;
2247 u_int type, rid;
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002248 int r;
Damien Miller6c3eec72011-05-05 14:16:22 +10002249
2250 debug3("%s: entering", __func__);
2251
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002252 if ((m = sshbuf_new()) == NULL)
2253 fatal("%s: sshbuf_new", __func__);
2254 if ((r = sshbuf_put_u32(m, MUX_C_STOP_LISTENING)) != 0 ||
2255 (r = sshbuf_put_u32(m, muxclient_request_id)) != 0)
2256 fatal("%s: request: %s", __func__, ssh_err(r));
Damien Miller6c3eec72011-05-05 14:16:22 +10002257
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002258 if (mux_client_write_packet(fd, m) != 0)
Damien Miller6c3eec72011-05-05 14:16:22 +10002259 fatal("%s: write packet: %s", __func__, strerror(errno));
2260
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002261 sshbuf_reset(m);
Damien Miller6c3eec72011-05-05 14:16:22 +10002262
2263 /* Read their reply */
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002264 if (mux_client_read_packet(fd, m) != 0)
Damien Miller6c3eec72011-05-05 14:16:22 +10002265 fatal("%s: read from master failed: %s",
2266 __func__, strerror(errno));
2267
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002268 if ((r = sshbuf_get_u32(m, &type)) != 0 ||
2269 (r = sshbuf_get_u32(m, &rid)) != 0)
2270 fatal("%s: decode: %s", __func__, ssh_err(r));
2271 if (rid != muxclient_request_id)
Damien Miller6c3eec72011-05-05 14:16:22 +10002272 fatal("%s: out of sequence reply: my id %u theirs %u",
2273 __func__, muxclient_request_id, rid);
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002274
Damien Miller6c3eec72011-05-05 14:16:22 +10002275 switch (type) {
2276 case MUX_S_OK:
2277 break;
2278 case MUX_S_PERMISSION_DENIED:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002279 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
2280 fatal("%s: decode error: %s", __func__, ssh_err(r));
Damien Miller6c3eec72011-05-05 14:16:22 +10002281 fatal("Master refused stop listening request: %s", e);
2282 case MUX_S_FAILURE:
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002283 if ((r = sshbuf_get_cstring(m, &e, NULL)) != 0)
2284 fatal("%s: decode error: %s", __func__, ssh_err(r));
Damien Miller6c3eec72011-05-05 14:16:22 +10002285 fatal("%s: stop listening request failed: %s", __func__, e);
2286 default:
2287 fatal("%s: unexpected response from master 0x%08x",
2288 __func__, type);
2289 }
markus@openbsd.orgf4608a72018-07-09 21:18:10 +00002290 sshbuf_free(m);
Damien Miller6c3eec72011-05-05 14:16:22 +10002291 muxclient_request_id++;
2292}
2293
Damien Millerb1cbfa22008-05-19 16:00:08 +10002294/* Multiplex client main loop. */
markus@openbsd.org8d057842016-09-30 09:19:13 +00002295int
Damien Millerb1cbfa22008-05-19 16:00:08 +10002296muxclient(const char *path)
2297{
2298 struct sockaddr_un addr;
Damien Millere1537f92010-01-26 13:26:22 +11002299 int sock;
2300 u_int pid;
Damien Millerb1cbfa22008-05-19 16:00:08 +10002301
Damien Millere1537f92010-01-26 13:26:22 +11002302 if (muxclient_command == 0) {
dtucker@openbsd.org8543ff32016-06-03 03:14:41 +00002303 if (options.stdio_forward_host != NULL)
Damien Millere1537f92010-01-26 13:26:22 +11002304 muxclient_command = SSHMUX_COMMAND_STDIO_FWD;
2305 else
2306 muxclient_command = SSHMUX_COMMAND_OPEN;
2307 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10002308
2309 switch (options.control_master) {
2310 case SSHCTL_MASTER_AUTO:
2311 case SSHCTL_MASTER_AUTO_ASK:
2312 debug("auto-mux: Trying existing master");
2313 /* FALLTHROUGH */
2314 case SSHCTL_MASTER_NO:
2315 break;
2316 default:
markus@openbsd.org8d057842016-09-30 09:19:13 +00002317 return -1;
Damien Millerb1cbfa22008-05-19 16:00:08 +10002318 }
2319
2320 memset(&addr, '\0', sizeof(addr));
2321 addr.sun_family = AF_UNIX;
Damien Millerb1cbfa22008-05-19 16:00:08 +10002322
2323 if (strlcpy(addr.sun_path, path,
2324 sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
dtucker@openbsd.org67dca602016-08-08 22:40:57 +00002325 fatal("ControlPath too long ('%s' >= %u bytes)", path,
2326 (unsigned int)sizeof(addr.sun_path));
Damien Millerb1cbfa22008-05-19 16:00:08 +10002327
2328 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
2329 fatal("%s socket(): %s", __func__, strerror(errno));
2330
guenther@openbsd.org4ba15462017-01-21 11:32:04 +00002331 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
Damien Millere1537f92010-01-26 13:26:22 +11002332 switch (muxclient_command) {
2333 case SSHMUX_COMMAND_OPEN:
2334 case SSHMUX_COMMAND_STDIO_FWD:
2335 break;
2336 default:
Damien Millerb1cbfa22008-05-19 16:00:08 +10002337 fatal("Control socket connect(%.100s): %s", path,
2338 strerror(errno));
2339 }
Damien Miller603134e2010-09-24 22:07:55 +10002340 if (errno == ECONNREFUSED &&
2341 options.control_master != SSHCTL_MASTER_NO) {
2342 debug("Stale control socket %.100s, unlinking", path);
2343 unlink(path);
2344 } else if (errno == ENOENT) {
Damien Millerb1cbfa22008-05-19 16:00:08 +10002345 debug("Control socket \"%.100s\" does not exist", path);
Damien Miller603134e2010-09-24 22:07:55 +10002346 } else {
Damien Millerb1cbfa22008-05-19 16:00:08 +10002347 error("Control socket connect(%.100s): %s", path,
2348 strerror(errno));
2349 }
2350 close(sock);
markus@openbsd.org8d057842016-09-30 09:19:13 +00002351 return -1;
Damien Millerb1cbfa22008-05-19 16:00:08 +10002352 }
Damien Millere1537f92010-01-26 13:26:22 +11002353 set_nonblock(sock);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002354
Damien Millere1537f92010-01-26 13:26:22 +11002355 if (mux_client_hello_exchange(sock) != 0) {
2356 error("%s: master hello exchange failed", __func__);
Darren Tuckerca19bfe2008-06-13 10:24:03 +10002357 close(sock);
markus@openbsd.org8d057842016-09-30 09:19:13 +00002358 return -1;
Darren Tuckerca19bfe2008-06-13 10:24:03 +10002359 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10002360
2361 switch (muxclient_command) {
2362 case SSHMUX_COMMAND_ALIVE_CHECK:
Damien Millere1537f92010-01-26 13:26:22 +11002363 if ((pid = mux_client_request_alive(sock)) == 0)
2364 fatal("%s: master alive check failed", __func__);
djm@openbsd.orgb1d38a32015-10-15 23:51:40 +00002365 fprintf(stderr, "Master running (pid=%u)\r\n", pid);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002366 exit(0);
2367 case SSHMUX_COMMAND_TERMINATE:
Damien Millere1537f92010-01-26 13:26:22 +11002368 mux_client_request_terminate(sock);
dtucker@openbsd.org0b9ee622016-10-19 23:21:56 +00002369 if (options.log_level != SYSLOG_LEVEL_QUIET)
2370 fprintf(stderr, "Exit request sent.\r\n");
Damien Millerb1cbfa22008-05-19 16:00:08 +10002371 exit(0);
Damien Miller388f6fc2010-05-21 14:57:35 +10002372 case SSHMUX_COMMAND_FORWARD:
Damien Millerf6dff7c2011-09-22 21:38:52 +10002373 if (mux_client_forwards(sock, 0) != 0)
Damien Miller388f6fc2010-05-21 14:57:35 +10002374 fatal("%s: master forward request failed", __func__);
2375 exit(0);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002376 case SSHMUX_COMMAND_OPEN:
Damien Millerf6dff7c2011-09-22 21:38:52 +10002377 if (mux_client_forwards(sock, 0) != 0) {
Damien Millere1537f92010-01-26 13:26:22 +11002378 error("%s: master forward request failed", __func__);
markus@openbsd.org8d057842016-09-30 09:19:13 +00002379 return -1;
Darren Tucker2fb66ca2008-06-13 04:49:33 +10002380 }
Damien Millere1537f92010-01-26 13:26:22 +11002381 mux_client_request_session(sock);
markus@openbsd.org8d057842016-09-30 09:19:13 +00002382 return -1;
Damien Millere1537f92010-01-26 13:26:22 +11002383 case SSHMUX_COMMAND_STDIO_FWD:
2384 mux_client_request_stdio_fwd(sock);
2385 exit(0);
Damien Miller6c3eec72011-05-05 14:16:22 +10002386 case SSHMUX_COMMAND_STOP:
2387 mux_client_request_stop_listening(sock);
dtucker@openbsd.org0b9ee622016-10-19 23:21:56 +00002388 if (options.log_level != SYSLOG_LEVEL_QUIET)
2389 fprintf(stderr, "Stop listening request sent.\r\n");
Damien Miller6c3eec72011-05-05 14:16:22 +10002390 exit(0);
Damien Millerf6dff7c2011-09-22 21:38:52 +10002391 case SSHMUX_COMMAND_CANCEL_FWD:
2392 if (mux_client_forwards(sock, 1) != 0)
2393 error("%s: master cancel forward request failed",
2394 __func__);
2395 exit(0);
markus@openbsd.org8d057842016-09-30 09:19:13 +00002396 case SSHMUX_COMMAND_PROXY:
2397 mux_client_proxy(sock);
2398 return (sock);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002399 default:
Darren Tucker2fb66ca2008-06-13 04:49:33 +10002400 fatal("unrecognised muxclient_command %d", muxclient_command);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002401 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10002402}