xref: /dflybsd-src/crypto/openssh/mux.c (revision 99e85e0dcfaeb12cbe3054a0d5172837a33078a8)
1*99e85e0dSPeter Avalos /* $OpenBSD: mux.c,v 1.36 2012/07/06 01:37:21 djm Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
418de8d7fSPeter Avalos  *
518de8d7fSPeter Avalos  * Permission to use, copy, modify, and distribute this software for any
618de8d7fSPeter Avalos  * purpose with or without fee is hereby granted, provided that the above
718de8d7fSPeter Avalos  * copyright notice and this permission notice appear in all copies.
818de8d7fSPeter Avalos  *
918de8d7fSPeter Avalos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1018de8d7fSPeter Avalos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1118de8d7fSPeter Avalos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1218de8d7fSPeter Avalos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1318de8d7fSPeter Avalos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1418de8d7fSPeter Avalos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1518de8d7fSPeter Avalos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1618de8d7fSPeter Avalos  */
1718de8d7fSPeter Avalos 
1818de8d7fSPeter Avalos /* ssh session multiplexing support */
1918de8d7fSPeter Avalos 
2018de8d7fSPeter Avalos /*
2118de8d7fSPeter Avalos  * TODO:
22856ea928SPeter Avalos  *   - Better signalling from master to slave, especially passing of
2318de8d7fSPeter Avalos  *      error messages
24856ea928SPeter Avalos  *   - Better fall-back from mux slave error to new connection.
25856ea928SPeter Avalos  *   - ExitOnForwardingFailure
26856ea928SPeter Avalos  *   - Maybe extension mechanisms for multi-X11/multi-agent forwarding
27856ea928SPeter Avalos  *   - Support ~^Z in mux slaves.
28856ea928SPeter Avalos  *   - Inspect or control sessions in master.
29856ea928SPeter Avalos  *   - If we ever support the "signal" channel request, send signals on
3018de8d7fSPeter Avalos  *     sessions in master.
3118de8d7fSPeter Avalos  */
3218de8d7fSPeter Avalos 
33856ea928SPeter Avalos #include "includes.h"
34856ea928SPeter Avalos 
3518de8d7fSPeter Avalos #include <sys/types.h>
3618de8d7fSPeter Avalos #include <sys/param.h>
3718de8d7fSPeter Avalos #include <sys/stat.h>
3818de8d7fSPeter Avalos #include <sys/socket.h>
3918de8d7fSPeter Avalos #include <sys/un.h>
4018de8d7fSPeter Avalos 
4118de8d7fSPeter Avalos #include <errno.h>
4218de8d7fSPeter Avalos #include <fcntl.h>
4318de8d7fSPeter Avalos #include <signal.h>
4418de8d7fSPeter Avalos #include <stdarg.h>
4518de8d7fSPeter Avalos #include <stddef.h>
4618de8d7fSPeter Avalos #include <stdlib.h>
4718de8d7fSPeter Avalos #include <stdio.h>
4818de8d7fSPeter Avalos #include <string.h>
4918de8d7fSPeter Avalos #include <unistd.h>
5018de8d7fSPeter Avalos #ifdef HAVE_PATHS_H
5118de8d7fSPeter Avalos #include <paths.h>
5218de8d7fSPeter Avalos #endif
5318de8d7fSPeter Avalos 
54856ea928SPeter Avalos #ifdef HAVE_POLL_H
55856ea928SPeter Avalos #include <poll.h>
56856ea928SPeter Avalos #else
57856ea928SPeter Avalos # ifdef HAVE_SYS_POLL_H
58856ea928SPeter Avalos #  include <sys/poll.h>
59856ea928SPeter Avalos # endif
60856ea928SPeter Avalos #endif
61856ea928SPeter Avalos 
6218de8d7fSPeter Avalos #ifdef HAVE_UTIL_H
6318de8d7fSPeter Avalos # include <util.h>
6418de8d7fSPeter Avalos #endif
6518de8d7fSPeter Avalos 
6618de8d7fSPeter Avalos #ifdef HAVE_LIBUTIL_H
6718de8d7fSPeter Avalos # include <libutil.h>
6818de8d7fSPeter Avalos #endif
6918de8d7fSPeter Avalos 
7018de8d7fSPeter Avalos #include "openbsd-compat/sys-queue.h"
7118de8d7fSPeter Avalos #include "xmalloc.h"
7218de8d7fSPeter Avalos #include "log.h"
7318de8d7fSPeter Avalos #include "ssh.h"
74856ea928SPeter Avalos #include "ssh2.h"
7518de8d7fSPeter Avalos #include "pathnames.h"
7618de8d7fSPeter Avalos #include "misc.h"
7718de8d7fSPeter Avalos #include "match.h"
7818de8d7fSPeter Avalos #include "buffer.h"
7918de8d7fSPeter Avalos #include "channels.h"
8018de8d7fSPeter Avalos #include "msg.h"
8118de8d7fSPeter Avalos #include "packet.h"
8218de8d7fSPeter Avalos #include "monitor_fdpass.h"
8318de8d7fSPeter Avalos #include "sshpty.h"
8418de8d7fSPeter Avalos #include "key.h"
8518de8d7fSPeter Avalos #include "readconf.h"
8618de8d7fSPeter Avalos #include "clientloop.h"
8718de8d7fSPeter Avalos 
8818de8d7fSPeter Avalos /* from ssh.c */
8918de8d7fSPeter Avalos extern int tty_flag;
9018de8d7fSPeter Avalos extern Options options;
9118de8d7fSPeter Avalos extern int stdin_null_flag;
9218de8d7fSPeter Avalos extern char *host;
93856ea928SPeter Avalos extern int subsystem_flag;
9418de8d7fSPeter Avalos extern Buffer command;
95856ea928SPeter Avalos extern volatile sig_atomic_t quit_pending;
96856ea928SPeter Avalos extern char *stdio_forward_host;
97856ea928SPeter Avalos extern int stdio_forward_port;
9818de8d7fSPeter Avalos 
9918de8d7fSPeter Avalos /* Context for session open confirmation callback */
10018de8d7fSPeter Avalos struct mux_session_confirm_ctx {
101856ea928SPeter Avalos 	u_int want_tty;
102856ea928SPeter Avalos 	u_int want_subsys;
103856ea928SPeter Avalos 	u_int want_x_fwd;
104856ea928SPeter Avalos 	u_int want_agent_fwd;
10518de8d7fSPeter Avalos 	Buffer cmd;
10618de8d7fSPeter Avalos 	char *term;
10718de8d7fSPeter Avalos 	struct termios tio;
10818de8d7fSPeter Avalos 	char **env;
109856ea928SPeter Avalos 	u_int rid;
110856ea928SPeter Avalos };
111856ea928SPeter Avalos 
112856ea928SPeter Avalos /* Context for global channel callback */
113856ea928SPeter Avalos struct mux_channel_confirm_ctx {
114856ea928SPeter Avalos 	u_int cid;	/* channel id */
115856ea928SPeter Avalos 	u_int rid;	/* request id */
116856ea928SPeter Avalos 	int fid;	/* forward id */
11718de8d7fSPeter Avalos };
11818de8d7fSPeter Avalos 
11918de8d7fSPeter Avalos /* fd to control socket */
12018de8d7fSPeter Avalos int muxserver_sock = -1;
12118de8d7fSPeter Avalos 
122856ea928SPeter Avalos /* client request id */
123856ea928SPeter Avalos u_int muxclient_request_id = 0;
124856ea928SPeter Avalos 
12518de8d7fSPeter Avalos /* Multiplexing control command */
12618de8d7fSPeter Avalos u_int muxclient_command = 0;
12718de8d7fSPeter Avalos 
12818de8d7fSPeter Avalos /* Set when signalled. */
12918de8d7fSPeter Avalos static volatile sig_atomic_t muxclient_terminate = 0;
13018de8d7fSPeter Avalos 
13118de8d7fSPeter Avalos /* PID of multiplex server */
13218de8d7fSPeter Avalos static u_int muxserver_pid = 0;
13318de8d7fSPeter Avalos 
134856ea928SPeter Avalos static Channel *mux_listener_channel = NULL;
13518de8d7fSPeter Avalos 
136856ea928SPeter Avalos struct mux_master_state {
137856ea928SPeter Avalos 	int hello_rcvd;
138856ea928SPeter Avalos };
139856ea928SPeter Avalos 
140856ea928SPeter Avalos /* mux protocol messages */
141856ea928SPeter Avalos #define MUX_MSG_HELLO		0x00000001
142856ea928SPeter Avalos #define MUX_C_NEW_SESSION	0x10000002
143856ea928SPeter Avalos #define MUX_C_ALIVE_CHECK	0x10000004
144856ea928SPeter Avalos #define MUX_C_TERMINATE		0x10000005
145856ea928SPeter Avalos #define MUX_C_OPEN_FWD		0x10000006
146856ea928SPeter Avalos #define MUX_C_CLOSE_FWD		0x10000007
147856ea928SPeter Avalos #define MUX_C_NEW_STDIO_FWD	0x10000008
1481c188a7fSPeter Avalos #define MUX_C_STOP_LISTENING	0x10000009
149856ea928SPeter Avalos #define MUX_S_OK		0x80000001
150856ea928SPeter Avalos #define MUX_S_PERMISSION_DENIED	0x80000002
151856ea928SPeter Avalos #define MUX_S_FAILURE		0x80000003
152856ea928SPeter Avalos #define MUX_S_EXIT_MESSAGE	0x80000004
153856ea928SPeter Avalos #define MUX_S_ALIVE		0x80000005
154856ea928SPeter Avalos #define MUX_S_SESSION_OPENED	0x80000006
155856ea928SPeter Avalos #define MUX_S_REMOTE_PORT	0x80000007
1561c188a7fSPeter Avalos #define MUX_S_TTY_ALLOC_FAIL	0x80000008
157856ea928SPeter Avalos 
158856ea928SPeter Avalos /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */
159856ea928SPeter Avalos #define MUX_FWD_LOCAL   1
160856ea928SPeter Avalos #define MUX_FWD_REMOTE  2
161856ea928SPeter Avalos #define MUX_FWD_DYNAMIC 3
162856ea928SPeter Avalos 
163856ea928SPeter Avalos static void mux_session_confirm(int, int, void *);
164856ea928SPeter Avalos 
165856ea928SPeter Avalos static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *);
166856ea928SPeter Avalos static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *);
167856ea928SPeter Avalos static int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *);
168856ea928SPeter Avalos static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *);
169856ea928SPeter Avalos static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *);
170856ea928SPeter Avalos static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *);
171856ea928SPeter Avalos static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *);
1721c188a7fSPeter Avalos static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *);
173856ea928SPeter Avalos 
174856ea928SPeter Avalos static const struct {
175856ea928SPeter Avalos 	u_int type;
176856ea928SPeter Avalos 	int (*handler)(u_int, Channel *, Buffer *, Buffer *);
177856ea928SPeter Avalos } mux_master_handlers[] = {
178856ea928SPeter Avalos 	{ MUX_MSG_HELLO, process_mux_master_hello },
179856ea928SPeter Avalos 	{ MUX_C_NEW_SESSION, process_mux_new_session },
180856ea928SPeter Avalos 	{ MUX_C_ALIVE_CHECK, process_mux_alive_check },
181856ea928SPeter Avalos 	{ MUX_C_TERMINATE, process_mux_terminate },
182856ea928SPeter Avalos 	{ MUX_C_OPEN_FWD, process_mux_open_fwd },
183856ea928SPeter Avalos 	{ MUX_C_CLOSE_FWD, process_mux_close_fwd },
184856ea928SPeter Avalos 	{ MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd },
1851c188a7fSPeter Avalos 	{ MUX_C_STOP_LISTENING, process_mux_stop_listening },
186856ea928SPeter Avalos 	{ 0, NULL }
187856ea928SPeter Avalos };
188856ea928SPeter Avalos 
189856ea928SPeter Avalos /* Cleanup callback fired on closure of mux slave _session_ channel */
190856ea928SPeter Avalos /* ARGSUSED */
191856ea928SPeter Avalos static void
192856ea928SPeter Avalos mux_master_session_cleanup_cb(int cid, void *unused)
193856ea928SPeter Avalos {
194856ea928SPeter Avalos 	Channel *cc, *c = channel_by_id(cid);
195856ea928SPeter Avalos 
196856ea928SPeter Avalos 	debug3("%s: entering for channel %d", __func__, cid);
197856ea928SPeter Avalos 	if (c == NULL)
198856ea928SPeter Avalos 		fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
199856ea928SPeter Avalos 	if (c->ctl_chan != -1) {
200856ea928SPeter Avalos 		if ((cc = channel_by_id(c->ctl_chan)) == NULL)
201856ea928SPeter Avalos 			fatal("%s: channel %d missing control channel %d",
202856ea928SPeter Avalos 			    __func__, c->self, c->ctl_chan);
203856ea928SPeter Avalos 		c->ctl_chan = -1;
204856ea928SPeter Avalos 		cc->remote_id = -1;
205856ea928SPeter Avalos 		chan_rcvd_oclose(cc);
206856ea928SPeter Avalos 	}
207856ea928SPeter Avalos 	channel_cancel_cleanup(c->self);
208856ea928SPeter Avalos }
209856ea928SPeter Avalos 
210856ea928SPeter Avalos /* Cleanup callback fired on closure of mux slave _control_ channel */
211856ea928SPeter Avalos /* ARGSUSED */
212856ea928SPeter Avalos static void
213856ea928SPeter Avalos mux_master_control_cleanup_cb(int cid, void *unused)
214856ea928SPeter Avalos {
215856ea928SPeter Avalos 	Channel *sc, *c = channel_by_id(cid);
216856ea928SPeter Avalos 
217856ea928SPeter Avalos 	debug3("%s: entering for channel %d", __func__, cid);
218856ea928SPeter Avalos 	if (c == NULL)
219856ea928SPeter Avalos 		fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
220856ea928SPeter Avalos 	if (c->remote_id != -1) {
221856ea928SPeter Avalos 		if ((sc = channel_by_id(c->remote_id)) == NULL)
222856ea928SPeter Avalos 			fatal("%s: channel %d missing session channel %d",
223856ea928SPeter Avalos 			    __func__, c->self, c->remote_id);
224856ea928SPeter Avalos 		c->remote_id = -1;
225856ea928SPeter Avalos 		sc->ctl_chan = -1;
226856ea928SPeter Avalos 		if (sc->type != SSH_CHANNEL_OPEN) {
227856ea928SPeter Avalos 			debug2("%s: channel %d: not open", __func__, sc->self);
228856ea928SPeter Avalos 			chan_mark_dead(sc);
229856ea928SPeter Avalos 		} else {
230856ea928SPeter Avalos 			if (sc->istate == CHAN_INPUT_OPEN)
231856ea928SPeter Avalos 				chan_read_failed(sc);
232856ea928SPeter Avalos 			if (sc->ostate == CHAN_OUTPUT_OPEN)
233856ea928SPeter Avalos 				chan_write_failed(sc);
234856ea928SPeter Avalos 		}
235856ea928SPeter Avalos 	}
236856ea928SPeter Avalos 	channel_cancel_cleanup(c->self);
237856ea928SPeter Avalos }
238856ea928SPeter Avalos 
239856ea928SPeter Avalos /* Check mux client environment variables before passing them to mux master. */
240856ea928SPeter Avalos static int
241856ea928SPeter Avalos env_permitted(char *env)
242856ea928SPeter Avalos {
243856ea928SPeter Avalos 	int i, ret;
244856ea928SPeter Avalos 	char name[1024], *cp;
245856ea928SPeter Avalos 
246856ea928SPeter Avalos 	if ((cp = strchr(env, '=')) == NULL || cp == env)
247856ea928SPeter Avalos 		return 0;
248856ea928SPeter Avalos 	ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
249856ea928SPeter Avalos 	if (ret <= 0 || (size_t)ret >= sizeof(name)) {
250856ea928SPeter Avalos 		error("env_permitted: name '%.100s...' too long", env);
251856ea928SPeter Avalos 		return 0;
252856ea928SPeter Avalos 	}
253856ea928SPeter Avalos 
254856ea928SPeter Avalos 	for (i = 0; i < options.num_send_env; i++)
255856ea928SPeter Avalos 		if (match_pattern(name, options.send_env[i]))
256856ea928SPeter Avalos 			return 1;
257856ea928SPeter Avalos 
258856ea928SPeter Avalos 	return 0;
259856ea928SPeter Avalos }
260856ea928SPeter Avalos 
261856ea928SPeter Avalos /* Mux master protocol message handlers */
262856ea928SPeter Avalos 
263856ea928SPeter Avalos static int
264856ea928SPeter Avalos process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r)
265856ea928SPeter Avalos {
266856ea928SPeter Avalos 	u_int ver;
267856ea928SPeter Avalos 	struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
268856ea928SPeter Avalos 
269856ea928SPeter Avalos 	if (state == NULL)
270856ea928SPeter Avalos 		fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self);
271856ea928SPeter Avalos 	if (state->hello_rcvd) {
272856ea928SPeter Avalos 		error("%s: HELLO received twice", __func__);
273856ea928SPeter Avalos 		return -1;
274856ea928SPeter Avalos 	}
275856ea928SPeter Avalos 	if (buffer_get_int_ret(&ver, m) != 0) {
276856ea928SPeter Avalos  malf:
277856ea928SPeter Avalos 		error("%s: malformed message", __func__);
278856ea928SPeter Avalos 		return -1;
279856ea928SPeter Avalos 	}
280856ea928SPeter Avalos 	if (ver != SSHMUX_VER) {
281856ea928SPeter Avalos 		error("Unsupported multiplexing protocol version %d "
282856ea928SPeter Avalos 		    "(expected %d)", ver, SSHMUX_VER);
283856ea928SPeter Avalos 		return -1;
284856ea928SPeter Avalos 	}
285856ea928SPeter Avalos 	debug2("%s: channel %d slave version %u", __func__, c->self, ver);
286856ea928SPeter Avalos 
287856ea928SPeter Avalos 	/* No extensions are presently defined */
288856ea928SPeter Avalos 	while (buffer_len(m) > 0) {
289856ea928SPeter Avalos 		char *name = buffer_get_string_ret(m, NULL);
290856ea928SPeter Avalos 		char *value = buffer_get_string_ret(m, NULL);
291856ea928SPeter Avalos 
292856ea928SPeter Avalos 		if (name == NULL || value == NULL) {
293856ea928SPeter Avalos 			if (name != NULL)
294856ea928SPeter Avalos 				xfree(name);
295856ea928SPeter Avalos 			goto malf;
296856ea928SPeter Avalos 		}
297856ea928SPeter Avalos 		debug2("Unrecognised slave extension \"%s\"", name);
298856ea928SPeter Avalos 		xfree(name);
299856ea928SPeter Avalos 		xfree(value);
300856ea928SPeter Avalos 	}
301856ea928SPeter Avalos 	state->hello_rcvd = 1;
302856ea928SPeter Avalos 	return 0;
303856ea928SPeter Avalos }
304856ea928SPeter Avalos 
305856ea928SPeter Avalos static int
306856ea928SPeter Avalos process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
307856ea928SPeter Avalos {
308856ea928SPeter Avalos 	Channel *nc;
309856ea928SPeter Avalos 	struct mux_session_confirm_ctx *cctx;
310856ea928SPeter Avalos 	char *reserved, *cmd, *cp;
311856ea928SPeter Avalos 	u_int i, j, len, env_len, escape_char, window, packetmax;
312856ea928SPeter Avalos 	int new_fd[3];
313856ea928SPeter Avalos 
314856ea928SPeter Avalos 	/* Reply for SSHMUX_COMMAND_OPEN */
315856ea928SPeter Avalos 	cctx = xcalloc(1, sizeof(*cctx));
316856ea928SPeter Avalos 	cctx->term = NULL;
317856ea928SPeter Avalos 	cctx->rid = rid;
318856ea928SPeter Avalos 	cmd = reserved = NULL;
319*99e85e0dSPeter Avalos 	cctx->env = NULL;
320*99e85e0dSPeter Avalos 	env_len = 0;
321856ea928SPeter Avalos 	if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
322856ea928SPeter Avalos 	    buffer_get_int_ret(&cctx->want_tty, m) != 0 ||
323856ea928SPeter Avalos 	    buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 ||
324856ea928SPeter Avalos 	    buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 ||
325856ea928SPeter Avalos 	    buffer_get_int_ret(&cctx->want_subsys, m) != 0 ||
326856ea928SPeter Avalos 	    buffer_get_int_ret(&escape_char, m) != 0 ||
327856ea928SPeter Avalos 	    (cctx->term = buffer_get_string_ret(m, &len)) == NULL ||
328856ea928SPeter Avalos 	    (cmd = buffer_get_string_ret(m, &len)) == NULL) {
329856ea928SPeter Avalos  malf:
330856ea928SPeter Avalos 		if (cmd != NULL)
331856ea928SPeter Avalos 			xfree(cmd);
332856ea928SPeter Avalos 		if (reserved != NULL)
333856ea928SPeter Avalos 			xfree(reserved);
334*99e85e0dSPeter Avalos 		for (j = 0; j < env_len; j++)
335*99e85e0dSPeter Avalos 			xfree(cctx->env[j]);
336*99e85e0dSPeter Avalos 		if (env_len > 0)
337*99e85e0dSPeter Avalos 			xfree(cctx->env);
338856ea928SPeter Avalos 		if (cctx->term != NULL)
339856ea928SPeter Avalos 			xfree(cctx->term);
340*99e85e0dSPeter Avalos 		xfree(cctx);
341856ea928SPeter Avalos 		error("%s: malformed message", __func__);
342856ea928SPeter Avalos 		return -1;
343856ea928SPeter Avalos 	}
344856ea928SPeter Avalos 	xfree(reserved);
345856ea928SPeter Avalos 	reserved = NULL;
346856ea928SPeter Avalos 
347856ea928SPeter Avalos 	while (buffer_len(m) > 0) {
348856ea928SPeter Avalos #define MUX_MAX_ENV_VARS	4096
349*99e85e0dSPeter Avalos 		if ((cp = buffer_get_string_ret(m, &len)) == NULL)
350856ea928SPeter Avalos 			goto malf;
351856ea928SPeter Avalos 		if (!env_permitted(cp)) {
352856ea928SPeter Avalos 			xfree(cp);
353856ea928SPeter Avalos 			continue;
354856ea928SPeter Avalos 		}
355856ea928SPeter Avalos 		cctx->env = xrealloc(cctx->env, env_len + 2,
356856ea928SPeter Avalos 		    sizeof(*cctx->env));
357856ea928SPeter Avalos 		cctx->env[env_len++] = cp;
358856ea928SPeter Avalos 		cctx->env[env_len] = NULL;
359856ea928SPeter Avalos 		if (env_len > MUX_MAX_ENV_VARS) {
360856ea928SPeter Avalos 			error(">%d environment variables received, ignoring "
361856ea928SPeter Avalos 			    "additional", MUX_MAX_ENV_VARS);
362856ea928SPeter Avalos 			break;
363856ea928SPeter Avalos 		}
364856ea928SPeter Avalos 	}
365856ea928SPeter Avalos 
366856ea928SPeter Avalos 	debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, "
367856ea928SPeter Avalos 	    "term \"%s\", cmd \"%s\", env %u", __func__, c->self,
368856ea928SPeter Avalos 	    cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd,
369856ea928SPeter Avalos 	    cctx->want_subsys, cctx->term, cmd, env_len);
370856ea928SPeter Avalos 
371856ea928SPeter Avalos 	buffer_init(&cctx->cmd);
372856ea928SPeter Avalos 	buffer_append(&cctx->cmd, cmd, strlen(cmd));
373856ea928SPeter Avalos 	xfree(cmd);
374856ea928SPeter Avalos 	cmd = NULL;
375856ea928SPeter Avalos 
376856ea928SPeter Avalos 	/* Gather fds from client */
377856ea928SPeter Avalos 	for(i = 0; i < 3; i++) {
378856ea928SPeter Avalos 		if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
379856ea928SPeter Avalos 			error("%s: failed to receive fd %d from slave",
380856ea928SPeter Avalos 			    __func__, i);
381856ea928SPeter Avalos 			for (j = 0; j < i; j++)
382856ea928SPeter Avalos 				close(new_fd[j]);
383856ea928SPeter Avalos 			for (j = 0; j < env_len; j++)
384856ea928SPeter Avalos 				xfree(cctx->env[j]);
385856ea928SPeter Avalos 			if (env_len > 0)
386856ea928SPeter Avalos 				xfree(cctx->env);
387856ea928SPeter Avalos 			xfree(cctx->term);
388856ea928SPeter Avalos 			buffer_free(&cctx->cmd);
389856ea928SPeter Avalos 			xfree(cctx);
390856ea928SPeter Avalos 
391856ea928SPeter Avalos 			/* prepare reply */
392856ea928SPeter Avalos 			buffer_put_int(r, MUX_S_FAILURE);
393856ea928SPeter Avalos 			buffer_put_int(r, rid);
394856ea928SPeter Avalos 			buffer_put_cstring(r,
395856ea928SPeter Avalos 			    "did not receive file descriptors");
396856ea928SPeter Avalos 			return -1;
397856ea928SPeter Avalos 		}
398856ea928SPeter Avalos 	}
399856ea928SPeter Avalos 
400856ea928SPeter Avalos 	debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
401856ea928SPeter Avalos 	    new_fd[0], new_fd[1], new_fd[2]);
402856ea928SPeter Avalos 
403856ea928SPeter Avalos 	/* XXX support multiple child sessions in future */
404856ea928SPeter Avalos 	if (c->remote_id != -1) {
405856ea928SPeter Avalos 		debug2("%s: session already open", __func__);
406856ea928SPeter Avalos 		/* prepare reply */
407856ea928SPeter Avalos 		buffer_put_int(r, MUX_S_FAILURE);
408856ea928SPeter Avalos 		buffer_put_int(r, rid);
409856ea928SPeter Avalos 		buffer_put_cstring(r, "Multiple sessions not supported");
410856ea928SPeter Avalos  cleanup:
411856ea928SPeter Avalos 		close(new_fd[0]);
412856ea928SPeter Avalos 		close(new_fd[1]);
413856ea928SPeter Avalos 		close(new_fd[2]);
414856ea928SPeter Avalos 		xfree(cctx->term);
415856ea928SPeter Avalos 		if (env_len != 0) {
416856ea928SPeter Avalos 			for (i = 0; i < env_len; i++)
417856ea928SPeter Avalos 				xfree(cctx->env[i]);
418856ea928SPeter Avalos 			xfree(cctx->env);
419856ea928SPeter Avalos 		}
420856ea928SPeter Avalos 		buffer_free(&cctx->cmd);
421*99e85e0dSPeter Avalos 		xfree(cctx);
422856ea928SPeter Avalos 		return 0;
423856ea928SPeter Avalos 	}
424856ea928SPeter Avalos 
425856ea928SPeter Avalos 	if (options.control_master == SSHCTL_MASTER_ASK ||
426856ea928SPeter Avalos 	    options.control_master == SSHCTL_MASTER_AUTO_ASK) {
427856ea928SPeter Avalos 		if (!ask_permission("Allow shared connection to %s? ", host)) {
428856ea928SPeter Avalos 			debug2("%s: session refused by user", __func__);
429856ea928SPeter Avalos 			/* prepare reply */
430856ea928SPeter Avalos 			buffer_put_int(r, MUX_S_PERMISSION_DENIED);
431856ea928SPeter Avalos 			buffer_put_int(r, rid);
432856ea928SPeter Avalos 			buffer_put_cstring(r, "Permission denied");
433856ea928SPeter Avalos 			goto cleanup;
434856ea928SPeter Avalos 		}
435856ea928SPeter Avalos 	}
436856ea928SPeter Avalos 
437856ea928SPeter Avalos 	/* Try to pick up ttymodes from client before it goes raw */
438856ea928SPeter Avalos 	if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
439856ea928SPeter Avalos 		error("%s: tcgetattr: %s", __func__, strerror(errno));
440856ea928SPeter Avalos 
441856ea928SPeter Avalos 	/* enable nonblocking unless tty */
442856ea928SPeter Avalos 	if (!isatty(new_fd[0]))
443856ea928SPeter Avalos 		set_nonblock(new_fd[0]);
444856ea928SPeter Avalos 	if (!isatty(new_fd[1]))
445856ea928SPeter Avalos 		set_nonblock(new_fd[1]);
446856ea928SPeter Avalos 	if (!isatty(new_fd[2]))
447856ea928SPeter Avalos 		set_nonblock(new_fd[2]);
448856ea928SPeter Avalos 
449856ea928SPeter Avalos 	window = CHAN_SES_WINDOW_DEFAULT;
450856ea928SPeter Avalos 	packetmax = CHAN_SES_PACKET_DEFAULT;
451856ea928SPeter Avalos 	if (cctx->want_tty) {
452856ea928SPeter Avalos 		window >>= 1;
453856ea928SPeter Avalos 		packetmax >>= 1;
454856ea928SPeter Avalos 	}
455856ea928SPeter Avalos 
456856ea928SPeter Avalos 	nc = channel_new("session", SSH_CHANNEL_OPENING,
457856ea928SPeter Avalos 	    new_fd[0], new_fd[1], new_fd[2], window, packetmax,
458856ea928SPeter Avalos 	    CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
459856ea928SPeter Avalos 
460856ea928SPeter Avalos 	nc->ctl_chan = c->self;		/* link session -> control channel */
461856ea928SPeter Avalos 	c->remote_id = nc->self; 	/* link control -> session channel */
462856ea928SPeter Avalos 
463856ea928SPeter Avalos 	if (cctx->want_tty && escape_char != 0xffffffff) {
464856ea928SPeter Avalos 		channel_register_filter(nc->self,
465856ea928SPeter Avalos 		    client_simple_escape_filter, NULL,
466856ea928SPeter Avalos 		    client_filter_cleanup,
467856ea928SPeter Avalos 		    client_new_escape_filter_ctx((int)escape_char));
468856ea928SPeter Avalos 	}
469856ea928SPeter Avalos 
470856ea928SPeter Avalos 	debug2("%s: channel_new: %d linked to control channel %d",
471856ea928SPeter Avalos 	    __func__, nc->self, nc->ctl_chan);
472856ea928SPeter Avalos 
473856ea928SPeter Avalos 	channel_send_open(nc->self);
474856ea928SPeter Avalos 	channel_register_open_confirm(nc->self, mux_session_confirm, cctx);
475856ea928SPeter Avalos 	c->mux_pause = 1; /* stop handling messages until open_confirm done */
476856ea928SPeter Avalos 	channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
477856ea928SPeter Avalos 
478856ea928SPeter Avalos 	/* reply is deferred, sent by mux_session_confirm */
479856ea928SPeter Avalos 	return 0;
480856ea928SPeter Avalos }
481856ea928SPeter Avalos 
482856ea928SPeter Avalos static int
483856ea928SPeter Avalos process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r)
484856ea928SPeter Avalos {
485856ea928SPeter Avalos 	debug2("%s: channel %d: alive check", __func__, c->self);
486856ea928SPeter Avalos 
487856ea928SPeter Avalos 	/* prepare reply */
488856ea928SPeter Avalos 	buffer_put_int(r, MUX_S_ALIVE);
489856ea928SPeter Avalos 	buffer_put_int(r, rid);
490856ea928SPeter Avalos 	buffer_put_int(r, (u_int)getpid());
491856ea928SPeter Avalos 
492856ea928SPeter Avalos 	return 0;
493856ea928SPeter Avalos }
494856ea928SPeter Avalos 
495856ea928SPeter Avalos static int
496856ea928SPeter Avalos process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r)
497856ea928SPeter Avalos {
498856ea928SPeter Avalos 	debug2("%s: channel %d: terminate request", __func__, c->self);
499856ea928SPeter Avalos 
500856ea928SPeter Avalos 	if (options.control_master == SSHCTL_MASTER_ASK ||
501856ea928SPeter Avalos 	    options.control_master == SSHCTL_MASTER_AUTO_ASK) {
502856ea928SPeter Avalos 		if (!ask_permission("Terminate shared connection to %s? ",
503856ea928SPeter Avalos 		    host)) {
504856ea928SPeter Avalos 			debug2("%s: termination refused by user", __func__);
505856ea928SPeter Avalos 			buffer_put_int(r, MUX_S_PERMISSION_DENIED);
506856ea928SPeter Avalos 			buffer_put_int(r, rid);
507856ea928SPeter Avalos 			buffer_put_cstring(r, "Permission denied");
508856ea928SPeter Avalos 			return 0;
509856ea928SPeter Avalos 		}
510856ea928SPeter Avalos 	}
511856ea928SPeter Avalos 
512856ea928SPeter Avalos 	quit_pending = 1;
513856ea928SPeter Avalos 	buffer_put_int(r, MUX_S_OK);
514856ea928SPeter Avalos 	buffer_put_int(r, rid);
515856ea928SPeter Avalos 	/* XXX exit happens too soon - message never makes it to client */
516856ea928SPeter Avalos 	return 0;
517856ea928SPeter Avalos }
518856ea928SPeter Avalos 
519856ea928SPeter Avalos static char *
520856ea928SPeter Avalos format_forward(u_int ftype, Forward *fwd)
521856ea928SPeter Avalos {
522856ea928SPeter Avalos 	char *ret;
523856ea928SPeter Avalos 
524856ea928SPeter Avalos 	switch (ftype) {
525856ea928SPeter Avalos 	case MUX_FWD_LOCAL:
526856ea928SPeter Avalos 		xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d",
527856ea928SPeter Avalos 		    (fwd->listen_host == NULL) ?
528856ea928SPeter Avalos 		    (options.gateway_ports ? "*" : "LOCALHOST") :
529856ea928SPeter Avalos 		    fwd->listen_host, fwd->listen_port,
530856ea928SPeter Avalos 		    fwd->connect_host, fwd->connect_port);
531856ea928SPeter Avalos 		break;
532856ea928SPeter Avalos 	case MUX_FWD_DYNAMIC:
533856ea928SPeter Avalos 		xasprintf(&ret, "dynamic forward %.200s:%d -> *",
534856ea928SPeter Avalos 		    (fwd->listen_host == NULL) ?
535856ea928SPeter Avalos 		    (options.gateway_ports ? "*" : "LOCALHOST") :
536856ea928SPeter Avalos 		     fwd->listen_host, fwd->listen_port);
537856ea928SPeter Avalos 		break;
538856ea928SPeter Avalos 	case MUX_FWD_REMOTE:
539856ea928SPeter Avalos 		xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d",
540856ea928SPeter Avalos 		    (fwd->listen_host == NULL) ?
541856ea928SPeter Avalos 		    "LOCALHOST" : fwd->listen_host,
542856ea928SPeter Avalos 		    fwd->listen_port,
543856ea928SPeter Avalos 		    fwd->connect_host, fwd->connect_port);
544856ea928SPeter Avalos 		break;
545856ea928SPeter Avalos 	default:
546856ea928SPeter Avalos 		fatal("%s: unknown forward type %u", __func__, ftype);
547856ea928SPeter Avalos 	}
548856ea928SPeter Avalos 	return ret;
549856ea928SPeter Avalos }
550856ea928SPeter Avalos 
551856ea928SPeter Avalos static int
552856ea928SPeter Avalos compare_host(const char *a, const char *b)
553856ea928SPeter Avalos {
554856ea928SPeter Avalos 	if (a == NULL && b == NULL)
555856ea928SPeter Avalos 		return 1;
556856ea928SPeter Avalos 	if (a == NULL || b == NULL)
557856ea928SPeter Avalos 		return 0;
558856ea928SPeter Avalos 	return strcmp(a, b) == 0;
559856ea928SPeter Avalos }
560856ea928SPeter Avalos 
561856ea928SPeter Avalos static int
562856ea928SPeter Avalos compare_forward(Forward *a, Forward *b)
563856ea928SPeter Avalos {
564856ea928SPeter Avalos 	if (!compare_host(a->listen_host, b->listen_host))
565856ea928SPeter Avalos 		return 0;
566856ea928SPeter Avalos 	if (a->listen_port != b->listen_port)
567856ea928SPeter Avalos 		return 0;
568856ea928SPeter Avalos 	if (!compare_host(a->connect_host, b->connect_host))
569856ea928SPeter Avalos 		return 0;
570856ea928SPeter Avalos 	if (a->connect_port != b->connect_port)
571856ea928SPeter Avalos 		return 0;
572856ea928SPeter Avalos 
573856ea928SPeter Avalos 	return 1;
574856ea928SPeter Avalos }
575856ea928SPeter Avalos 
576856ea928SPeter Avalos static void
577856ea928SPeter Avalos mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
578856ea928SPeter Avalos {
579856ea928SPeter Avalos 	struct mux_channel_confirm_ctx *fctx = ctxt;
580856ea928SPeter Avalos 	char *failmsg = NULL;
581856ea928SPeter Avalos 	Forward *rfwd;
582856ea928SPeter Avalos 	Channel *c;
583856ea928SPeter Avalos 	Buffer out;
584856ea928SPeter Avalos 
585856ea928SPeter Avalos 	if ((c = channel_by_id(fctx->cid)) == NULL) {
586856ea928SPeter Avalos 		/* no channel for reply */
587856ea928SPeter Avalos 		error("%s: unknown channel", __func__);
588856ea928SPeter Avalos 		return;
589856ea928SPeter Avalos 	}
590856ea928SPeter Avalos 	buffer_init(&out);
591856ea928SPeter Avalos 	if (fctx->fid >= options.num_remote_forwards) {
592856ea928SPeter Avalos 		xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid);
593856ea928SPeter Avalos 		goto fail;
594856ea928SPeter Avalos 	}
595856ea928SPeter Avalos 	rfwd = &options.remote_forwards[fctx->fid];
596856ea928SPeter Avalos 	debug("%s: %s for: listen %d, connect %s:%d", __func__,
597856ea928SPeter Avalos 	    type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
598856ea928SPeter Avalos 	    rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
599856ea928SPeter Avalos 	if (type == SSH2_MSG_REQUEST_SUCCESS) {
600856ea928SPeter Avalos 		if (rfwd->listen_port == 0) {
601856ea928SPeter Avalos 			rfwd->allocated_port = packet_get_int();
602856ea928SPeter Avalos 			logit("Allocated port %u for mux remote forward"
603856ea928SPeter Avalos 			    " to %s:%d", rfwd->allocated_port,
604856ea928SPeter Avalos 			    rfwd->connect_host, rfwd->connect_port);
605856ea928SPeter Avalos 			buffer_put_int(&out, MUX_S_REMOTE_PORT);
606856ea928SPeter Avalos 			buffer_put_int(&out, fctx->rid);
607856ea928SPeter Avalos 			buffer_put_int(&out, rfwd->allocated_port);
608*99e85e0dSPeter Avalos 			channel_update_permitted_opens(rfwd->handle,
609*99e85e0dSPeter Avalos 			   rfwd->allocated_port);
610856ea928SPeter Avalos 		} else {
611856ea928SPeter Avalos 			buffer_put_int(&out, MUX_S_OK);
612856ea928SPeter Avalos 			buffer_put_int(&out, fctx->rid);
613856ea928SPeter Avalos 		}
614856ea928SPeter Avalos 		goto out;
615856ea928SPeter Avalos 	} else {
616*99e85e0dSPeter Avalos 		if (rfwd->listen_port == 0)
617*99e85e0dSPeter Avalos 			channel_update_permitted_opens(rfwd->handle, -1);
618856ea928SPeter Avalos 		xasprintf(&failmsg, "remote port forwarding failed for "
619856ea928SPeter Avalos 		    "listen port %d", rfwd->listen_port);
620856ea928SPeter Avalos 	}
621856ea928SPeter Avalos  fail:
622856ea928SPeter Avalos 	error("%s: %s", __func__, failmsg);
623856ea928SPeter Avalos 	buffer_put_int(&out, MUX_S_FAILURE);
624856ea928SPeter Avalos 	buffer_put_int(&out, fctx->rid);
625856ea928SPeter Avalos 	buffer_put_cstring(&out, failmsg);
626856ea928SPeter Avalos 	xfree(failmsg);
627856ea928SPeter Avalos  out:
628856ea928SPeter Avalos 	buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out));
629856ea928SPeter Avalos 	buffer_free(&out);
630856ea928SPeter Avalos 	if (c->mux_pause <= 0)
631856ea928SPeter Avalos 		fatal("%s: mux_pause %d", __func__, c->mux_pause);
632856ea928SPeter Avalos 	c->mux_pause = 0; /* start processing messages again */
633856ea928SPeter Avalos }
634856ea928SPeter Avalos 
635856ea928SPeter Avalos static int
636856ea928SPeter Avalos process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
637856ea928SPeter Avalos {
638856ea928SPeter Avalos 	Forward fwd;
639856ea928SPeter Avalos 	char *fwd_desc = NULL;
640856ea928SPeter Avalos 	u_int ftype;
641856ea928SPeter Avalos 	int i, ret = 0, freefwd = 1;
642856ea928SPeter Avalos 
643856ea928SPeter Avalos 	fwd.listen_host = fwd.connect_host = NULL;
644856ea928SPeter Avalos 	if (buffer_get_int_ret(&ftype, m) != 0 ||
645856ea928SPeter Avalos 	    (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
646856ea928SPeter Avalos 	    buffer_get_int_ret(&fwd.listen_port, m) != 0 ||
647856ea928SPeter Avalos 	    (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
648856ea928SPeter Avalos 	    buffer_get_int_ret(&fwd.connect_port, m) != 0) {
649856ea928SPeter Avalos 		error("%s: malformed message", __func__);
650856ea928SPeter Avalos 		ret = -1;
651856ea928SPeter Avalos 		goto out;
652856ea928SPeter Avalos 	}
653856ea928SPeter Avalos 
654856ea928SPeter Avalos 	if (*fwd.listen_host == '\0') {
655856ea928SPeter Avalos 		xfree(fwd.listen_host);
656856ea928SPeter Avalos 		fwd.listen_host = NULL;
657856ea928SPeter Avalos 	}
658856ea928SPeter Avalos 	if (*fwd.connect_host == '\0') {
659856ea928SPeter Avalos 		xfree(fwd.connect_host);
660856ea928SPeter Avalos 		fwd.connect_host = NULL;
661856ea928SPeter Avalos 	}
662856ea928SPeter Avalos 
663856ea928SPeter Avalos 	debug2("%s: channel %d: request %s", __func__, c->self,
664856ea928SPeter Avalos 	    (fwd_desc = format_forward(ftype, &fwd)));
665856ea928SPeter Avalos 
666856ea928SPeter Avalos 	if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE &&
667856ea928SPeter Avalos 	    ftype != MUX_FWD_DYNAMIC) {
668856ea928SPeter Avalos 		logit("%s: invalid forwarding type %u", __func__, ftype);
669856ea928SPeter Avalos  invalid:
670856ea928SPeter Avalos 		if (fwd.listen_host)
671856ea928SPeter Avalos 			xfree(fwd.listen_host);
672856ea928SPeter Avalos 		if (fwd.connect_host)
673856ea928SPeter Avalos 			xfree(fwd.connect_host);
674856ea928SPeter Avalos 		buffer_put_int(r, MUX_S_FAILURE);
675856ea928SPeter Avalos 		buffer_put_int(r, rid);
676856ea928SPeter Avalos 		buffer_put_cstring(r, "Invalid forwarding request");
677856ea928SPeter Avalos 		return 0;
678856ea928SPeter Avalos 	}
679856ea928SPeter Avalos 	if (fwd.listen_port >= 65536) {
680856ea928SPeter Avalos 		logit("%s: invalid listen port %u", __func__,
681856ea928SPeter Avalos 		    fwd.listen_port);
682856ea928SPeter Avalos 		goto invalid;
683856ea928SPeter Avalos 	}
684856ea928SPeter Avalos 	if (fwd.connect_port >= 65536 || (ftype != MUX_FWD_DYNAMIC &&
685856ea928SPeter Avalos 	    ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) {
686856ea928SPeter Avalos 		logit("%s: invalid connect port %u", __func__,
687856ea928SPeter Avalos 		    fwd.connect_port);
688856ea928SPeter Avalos 		goto invalid;
689856ea928SPeter Avalos 	}
690856ea928SPeter Avalos 	if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL) {
691856ea928SPeter Avalos 		logit("%s: missing connect host", __func__);
692856ea928SPeter Avalos 		goto invalid;
693856ea928SPeter Avalos 	}
694856ea928SPeter Avalos 
695856ea928SPeter Avalos 	/* Skip forwards that have already been requested */
696856ea928SPeter Avalos 	switch (ftype) {
697856ea928SPeter Avalos 	case MUX_FWD_LOCAL:
698856ea928SPeter Avalos 	case MUX_FWD_DYNAMIC:
699856ea928SPeter Avalos 		for (i = 0; i < options.num_local_forwards; i++) {
700856ea928SPeter Avalos 			if (compare_forward(&fwd,
701856ea928SPeter Avalos 			    options.local_forwards + i)) {
702856ea928SPeter Avalos  exists:
703856ea928SPeter Avalos 				debug2("%s: found existing forwarding",
704856ea928SPeter Avalos 				    __func__);
705856ea928SPeter Avalos 				buffer_put_int(r, MUX_S_OK);
706856ea928SPeter Avalos 				buffer_put_int(r, rid);
707856ea928SPeter Avalos 				goto out;
708856ea928SPeter Avalos 			}
709856ea928SPeter Avalos 		}
710856ea928SPeter Avalos 		break;
711856ea928SPeter Avalos 	case MUX_FWD_REMOTE:
712856ea928SPeter Avalos 		for (i = 0; i < options.num_remote_forwards; i++) {
713856ea928SPeter Avalos 			if (compare_forward(&fwd,
714856ea928SPeter Avalos 			    options.remote_forwards + i)) {
715856ea928SPeter Avalos 				if (fwd.listen_port != 0)
716856ea928SPeter Avalos 					goto exists;
717856ea928SPeter Avalos 				debug2("%s: found allocated port",
718856ea928SPeter Avalos 				    __func__);
719856ea928SPeter Avalos 				buffer_put_int(r, MUX_S_REMOTE_PORT);
720856ea928SPeter Avalos 				buffer_put_int(r, rid);
721856ea928SPeter Avalos 				buffer_put_int(r,
722856ea928SPeter Avalos 				    options.remote_forwards[i].allocated_port);
723856ea928SPeter Avalos 				goto out;
724856ea928SPeter Avalos 			}
725856ea928SPeter Avalos 		}
726856ea928SPeter Avalos 		break;
727856ea928SPeter Avalos 	}
728856ea928SPeter Avalos 
729856ea928SPeter Avalos 	if (options.control_master == SSHCTL_MASTER_ASK ||
730856ea928SPeter Avalos 	    options.control_master == SSHCTL_MASTER_AUTO_ASK) {
731856ea928SPeter Avalos 		if (!ask_permission("Open %s on %s?", fwd_desc, host)) {
732856ea928SPeter Avalos 			debug2("%s: forwarding refused by user", __func__);
733856ea928SPeter Avalos 			buffer_put_int(r, MUX_S_PERMISSION_DENIED);
734856ea928SPeter Avalos 			buffer_put_int(r, rid);
735856ea928SPeter Avalos 			buffer_put_cstring(r, "Permission denied");
736856ea928SPeter Avalos 			goto out;
737856ea928SPeter Avalos 		}
738856ea928SPeter Avalos 	}
739856ea928SPeter Avalos 
740856ea928SPeter Avalos 	if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) {
741856ea928SPeter Avalos 		if (channel_setup_local_fwd_listener(fwd.listen_host,
742856ea928SPeter Avalos 		    fwd.listen_port, fwd.connect_host, fwd.connect_port,
743856ea928SPeter Avalos 		    options.gateway_ports) < 0) {
744856ea928SPeter Avalos  fail:
745856ea928SPeter Avalos 			logit("slave-requested %s failed", fwd_desc);
746856ea928SPeter Avalos 			buffer_put_int(r, MUX_S_FAILURE);
747856ea928SPeter Avalos 			buffer_put_int(r, rid);
748856ea928SPeter Avalos 			buffer_put_cstring(r, "Port forwarding failed");
749856ea928SPeter Avalos 			goto out;
750856ea928SPeter Avalos 		}
751856ea928SPeter Avalos 		add_local_forward(&options, &fwd);
752856ea928SPeter Avalos 		freefwd = 0;
753856ea928SPeter Avalos 	} else {
754856ea928SPeter Avalos 		struct mux_channel_confirm_ctx *fctx;
755856ea928SPeter Avalos 
756*99e85e0dSPeter Avalos 		fwd.handle = channel_request_remote_forwarding(fwd.listen_host,
757*99e85e0dSPeter Avalos 		    fwd.listen_port, fwd.connect_host, fwd.connect_port);
758*99e85e0dSPeter Avalos 		if (fwd.handle < 0)
759856ea928SPeter Avalos 			goto fail;
760856ea928SPeter Avalos 		add_remote_forward(&options, &fwd);
761856ea928SPeter Avalos 		fctx = xcalloc(1, sizeof(*fctx));
762856ea928SPeter Avalos 		fctx->cid = c->self;
763856ea928SPeter Avalos 		fctx->rid = rid;
764856ea928SPeter Avalos 		fctx->fid = options.num_remote_forwards - 1;
765856ea928SPeter Avalos 		client_register_global_confirm(mux_confirm_remote_forward,
766856ea928SPeter Avalos 		    fctx);
767856ea928SPeter Avalos 		freefwd = 0;
768856ea928SPeter Avalos 		c->mux_pause = 1; /* wait for mux_confirm_remote_forward */
769856ea928SPeter Avalos 		/* delayed reply in mux_confirm_remote_forward */
770856ea928SPeter Avalos 		goto out;
771856ea928SPeter Avalos 	}
772856ea928SPeter Avalos 	buffer_put_int(r, MUX_S_OK);
773856ea928SPeter Avalos 	buffer_put_int(r, rid);
774856ea928SPeter Avalos  out:
775856ea928SPeter Avalos 	if (fwd_desc != NULL)
776856ea928SPeter Avalos 		xfree(fwd_desc);
777856ea928SPeter Avalos 	if (freefwd) {
778856ea928SPeter Avalos 		if (fwd.listen_host != NULL)
779856ea928SPeter Avalos 			xfree(fwd.listen_host);
780856ea928SPeter Avalos 		if (fwd.connect_host != NULL)
781856ea928SPeter Avalos 			xfree(fwd.connect_host);
782856ea928SPeter Avalos 	}
783856ea928SPeter Avalos 	return ret;
784856ea928SPeter Avalos }
785856ea928SPeter Avalos 
786856ea928SPeter Avalos static int
787856ea928SPeter Avalos process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
788856ea928SPeter Avalos {
789*99e85e0dSPeter Avalos 	Forward fwd, *found_fwd;
790856ea928SPeter Avalos 	char *fwd_desc = NULL;
791*99e85e0dSPeter Avalos 	const char *error_reason = NULL;
792856ea928SPeter Avalos 	u_int ftype;
793*99e85e0dSPeter Avalos 	int i, listen_port, ret = 0;
794856ea928SPeter Avalos 
795856ea928SPeter Avalos 	fwd.listen_host = fwd.connect_host = NULL;
796856ea928SPeter Avalos 	if (buffer_get_int_ret(&ftype, m) != 0 ||
797856ea928SPeter Avalos 	    (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
798856ea928SPeter Avalos 	    buffer_get_int_ret(&fwd.listen_port, m) != 0 ||
799856ea928SPeter Avalos 	    (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
800856ea928SPeter Avalos 	    buffer_get_int_ret(&fwd.connect_port, m) != 0) {
801856ea928SPeter Avalos 		error("%s: malformed message", __func__);
802856ea928SPeter Avalos 		ret = -1;
803856ea928SPeter Avalos 		goto out;
804856ea928SPeter Avalos 	}
805856ea928SPeter Avalos 
806856ea928SPeter Avalos 	if (*fwd.listen_host == '\0') {
807856ea928SPeter Avalos 		xfree(fwd.listen_host);
808856ea928SPeter Avalos 		fwd.listen_host = NULL;
809856ea928SPeter Avalos 	}
810856ea928SPeter Avalos 	if (*fwd.connect_host == '\0') {
811856ea928SPeter Avalos 		xfree(fwd.connect_host);
812856ea928SPeter Avalos 		fwd.connect_host = NULL;
813856ea928SPeter Avalos 	}
814856ea928SPeter Avalos 
815*99e85e0dSPeter Avalos 	debug2("%s: channel %d: request cancel %s", __func__, c->self,
816856ea928SPeter Avalos 	    (fwd_desc = format_forward(ftype, &fwd)));
817856ea928SPeter Avalos 
818*99e85e0dSPeter Avalos 	/* make sure this has been requested */
819*99e85e0dSPeter Avalos 	found_fwd = NULL;
820*99e85e0dSPeter Avalos 	switch (ftype) {
821*99e85e0dSPeter Avalos 	case MUX_FWD_LOCAL:
822*99e85e0dSPeter Avalos 	case MUX_FWD_DYNAMIC:
823*99e85e0dSPeter Avalos 		for (i = 0; i < options.num_local_forwards; i++) {
824*99e85e0dSPeter Avalos 			if (compare_forward(&fwd,
825*99e85e0dSPeter Avalos 			    options.local_forwards + i)) {
826*99e85e0dSPeter Avalos 				found_fwd = options.local_forwards + i;
827*99e85e0dSPeter Avalos 				break;
828*99e85e0dSPeter Avalos 			}
829*99e85e0dSPeter Avalos 		}
830*99e85e0dSPeter Avalos 		break;
831*99e85e0dSPeter Avalos 	case MUX_FWD_REMOTE:
832*99e85e0dSPeter Avalos 		for (i = 0; i < options.num_remote_forwards; i++) {
833*99e85e0dSPeter Avalos 			if (compare_forward(&fwd,
834*99e85e0dSPeter Avalos 			    options.remote_forwards + i)) {
835*99e85e0dSPeter Avalos 				found_fwd = options.remote_forwards + i;
836*99e85e0dSPeter Avalos 				break;
837*99e85e0dSPeter Avalos 			}
838*99e85e0dSPeter Avalos 		}
839*99e85e0dSPeter Avalos 		break;
840*99e85e0dSPeter Avalos 	}
841*99e85e0dSPeter Avalos 
842*99e85e0dSPeter Avalos 	if (found_fwd == NULL)
843*99e85e0dSPeter Avalos 		error_reason = "port not forwarded";
844*99e85e0dSPeter Avalos 	else if (ftype == MUX_FWD_REMOTE) {
845*99e85e0dSPeter Avalos 		/*
846*99e85e0dSPeter Avalos 		 * This shouldn't fail unless we confused the host/port
847*99e85e0dSPeter Avalos 		 * between options.remote_forwards and permitted_opens.
848*99e85e0dSPeter Avalos 		 * However, for dynamic allocated listen ports we need
849*99e85e0dSPeter Avalos 		 * to lookup the actual listen port.
850*99e85e0dSPeter Avalos 		 */
851*99e85e0dSPeter Avalos 	        listen_port = (fwd.listen_port == 0) ?
852*99e85e0dSPeter Avalos 		    found_fwd->allocated_port : fwd.listen_port;
853*99e85e0dSPeter Avalos 		if (channel_request_rforward_cancel(fwd.listen_host,
854*99e85e0dSPeter Avalos 		    listen_port) == -1)
855*99e85e0dSPeter Avalos 			error_reason = "port not in permitted opens";
856*99e85e0dSPeter Avalos 	} else {	/* local and dynamic forwards */
857*99e85e0dSPeter Avalos 		/* Ditto */
858*99e85e0dSPeter Avalos 		if (channel_cancel_lport_listener(fwd.listen_host,
859*99e85e0dSPeter Avalos 		    fwd.listen_port, fwd.connect_port,
860*99e85e0dSPeter Avalos 		    options.gateway_ports) == -1)
861*99e85e0dSPeter Avalos 			error_reason = "port not found";
862*99e85e0dSPeter Avalos 	}
863*99e85e0dSPeter Avalos 
864*99e85e0dSPeter Avalos 	if (error_reason == NULL) {
865*99e85e0dSPeter Avalos 		buffer_put_int(r, MUX_S_OK);
866*99e85e0dSPeter Avalos 		buffer_put_int(r, rid);
867*99e85e0dSPeter Avalos 
868*99e85e0dSPeter Avalos 		if (found_fwd->listen_host != NULL)
869*99e85e0dSPeter Avalos 			xfree(found_fwd->listen_host);
870*99e85e0dSPeter Avalos 		if (found_fwd->connect_host != NULL)
871*99e85e0dSPeter Avalos 			xfree(found_fwd->connect_host);
872*99e85e0dSPeter Avalos 		found_fwd->listen_host = found_fwd->connect_host = NULL;
873*99e85e0dSPeter Avalos 		found_fwd->listen_port = found_fwd->connect_port = 0;
874*99e85e0dSPeter Avalos 	} else {
875856ea928SPeter Avalos 		buffer_put_int(r, MUX_S_FAILURE);
876856ea928SPeter Avalos 		buffer_put_int(r, rid);
877*99e85e0dSPeter Avalos 		buffer_put_cstring(r, error_reason);
878*99e85e0dSPeter Avalos 	}
879856ea928SPeter Avalos  out:
880856ea928SPeter Avalos 	if (fwd_desc != NULL)
881856ea928SPeter Avalos 		xfree(fwd_desc);
882856ea928SPeter Avalos 	if (fwd.listen_host != NULL)
883856ea928SPeter Avalos 		xfree(fwd.listen_host);
884856ea928SPeter Avalos 	if (fwd.connect_host != NULL)
885856ea928SPeter Avalos 		xfree(fwd.connect_host);
886856ea928SPeter Avalos 
887856ea928SPeter Avalos 	return ret;
888856ea928SPeter Avalos }
889856ea928SPeter Avalos 
890856ea928SPeter Avalos static int
891856ea928SPeter Avalos process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
892856ea928SPeter Avalos {
893856ea928SPeter Avalos 	Channel *nc;
894856ea928SPeter Avalos 	char *reserved, *chost;
895856ea928SPeter Avalos 	u_int cport, i, j;
896856ea928SPeter Avalos 	int new_fd[2];
897856ea928SPeter Avalos 
898856ea928SPeter Avalos 	chost = reserved = NULL;
899856ea928SPeter Avalos 	if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
900856ea928SPeter Avalos 	   (chost = buffer_get_string_ret(m, NULL)) == NULL ||
901856ea928SPeter Avalos 	    buffer_get_int_ret(&cport, m) != 0) {
902856ea928SPeter Avalos 		if (reserved != NULL)
903856ea928SPeter Avalos 			xfree(reserved);
904856ea928SPeter Avalos 		if (chost != NULL)
905856ea928SPeter Avalos 			xfree(chost);
906856ea928SPeter Avalos 		error("%s: malformed message", __func__);
907856ea928SPeter Avalos 		return -1;
908856ea928SPeter Avalos 	}
909856ea928SPeter Avalos 	xfree(reserved);
910856ea928SPeter Avalos 
911856ea928SPeter Avalos 	debug2("%s: channel %d: request stdio fwd to %s:%u",
912856ea928SPeter Avalos 	    __func__, c->self, chost, cport);
913856ea928SPeter Avalos 
914856ea928SPeter Avalos 	/* Gather fds from client */
915856ea928SPeter Avalos 	for(i = 0; i < 2; i++) {
916856ea928SPeter Avalos 		if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
917856ea928SPeter Avalos 			error("%s: failed to receive fd %d from slave",
918856ea928SPeter Avalos 			    __func__, i);
919856ea928SPeter Avalos 			for (j = 0; j < i; j++)
920856ea928SPeter Avalos 				close(new_fd[j]);
921856ea928SPeter Avalos 			xfree(chost);
922856ea928SPeter Avalos 
923856ea928SPeter Avalos 			/* prepare reply */
924856ea928SPeter Avalos 			buffer_put_int(r, MUX_S_FAILURE);
925856ea928SPeter Avalos 			buffer_put_int(r, rid);
926856ea928SPeter Avalos 			buffer_put_cstring(r,
927856ea928SPeter Avalos 			    "did not receive file descriptors");
928856ea928SPeter Avalos 			return -1;
929856ea928SPeter Avalos 		}
930856ea928SPeter Avalos 	}
931856ea928SPeter Avalos 
932856ea928SPeter Avalos 	debug3("%s: got fds stdin %d, stdout %d", __func__,
933856ea928SPeter Avalos 	    new_fd[0], new_fd[1]);
934856ea928SPeter Avalos 
935856ea928SPeter Avalos 	/* XXX support multiple child sessions in future */
936856ea928SPeter Avalos 	if (c->remote_id != -1) {
937856ea928SPeter Avalos 		debug2("%s: session already open", __func__);
938856ea928SPeter Avalos 		/* prepare reply */
939856ea928SPeter Avalos 		buffer_put_int(r, MUX_S_FAILURE);
940856ea928SPeter Avalos 		buffer_put_int(r, rid);
941856ea928SPeter Avalos 		buffer_put_cstring(r, "Multiple sessions not supported");
942856ea928SPeter Avalos  cleanup:
943856ea928SPeter Avalos 		close(new_fd[0]);
944856ea928SPeter Avalos 		close(new_fd[1]);
945856ea928SPeter Avalos 		xfree(chost);
946856ea928SPeter Avalos 		return 0;
947856ea928SPeter Avalos 	}
948856ea928SPeter Avalos 
949856ea928SPeter Avalos 	if (options.control_master == SSHCTL_MASTER_ASK ||
950856ea928SPeter Avalos 	    options.control_master == SSHCTL_MASTER_AUTO_ASK) {
9519f304aafSPeter Avalos 		if (!ask_permission("Allow forward to %s:%u? ",
952856ea928SPeter Avalos 		    chost, cport)) {
953856ea928SPeter Avalos 			debug2("%s: stdio fwd refused by user", __func__);
954856ea928SPeter Avalos 			/* prepare reply */
955856ea928SPeter Avalos 			buffer_put_int(r, MUX_S_PERMISSION_DENIED);
956856ea928SPeter Avalos 			buffer_put_int(r, rid);
957856ea928SPeter Avalos 			buffer_put_cstring(r, "Permission denied");
958856ea928SPeter Avalos 			goto cleanup;
959856ea928SPeter Avalos 		}
960856ea928SPeter Avalos 	}
961856ea928SPeter Avalos 
962856ea928SPeter Avalos 	/* enable nonblocking unless tty */
963856ea928SPeter Avalos 	if (!isatty(new_fd[0]))
964856ea928SPeter Avalos 		set_nonblock(new_fd[0]);
965856ea928SPeter Avalos 	if (!isatty(new_fd[1]))
966856ea928SPeter Avalos 		set_nonblock(new_fd[1]);
967856ea928SPeter Avalos 
968856ea928SPeter Avalos 	nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]);
969856ea928SPeter Avalos 
970856ea928SPeter Avalos 	nc->ctl_chan = c->self;		/* link session -> control channel */
971856ea928SPeter Avalos 	c->remote_id = nc->self; 	/* link control -> session channel */
972856ea928SPeter Avalos 
973856ea928SPeter Avalos 	debug2("%s: channel_new: %d linked to control channel %d",
974856ea928SPeter Avalos 	    __func__, nc->self, nc->ctl_chan);
975856ea928SPeter Avalos 
976856ea928SPeter Avalos 	channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
977856ea928SPeter Avalos 
978856ea928SPeter Avalos 	/* prepare reply */
979856ea928SPeter Avalos 	/* XXX defer until channel confirmed */
980856ea928SPeter Avalos 	buffer_put_int(r, MUX_S_SESSION_OPENED);
981856ea928SPeter Avalos 	buffer_put_int(r, rid);
982856ea928SPeter Avalos 	buffer_put_int(r, nc->self);
983856ea928SPeter Avalos 
984856ea928SPeter Avalos 	return 0;
985856ea928SPeter Avalos }
986856ea928SPeter Avalos 
9871c188a7fSPeter Avalos static int
9881c188a7fSPeter Avalos process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
9891c188a7fSPeter Avalos {
9901c188a7fSPeter Avalos 	debug("%s: channel %d: stop listening", __func__, c->self);
9911c188a7fSPeter Avalos 
9921c188a7fSPeter Avalos 	if (options.control_master == SSHCTL_MASTER_ASK ||
9931c188a7fSPeter Avalos 	    options.control_master == SSHCTL_MASTER_AUTO_ASK) {
9941c188a7fSPeter Avalos 		if (!ask_permission("Disable further multiplexing on shared "
9951c188a7fSPeter Avalos 		    "connection to %s? ", host)) {
9961c188a7fSPeter Avalos 			debug2("%s: stop listen refused by user", __func__);
9971c188a7fSPeter Avalos 			buffer_put_int(r, MUX_S_PERMISSION_DENIED);
9981c188a7fSPeter Avalos 			buffer_put_int(r, rid);
9991c188a7fSPeter Avalos 			buffer_put_cstring(r, "Permission denied");
10001c188a7fSPeter Avalos 			return 0;
10011c188a7fSPeter Avalos 		}
10021c188a7fSPeter Avalos 	}
10031c188a7fSPeter Avalos 
10041c188a7fSPeter Avalos 	if (mux_listener_channel != NULL) {
10051c188a7fSPeter Avalos 		channel_free(mux_listener_channel);
10061c188a7fSPeter Avalos 		client_stop_mux();
10071c188a7fSPeter Avalos 		xfree(options.control_path);
10081c188a7fSPeter Avalos 		options.control_path = NULL;
10091c188a7fSPeter Avalos 		mux_listener_channel = NULL;
10101c188a7fSPeter Avalos 		muxserver_sock = -1;
10111c188a7fSPeter Avalos 	}
10121c188a7fSPeter Avalos 
10131c188a7fSPeter Avalos 	/* prepare reply */
10141c188a7fSPeter Avalos 	buffer_put_int(r, MUX_S_OK);
10151c188a7fSPeter Avalos 	buffer_put_int(r, rid);
10161c188a7fSPeter Avalos 
10171c188a7fSPeter Avalos 	return 0;
10181c188a7fSPeter Avalos }
10191c188a7fSPeter Avalos 
1020856ea928SPeter Avalos /* Channel callbacks fired on read/write from mux slave fd */
1021856ea928SPeter Avalos static int
1022856ea928SPeter Avalos mux_master_read_cb(Channel *c)
1023856ea928SPeter Avalos {
1024856ea928SPeter Avalos 	struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
1025856ea928SPeter Avalos 	Buffer in, out;
1026856ea928SPeter Avalos 	void *ptr;
1027856ea928SPeter Avalos 	u_int type, rid, have, i;
1028856ea928SPeter Avalos 	int ret = -1;
1029856ea928SPeter Avalos 
1030856ea928SPeter Avalos 	/* Setup ctx and  */
1031856ea928SPeter Avalos 	if (c->mux_ctx == NULL) {
1032856ea928SPeter Avalos 		state = xcalloc(1, sizeof(*state));
1033856ea928SPeter Avalos 		c->mux_ctx = state;
1034856ea928SPeter Avalos 		channel_register_cleanup(c->self,
1035856ea928SPeter Avalos 		    mux_master_control_cleanup_cb, 0);
1036856ea928SPeter Avalos 
1037856ea928SPeter Avalos 		/* Send hello */
1038856ea928SPeter Avalos 		buffer_init(&out);
1039856ea928SPeter Avalos 		buffer_put_int(&out, MUX_MSG_HELLO);
1040856ea928SPeter Avalos 		buffer_put_int(&out, SSHMUX_VER);
1041856ea928SPeter Avalos 		/* no extensions */
1042856ea928SPeter Avalos 		buffer_put_string(&c->output, buffer_ptr(&out),
1043856ea928SPeter Avalos 		    buffer_len(&out));
1044856ea928SPeter Avalos 		buffer_free(&out);
1045856ea928SPeter Avalos 		debug3("%s: channel %d: hello sent", __func__, c->self);
1046856ea928SPeter Avalos 		return 0;
1047856ea928SPeter Avalos 	}
1048856ea928SPeter Avalos 
1049856ea928SPeter Avalos 	buffer_init(&in);
1050856ea928SPeter Avalos 	buffer_init(&out);
1051856ea928SPeter Avalos 
1052856ea928SPeter Avalos 	/* Channel code ensures that we receive whole packets */
1053856ea928SPeter Avalos 	if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) {
1054856ea928SPeter Avalos  malf:
1055856ea928SPeter Avalos 		error("%s: malformed message", __func__);
1056856ea928SPeter Avalos 		goto out;
1057856ea928SPeter Avalos 	}
1058856ea928SPeter Avalos 	buffer_append(&in, ptr, have);
1059856ea928SPeter Avalos 
1060856ea928SPeter Avalos 	if (buffer_get_int_ret(&type, &in) != 0)
1061856ea928SPeter Avalos 		goto malf;
1062856ea928SPeter Avalos 	debug3("%s: channel %d packet type 0x%08x len %u",
1063856ea928SPeter Avalos 	    __func__, c->self, type, buffer_len(&in));
1064856ea928SPeter Avalos 
1065856ea928SPeter Avalos 	if (type == MUX_MSG_HELLO)
1066856ea928SPeter Avalos 		rid = 0;
1067856ea928SPeter Avalos 	else {
1068856ea928SPeter Avalos 		if (!state->hello_rcvd) {
1069856ea928SPeter Avalos 			error("%s: expected MUX_MSG_HELLO(0x%08x), "
1070856ea928SPeter Avalos 			    "received 0x%08x", __func__, MUX_MSG_HELLO, type);
1071856ea928SPeter Avalos 			goto out;
1072856ea928SPeter Avalos 		}
1073856ea928SPeter Avalos 		if (buffer_get_int_ret(&rid, &in) != 0)
1074856ea928SPeter Avalos 			goto malf;
1075856ea928SPeter Avalos 	}
1076856ea928SPeter Avalos 
1077856ea928SPeter Avalos 	for (i = 0; mux_master_handlers[i].handler != NULL; i++) {
1078856ea928SPeter Avalos 		if (type == mux_master_handlers[i].type) {
1079856ea928SPeter Avalos 			ret = mux_master_handlers[i].handler(rid, c, &in, &out);
1080856ea928SPeter Avalos 			break;
1081856ea928SPeter Avalos 		}
1082856ea928SPeter Avalos 	}
1083856ea928SPeter Avalos 	if (mux_master_handlers[i].handler == NULL) {
1084856ea928SPeter Avalos 		error("%s: unsupported mux message 0x%08x", __func__, type);
1085856ea928SPeter Avalos 		buffer_put_int(&out, MUX_S_FAILURE);
1086856ea928SPeter Avalos 		buffer_put_int(&out, rid);
1087856ea928SPeter Avalos 		buffer_put_cstring(&out, "unsupported request");
1088856ea928SPeter Avalos 		ret = 0;
1089856ea928SPeter Avalos 	}
1090856ea928SPeter Avalos 	/* Enqueue reply packet */
1091856ea928SPeter Avalos 	if (buffer_len(&out) != 0) {
1092856ea928SPeter Avalos 		buffer_put_string(&c->output, buffer_ptr(&out),
1093856ea928SPeter Avalos 		    buffer_len(&out));
1094856ea928SPeter Avalos 	}
1095856ea928SPeter Avalos  out:
1096856ea928SPeter Avalos 	buffer_free(&in);
1097856ea928SPeter Avalos 	buffer_free(&out);
1098856ea928SPeter Avalos 	return ret;
1099856ea928SPeter Avalos }
1100856ea928SPeter Avalos 
1101856ea928SPeter Avalos void
1102856ea928SPeter Avalos mux_exit_message(Channel *c, int exitval)
1103856ea928SPeter Avalos {
1104856ea928SPeter Avalos 	Buffer m;
1105856ea928SPeter Avalos 	Channel *mux_chan;
1106856ea928SPeter Avalos 
1107856ea928SPeter Avalos 	debug3("%s: channel %d: exit message, evitval %d", __func__, c->self,
1108856ea928SPeter Avalos 	    exitval);
1109856ea928SPeter Avalos 
1110856ea928SPeter Avalos 	if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
1111856ea928SPeter Avalos 		fatal("%s: channel %d missing mux channel %d",
1112856ea928SPeter Avalos 		    __func__, c->self, c->ctl_chan);
1113856ea928SPeter Avalos 
1114856ea928SPeter Avalos 	/* Append exit message packet to control socket output queue */
1115856ea928SPeter Avalos 	buffer_init(&m);
1116856ea928SPeter Avalos 	buffer_put_int(&m, MUX_S_EXIT_MESSAGE);
1117856ea928SPeter Avalos 	buffer_put_int(&m, c->self);
1118856ea928SPeter Avalos 	buffer_put_int(&m, exitval);
1119856ea928SPeter Avalos 
1120856ea928SPeter Avalos 	buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
1121856ea928SPeter Avalos 	buffer_free(&m);
1122856ea928SPeter Avalos }
112318de8d7fSPeter Avalos 
11241c188a7fSPeter Avalos void
11251c188a7fSPeter Avalos mux_tty_alloc_failed(Channel *c)
11261c188a7fSPeter Avalos {
11271c188a7fSPeter Avalos 	Buffer m;
11281c188a7fSPeter Avalos 	Channel *mux_chan;
11291c188a7fSPeter Avalos 
11301c188a7fSPeter Avalos 	debug3("%s: channel %d: TTY alloc failed", __func__, c->self);
11311c188a7fSPeter Avalos 
11321c188a7fSPeter Avalos 	if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
11331c188a7fSPeter Avalos 		fatal("%s: channel %d missing mux channel %d",
11341c188a7fSPeter Avalos 		    __func__, c->self, c->ctl_chan);
11351c188a7fSPeter Avalos 
11361c188a7fSPeter Avalos 	/* Append exit message packet to control socket output queue */
11371c188a7fSPeter Avalos 	buffer_init(&m);
11381c188a7fSPeter Avalos 	buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL);
11391c188a7fSPeter Avalos 	buffer_put_int(&m, c->self);
11401c188a7fSPeter Avalos 
11411c188a7fSPeter Avalos 	buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
11421c188a7fSPeter Avalos 	buffer_free(&m);
11431c188a7fSPeter Avalos }
11441c188a7fSPeter Avalos 
114518de8d7fSPeter Avalos /* Prepare a mux master to listen on a Unix domain socket. */
114618de8d7fSPeter Avalos void
114718de8d7fSPeter Avalos muxserver_listen(void)
114818de8d7fSPeter Avalos {
114918de8d7fSPeter Avalos 	struct sockaddr_un addr;
1150856ea928SPeter Avalos 	socklen_t sun_len;
115118de8d7fSPeter Avalos 	mode_t old_umask;
11529f304aafSPeter Avalos 	char *orig_control_path = options.control_path;
11539f304aafSPeter Avalos 	char rbuf[16+1];
11549f304aafSPeter Avalos 	u_int i, r;
115518de8d7fSPeter Avalos 
115618de8d7fSPeter Avalos 	if (options.control_path == NULL ||
115718de8d7fSPeter Avalos 	    options.control_master == SSHCTL_MASTER_NO)
115818de8d7fSPeter Avalos 		return;
115918de8d7fSPeter Avalos 
116018de8d7fSPeter Avalos 	debug("setting up multiplex master socket");
116118de8d7fSPeter Avalos 
11629f304aafSPeter Avalos 	/*
11639f304aafSPeter Avalos 	 * Use a temporary path before listen so we can pseudo-atomically
11649f304aafSPeter Avalos 	 * establish the listening socket in its final location to avoid
11659f304aafSPeter Avalos 	 * other processes racing in between bind() and listen() and hitting
11669f304aafSPeter Avalos 	 * an unready socket.
11679f304aafSPeter Avalos 	 */
11689f304aafSPeter Avalos 	for (i = 0; i < sizeof(rbuf) - 1; i++) {
11699f304aafSPeter Avalos 		r = arc4random_uniform(26+26+10);
11709f304aafSPeter Avalos 		rbuf[i] = (r < 26) ? 'a' + r :
11719f304aafSPeter Avalos 		    (r < 26*2) ? 'A' + r - 26 :
11729f304aafSPeter Avalos 		    '0' + r - 26 - 26;
11739f304aafSPeter Avalos 	}
11749f304aafSPeter Avalos 	rbuf[sizeof(rbuf) - 1] = '\0';
11759f304aafSPeter Avalos 	options.control_path = NULL;
11769f304aafSPeter Avalos 	xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf);
11779f304aafSPeter Avalos 	debug3("%s: temporary control path %s", __func__, options.control_path);
11789f304aafSPeter Avalos 
117918de8d7fSPeter Avalos 	memset(&addr, '\0', sizeof(addr));
118018de8d7fSPeter Avalos 	addr.sun_family = AF_UNIX;
1181856ea928SPeter Avalos 	sun_len = offsetof(struct sockaddr_un, sun_path) +
118218de8d7fSPeter Avalos 	    strlen(options.control_path) + 1;
118318de8d7fSPeter Avalos 
118418de8d7fSPeter Avalos 	if (strlcpy(addr.sun_path, options.control_path,
11851c188a7fSPeter Avalos 	    sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) {
11861c188a7fSPeter Avalos 		error("ControlPath \"%s\" too long for Unix domain socket",
11871c188a7fSPeter Avalos 		    options.control_path);
11881c188a7fSPeter Avalos 		goto disable_mux_master;
11891c188a7fSPeter Avalos 	}
119018de8d7fSPeter Avalos 
119118de8d7fSPeter Avalos 	if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
119218de8d7fSPeter Avalos 		fatal("%s socket(): %s", __func__, strerror(errno));
119318de8d7fSPeter Avalos 
119418de8d7fSPeter Avalos 	old_umask = umask(0177);
1195856ea928SPeter Avalos 	if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) {
119618de8d7fSPeter Avalos 		if (errno == EINVAL || errno == EADDRINUSE) {
119718de8d7fSPeter Avalos 			error("ControlSocket %s already exists, "
119818de8d7fSPeter Avalos 			    "disabling multiplexing", options.control_path);
11999f304aafSPeter Avalos  disable_mux_master:
12001c188a7fSPeter Avalos 			if (muxserver_sock != -1) {
120118de8d7fSPeter Avalos 				close(muxserver_sock);
120218de8d7fSPeter Avalos 				muxserver_sock = -1;
12031c188a7fSPeter Avalos 			}
1204*99e85e0dSPeter Avalos 			xfree(orig_control_path);
120518de8d7fSPeter Avalos 			xfree(options.control_path);
120618de8d7fSPeter Avalos 			options.control_path = NULL;
120718de8d7fSPeter Avalos 			options.control_master = SSHCTL_MASTER_NO;
120818de8d7fSPeter Avalos 			return;
120918de8d7fSPeter Avalos 		} else
121018de8d7fSPeter Avalos 			fatal("%s bind(): %s", __func__, strerror(errno));
121118de8d7fSPeter Avalos 	}
121218de8d7fSPeter Avalos 	umask(old_umask);
121318de8d7fSPeter Avalos 
121418de8d7fSPeter Avalos 	if (listen(muxserver_sock, 64) == -1)
121518de8d7fSPeter Avalos 		fatal("%s listen(): %s", __func__, strerror(errno));
121618de8d7fSPeter Avalos 
12179f304aafSPeter Avalos 	/* Now atomically "move" the mux socket into position */
12189f304aafSPeter Avalos 	if (link(options.control_path, orig_control_path) != 0) {
12199f304aafSPeter Avalos 		if (errno != EEXIST) {
12209f304aafSPeter Avalos 			fatal("%s: link mux listener %s => %s: %s", __func__,
12219f304aafSPeter Avalos 			    options.control_path, orig_control_path,
12229f304aafSPeter Avalos 			    strerror(errno));
12239f304aafSPeter Avalos 		}
12249f304aafSPeter Avalos 		error("ControlSocket %s already exists, disabling multiplexing",
12259f304aafSPeter Avalos 		    orig_control_path);
12269f304aafSPeter Avalos 		unlink(options.control_path);
12279f304aafSPeter Avalos 		goto disable_mux_master;
12289f304aafSPeter Avalos 	}
12299f304aafSPeter Avalos 	unlink(options.control_path);
12309f304aafSPeter Avalos 	xfree(options.control_path);
12319f304aafSPeter Avalos 	options.control_path = orig_control_path;
12329f304aafSPeter Avalos 
123318de8d7fSPeter Avalos 	set_nonblock(muxserver_sock);
1234856ea928SPeter Avalos 
1235856ea928SPeter Avalos 	mux_listener_channel = channel_new("mux listener",
1236856ea928SPeter Avalos 	    SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1,
1237856ea928SPeter Avalos 	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
12389f304aafSPeter Avalos 	    0, options.control_path, 1);
1239856ea928SPeter Avalos 	mux_listener_channel->mux_rcb = mux_master_read_cb;
1240856ea928SPeter Avalos 	debug3("%s: mux listener channel %d fd %d", __func__,
1241856ea928SPeter Avalos 	    mux_listener_channel->self, mux_listener_channel->sock);
124218de8d7fSPeter Avalos }
124318de8d7fSPeter Avalos 
124418de8d7fSPeter Avalos /* Callback on open confirmation in mux master for a mux client session. */
124518de8d7fSPeter Avalos static void
1246856ea928SPeter Avalos mux_session_confirm(int id, int success, void *arg)
124718de8d7fSPeter Avalos {
124818de8d7fSPeter Avalos 	struct mux_session_confirm_ctx *cctx = arg;
124918de8d7fSPeter Avalos 	const char *display;
1250856ea928SPeter Avalos 	Channel *c, *cc;
125118de8d7fSPeter Avalos 	int i;
1252856ea928SPeter Avalos 	Buffer reply;
125318de8d7fSPeter Avalos 
125418de8d7fSPeter Avalos 	if (cctx == NULL)
125518de8d7fSPeter Avalos 		fatal("%s: cctx == NULL", __func__);
1256856ea928SPeter Avalos 	if ((c = channel_by_id(id)) == NULL)
125718de8d7fSPeter Avalos 		fatal("%s: no channel for id %d", __func__, id);
1258856ea928SPeter Avalos 	if ((cc = channel_by_id(c->ctl_chan)) == NULL)
1259856ea928SPeter Avalos 		fatal("%s: channel %d lacks control channel %d", __func__,
1260856ea928SPeter Avalos 		    id, c->ctl_chan);
1261856ea928SPeter Avalos 
1262856ea928SPeter Avalos 	if (!success) {
1263856ea928SPeter Avalos 		debug3("%s: sending failure reply", __func__);
1264856ea928SPeter Avalos 		/* prepare reply */
1265856ea928SPeter Avalos 		buffer_init(&reply);
1266856ea928SPeter Avalos 		buffer_put_int(&reply, MUX_S_FAILURE);
1267856ea928SPeter Avalos 		buffer_put_int(&reply, cctx->rid);
1268856ea928SPeter Avalos 		buffer_put_cstring(&reply, "Session open refused by peer");
1269856ea928SPeter Avalos 		goto done;
1270856ea928SPeter Avalos 	}
127118de8d7fSPeter Avalos 
127218de8d7fSPeter Avalos 	display = getenv("DISPLAY");
127318de8d7fSPeter Avalos 	if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
127418de8d7fSPeter Avalos 		char *proto, *data;
1275856ea928SPeter Avalos 
127618de8d7fSPeter Avalos 		/* Get reasonable local authentication information. */
127718de8d7fSPeter Avalos 		client_x11_get_proto(display, options.xauth_location,
1278856ea928SPeter Avalos 		    options.forward_x11_trusted, options.forward_x11_timeout,
1279856ea928SPeter Avalos 		    &proto, &data);
128018de8d7fSPeter Avalos 		/* Request forwarding with authentication spoofing. */
1281856ea928SPeter Avalos 		debug("Requesting X11 forwarding with authentication "
1282856ea928SPeter Avalos 		    "spoofing.");
12831c188a7fSPeter Avalos 		x11_request_forwarding_with_spoofing(id, display, proto,
12841c188a7fSPeter Avalos 		    data, 1);
12851c188a7fSPeter Avalos 		client_expect_confirm(id, "X11 forwarding", CONFIRM_WARN);
12861c188a7fSPeter Avalos 		/* XXX exit_on_forward_failure */
128718de8d7fSPeter Avalos 	}
128818de8d7fSPeter Avalos 
128918de8d7fSPeter Avalos 	if (cctx->want_agent_fwd && options.forward_agent) {
129018de8d7fSPeter Avalos 		debug("Requesting authentication agent forwarding.");
129118de8d7fSPeter Avalos 		channel_request_start(id, "auth-agent-req@openssh.com", 0);
129218de8d7fSPeter Avalos 		packet_send();
129318de8d7fSPeter Avalos 	}
129418de8d7fSPeter Avalos 
129518de8d7fSPeter Avalos 	client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
129618de8d7fSPeter Avalos 	    cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);
129718de8d7fSPeter Avalos 
1298856ea928SPeter Avalos 	debug3("%s: sending success reply", __func__);
1299856ea928SPeter Avalos 	/* prepare reply */
1300856ea928SPeter Avalos 	buffer_init(&reply);
1301856ea928SPeter Avalos 	buffer_put_int(&reply, MUX_S_SESSION_OPENED);
1302856ea928SPeter Avalos 	buffer_put_int(&reply, cctx->rid);
1303856ea928SPeter Avalos 	buffer_put_int(&reply, c->self);
1304856ea928SPeter Avalos 
1305856ea928SPeter Avalos  done:
1306856ea928SPeter Avalos 	/* Send reply */
1307856ea928SPeter Avalos 	buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
1308856ea928SPeter Avalos 	buffer_free(&reply);
1309856ea928SPeter Avalos 
1310856ea928SPeter Avalos 	if (cc->mux_pause <= 0)
1311856ea928SPeter Avalos 		fatal("%s: mux_pause %d", __func__, cc->mux_pause);
1312856ea928SPeter Avalos 	cc->mux_pause = 0; /* start processing messages again */
131318de8d7fSPeter Avalos 	c->open_confirm_ctx = NULL;
131418de8d7fSPeter Avalos 	buffer_free(&cctx->cmd);
131518de8d7fSPeter Avalos 	xfree(cctx->term);
131618de8d7fSPeter Avalos 	if (cctx->env != NULL) {
131718de8d7fSPeter Avalos 		for (i = 0; cctx->env[i] != NULL; i++)
131818de8d7fSPeter Avalos 			xfree(cctx->env[i]);
131918de8d7fSPeter Avalos 		xfree(cctx->env);
132018de8d7fSPeter Avalos 	}
132118de8d7fSPeter Avalos 	xfree(cctx);
132218de8d7fSPeter Avalos }
132318de8d7fSPeter Avalos 
132418de8d7fSPeter Avalos /* ** Multiplexing client support */
132518de8d7fSPeter Avalos 
132618de8d7fSPeter Avalos /* Exit signal handler */
132718de8d7fSPeter Avalos static void
132818de8d7fSPeter Avalos control_client_sighandler(int signo)
132918de8d7fSPeter Avalos {
133018de8d7fSPeter Avalos 	muxclient_terminate = signo;
133118de8d7fSPeter Avalos }
133218de8d7fSPeter Avalos 
133318de8d7fSPeter Avalos /*
133418de8d7fSPeter Avalos  * Relay signal handler - used to pass some signals from mux client to
133518de8d7fSPeter Avalos  * mux master.
133618de8d7fSPeter Avalos  */
133718de8d7fSPeter Avalos static void
133818de8d7fSPeter Avalos control_client_sigrelay(int signo)
133918de8d7fSPeter Avalos {
134018de8d7fSPeter Avalos 	int save_errno = errno;
134118de8d7fSPeter Avalos 
134218de8d7fSPeter Avalos 	if (muxserver_pid > 1)
134318de8d7fSPeter Avalos 		kill(muxserver_pid, signo);
134418de8d7fSPeter Avalos 
134518de8d7fSPeter Avalos 	errno = save_errno;
134618de8d7fSPeter Avalos }
134718de8d7fSPeter Avalos 
134818de8d7fSPeter Avalos static int
1349856ea928SPeter Avalos mux_client_read(int fd, Buffer *b, u_int need)
135018de8d7fSPeter Avalos {
1351856ea928SPeter Avalos 	u_int have;
1352856ea928SPeter Avalos 	ssize_t len;
1353856ea928SPeter Avalos 	u_char *p;
1354856ea928SPeter Avalos 	struct pollfd pfd;
135518de8d7fSPeter Avalos 
1356856ea928SPeter Avalos 	pfd.fd = fd;
1357856ea928SPeter Avalos 	pfd.events = POLLIN;
1358856ea928SPeter Avalos 	p = buffer_append_space(b, need);
1359856ea928SPeter Avalos 	for (have = 0; have < need; ) {
1360856ea928SPeter Avalos 		if (muxclient_terminate) {
1361856ea928SPeter Avalos 			errno = EINTR;
1362856ea928SPeter Avalos 			return -1;
1363856ea928SPeter Avalos 		}
1364856ea928SPeter Avalos 		len = read(fd, p + have, need - have);
1365856ea928SPeter Avalos 		if (len < 0) {
1366856ea928SPeter Avalos 			switch (errno) {
1367856ea928SPeter Avalos #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1368856ea928SPeter Avalos 			case EWOULDBLOCK:
1369856ea928SPeter Avalos #endif
1370856ea928SPeter Avalos 			case EAGAIN:
1371856ea928SPeter Avalos 				(void)poll(&pfd, 1, -1);
1372856ea928SPeter Avalos 				/* FALLTHROUGH */
1373856ea928SPeter Avalos 			case EINTR:
1374856ea928SPeter Avalos 				continue;
1375856ea928SPeter Avalos 			default:
1376856ea928SPeter Avalos 				return -1;
1377856ea928SPeter Avalos 			}
1378856ea928SPeter Avalos 		}
1379856ea928SPeter Avalos 		if (len == 0) {
1380856ea928SPeter Avalos 			errno = EPIPE;
1381856ea928SPeter Avalos 			return -1;
1382856ea928SPeter Avalos 		}
1383856ea928SPeter Avalos 		have += (u_int)len;
1384856ea928SPeter Avalos 	}
1385856ea928SPeter Avalos 	return 0;
1386856ea928SPeter Avalos }
138718de8d7fSPeter Avalos 
1388856ea928SPeter Avalos static int
1389856ea928SPeter Avalos mux_client_write_packet(int fd, Buffer *m)
1390856ea928SPeter Avalos {
1391856ea928SPeter Avalos 	Buffer queue;
1392856ea928SPeter Avalos 	u_int have, need;
1393856ea928SPeter Avalos 	int oerrno, len;
1394856ea928SPeter Avalos 	u_char *ptr;
1395856ea928SPeter Avalos 	struct pollfd pfd;
139618de8d7fSPeter Avalos 
1397856ea928SPeter Avalos 	pfd.fd = fd;
1398856ea928SPeter Avalos 	pfd.events = POLLOUT;
1399856ea928SPeter Avalos 	buffer_init(&queue);
1400856ea928SPeter Avalos 	buffer_put_string(&queue, buffer_ptr(m), buffer_len(m));
1401856ea928SPeter Avalos 
1402856ea928SPeter Avalos 	need = buffer_len(&queue);
1403856ea928SPeter Avalos 	ptr = buffer_ptr(&queue);
1404856ea928SPeter Avalos 
1405856ea928SPeter Avalos 	for (have = 0; have < need; ) {
1406856ea928SPeter Avalos 		if (muxclient_terminate) {
1407856ea928SPeter Avalos 			buffer_free(&queue);
1408856ea928SPeter Avalos 			errno = EINTR;
1409856ea928SPeter Avalos 			return -1;
1410856ea928SPeter Avalos 		}
1411856ea928SPeter Avalos 		len = write(fd, ptr + have, need - have);
1412856ea928SPeter Avalos 		if (len < 0) {
1413856ea928SPeter Avalos 			switch (errno) {
1414856ea928SPeter Avalos #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1415856ea928SPeter Avalos 			case EWOULDBLOCK:
1416856ea928SPeter Avalos #endif
1417856ea928SPeter Avalos 			case EAGAIN:
1418856ea928SPeter Avalos 				(void)poll(&pfd, 1, -1);
1419856ea928SPeter Avalos 				/* FALLTHROUGH */
1420856ea928SPeter Avalos 			case EINTR:
1421856ea928SPeter Avalos 				continue;
1422856ea928SPeter Avalos 			default:
1423856ea928SPeter Avalos 				oerrno = errno;
1424856ea928SPeter Avalos 				buffer_free(&queue);
1425856ea928SPeter Avalos 				errno = oerrno;
1426856ea928SPeter Avalos 				return -1;
1427856ea928SPeter Avalos 			}
1428856ea928SPeter Avalos 		}
1429856ea928SPeter Avalos 		if (len == 0) {
1430856ea928SPeter Avalos 			buffer_free(&queue);
1431856ea928SPeter Avalos 			errno = EPIPE;
1432856ea928SPeter Avalos 			return -1;
1433856ea928SPeter Avalos 		}
1434856ea928SPeter Avalos 		have += (u_int)len;
1435856ea928SPeter Avalos 	}
1436856ea928SPeter Avalos 	buffer_free(&queue);
1437856ea928SPeter Avalos 	return 0;
1438856ea928SPeter Avalos }
1439856ea928SPeter Avalos 
1440856ea928SPeter Avalos static int
1441856ea928SPeter Avalos mux_client_read_packet(int fd, Buffer *m)
1442856ea928SPeter Avalos {
1443856ea928SPeter Avalos 	Buffer queue;
1444856ea928SPeter Avalos 	u_int need, have;
1445856ea928SPeter Avalos 	void *ptr;
1446856ea928SPeter Avalos 	int oerrno;
1447856ea928SPeter Avalos 
1448856ea928SPeter Avalos 	buffer_init(&queue);
1449856ea928SPeter Avalos 	if (mux_client_read(fd, &queue, 4) != 0) {
1450856ea928SPeter Avalos 		if ((oerrno = errno) == EPIPE)
1451856ea928SPeter Avalos 		debug3("%s: read header failed: %s", __func__, strerror(errno));
1452856ea928SPeter Avalos 		errno = oerrno;
1453856ea928SPeter Avalos 		return -1;
1454856ea928SPeter Avalos 	}
1455856ea928SPeter Avalos 	need = get_u32(buffer_ptr(&queue));
1456856ea928SPeter Avalos 	if (mux_client_read(fd, &queue, need) != 0) {
1457856ea928SPeter Avalos 		oerrno = errno;
1458856ea928SPeter Avalos 		debug3("%s: read body failed: %s", __func__, strerror(errno));
1459856ea928SPeter Avalos 		errno = oerrno;
1460856ea928SPeter Avalos 		return -1;
1461856ea928SPeter Avalos 	}
1462856ea928SPeter Avalos 	ptr = buffer_get_string_ptr(&queue, &have);
1463856ea928SPeter Avalos 	buffer_append(m, ptr, have);
1464856ea928SPeter Avalos 	buffer_free(&queue);
1465856ea928SPeter Avalos 	return 0;
1466856ea928SPeter Avalos }
1467856ea928SPeter Avalos 
1468856ea928SPeter Avalos static int
1469856ea928SPeter Avalos mux_client_hello_exchange(int fd)
1470856ea928SPeter Avalos {
1471856ea928SPeter Avalos 	Buffer m;
1472856ea928SPeter Avalos 	u_int type, ver;
1473856ea928SPeter Avalos 
1474856ea928SPeter Avalos 	buffer_init(&m);
1475856ea928SPeter Avalos 	buffer_put_int(&m, MUX_MSG_HELLO);
1476856ea928SPeter Avalos 	buffer_put_int(&m, SSHMUX_VER);
1477856ea928SPeter Avalos 	/* no extensions */
1478856ea928SPeter Avalos 
1479856ea928SPeter Avalos 	if (mux_client_write_packet(fd, &m) != 0)
1480856ea928SPeter Avalos 		fatal("%s: write packet: %s", __func__, strerror(errno));
1481856ea928SPeter Avalos 
1482856ea928SPeter Avalos 	buffer_clear(&m);
1483856ea928SPeter Avalos 
1484856ea928SPeter Avalos 	/* Read their HELLO */
1485856ea928SPeter Avalos 	if (mux_client_read_packet(fd, &m) != 0) {
1486856ea928SPeter Avalos 		buffer_free(&m);
1487856ea928SPeter Avalos 		return -1;
1488856ea928SPeter Avalos 	}
1489856ea928SPeter Avalos 
1490856ea928SPeter Avalos 	type = buffer_get_int(&m);
1491856ea928SPeter Avalos 	if (type != MUX_MSG_HELLO)
1492856ea928SPeter Avalos 		fatal("%s: expected HELLO (%u) received %u",
1493856ea928SPeter Avalos 		    __func__, MUX_MSG_HELLO, type);
1494856ea928SPeter Avalos 	ver = buffer_get_int(&m);
1495856ea928SPeter Avalos 	if (ver != SSHMUX_VER)
1496856ea928SPeter Avalos 		fatal("Unsupported multiplexing protocol version %d "
1497856ea928SPeter Avalos 		    "(expected %d)", ver, SSHMUX_VER);
1498856ea928SPeter Avalos 	debug2("%s: master version %u", __func__, ver);
1499856ea928SPeter Avalos 	/* No extensions are presently defined */
1500856ea928SPeter Avalos 	while (buffer_len(&m) > 0) {
1501856ea928SPeter Avalos 		char *name = buffer_get_string(&m, NULL);
1502856ea928SPeter Avalos 		char *value = buffer_get_string(&m, NULL);
1503856ea928SPeter Avalos 
1504856ea928SPeter Avalos 		debug2("Unrecognised master extension \"%s\"", name);
1505856ea928SPeter Avalos 		xfree(name);
1506856ea928SPeter Avalos 		xfree(value);
1507856ea928SPeter Avalos 	}
1508856ea928SPeter Avalos 	buffer_free(&m);
1509856ea928SPeter Avalos 	return 0;
1510856ea928SPeter Avalos }
1511856ea928SPeter Avalos 
1512856ea928SPeter Avalos static u_int
1513856ea928SPeter Avalos mux_client_request_alive(int fd)
1514856ea928SPeter Avalos {
1515856ea928SPeter Avalos 	Buffer m;
1516856ea928SPeter Avalos 	char *e;
1517856ea928SPeter Avalos 	u_int pid, type, rid;
1518856ea928SPeter Avalos 
1519856ea928SPeter Avalos 	debug3("%s: entering", __func__);
1520856ea928SPeter Avalos 
1521856ea928SPeter Avalos 	buffer_init(&m);
1522856ea928SPeter Avalos 	buffer_put_int(&m, MUX_C_ALIVE_CHECK);
1523856ea928SPeter Avalos 	buffer_put_int(&m, muxclient_request_id);
1524856ea928SPeter Avalos 
1525856ea928SPeter Avalos 	if (mux_client_write_packet(fd, &m) != 0)
1526856ea928SPeter Avalos 		fatal("%s: write packet: %s", __func__, strerror(errno));
1527856ea928SPeter Avalos 
1528856ea928SPeter Avalos 	buffer_clear(&m);
1529856ea928SPeter Avalos 
1530856ea928SPeter Avalos 	/* Read their reply */
1531856ea928SPeter Avalos 	if (mux_client_read_packet(fd, &m) != 0) {
1532856ea928SPeter Avalos 		buffer_free(&m);
1533856ea928SPeter Avalos 		return 0;
1534856ea928SPeter Avalos 	}
1535856ea928SPeter Avalos 
1536856ea928SPeter Avalos 	type = buffer_get_int(&m);
1537856ea928SPeter Avalos 	if (type != MUX_S_ALIVE) {
1538856ea928SPeter Avalos 		e = buffer_get_string(&m, NULL);
1539856ea928SPeter Avalos 		fatal("%s: master returned error: %s", __func__, e);
1540856ea928SPeter Avalos 	}
1541856ea928SPeter Avalos 
1542856ea928SPeter Avalos 	if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1543856ea928SPeter Avalos 		fatal("%s: out of sequence reply: my id %u theirs %u",
1544856ea928SPeter Avalos 		    __func__, muxclient_request_id, rid);
1545856ea928SPeter Avalos 	pid = buffer_get_int(&m);
1546856ea928SPeter Avalos 	buffer_free(&m);
1547856ea928SPeter Avalos 
1548856ea928SPeter Avalos 	debug3("%s: done pid = %u", __func__, pid);
1549856ea928SPeter Avalos 
1550856ea928SPeter Avalos 	muxclient_request_id++;
1551856ea928SPeter Avalos 
1552856ea928SPeter Avalos 	return pid;
1553856ea928SPeter Avalos }
1554856ea928SPeter Avalos 
1555856ea928SPeter Avalos static void
1556856ea928SPeter Avalos mux_client_request_terminate(int fd)
1557856ea928SPeter Avalos {
1558856ea928SPeter Avalos 	Buffer m;
1559856ea928SPeter Avalos 	char *e;
1560856ea928SPeter Avalos 	u_int type, rid;
1561856ea928SPeter Avalos 
1562856ea928SPeter Avalos 	debug3("%s: entering", __func__);
1563856ea928SPeter Avalos 
1564856ea928SPeter Avalos 	buffer_init(&m);
1565856ea928SPeter Avalos 	buffer_put_int(&m, MUX_C_TERMINATE);
1566856ea928SPeter Avalos 	buffer_put_int(&m, muxclient_request_id);
1567856ea928SPeter Avalos 
1568856ea928SPeter Avalos 	if (mux_client_write_packet(fd, &m) != 0)
1569856ea928SPeter Avalos 		fatal("%s: write packet: %s", __func__, strerror(errno));
1570856ea928SPeter Avalos 
1571856ea928SPeter Avalos 	buffer_clear(&m);
1572856ea928SPeter Avalos 
1573856ea928SPeter Avalos 	/* Read their reply */
1574856ea928SPeter Avalos 	if (mux_client_read_packet(fd, &m) != 0) {
1575856ea928SPeter Avalos 		/* Remote end exited already */
1576856ea928SPeter Avalos 		if (errno == EPIPE) {
1577856ea928SPeter Avalos 			buffer_free(&m);
1578856ea928SPeter Avalos 			return;
1579856ea928SPeter Avalos 		}
1580856ea928SPeter Avalos 		fatal("%s: read from master failed: %s",
1581856ea928SPeter Avalos 		    __func__, strerror(errno));
1582856ea928SPeter Avalos 	}
1583856ea928SPeter Avalos 
1584856ea928SPeter Avalos 	type = buffer_get_int(&m);
1585856ea928SPeter Avalos 	if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1586856ea928SPeter Avalos 		fatal("%s: out of sequence reply: my id %u theirs %u",
1587856ea928SPeter Avalos 		    __func__, muxclient_request_id, rid);
1588856ea928SPeter Avalos 	switch (type) {
1589856ea928SPeter Avalos 	case MUX_S_OK:
1590856ea928SPeter Avalos 		break;
1591856ea928SPeter Avalos 	case MUX_S_PERMISSION_DENIED:
1592856ea928SPeter Avalos 		e = buffer_get_string(&m, NULL);
1593856ea928SPeter Avalos 		fatal("Master refused termination request: %s", e);
1594856ea928SPeter Avalos 	case MUX_S_FAILURE:
1595856ea928SPeter Avalos 		e = buffer_get_string(&m, NULL);
1596856ea928SPeter Avalos 		fatal("%s: termination request failed: %s", __func__, e);
1597856ea928SPeter Avalos 	default:
1598856ea928SPeter Avalos 		fatal("%s: unexpected response from master 0x%08x",
1599856ea928SPeter Avalos 		    __func__, type);
1600856ea928SPeter Avalos 	}
1601856ea928SPeter Avalos 	buffer_free(&m);
1602856ea928SPeter Avalos 	muxclient_request_id++;
1603856ea928SPeter Avalos }
1604856ea928SPeter Avalos 
1605856ea928SPeter Avalos static int
1606*99e85e0dSPeter Avalos mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd)
1607856ea928SPeter Avalos {
1608856ea928SPeter Avalos 	Buffer m;
1609856ea928SPeter Avalos 	char *e, *fwd_desc;
1610856ea928SPeter Avalos 	u_int type, rid;
1611856ea928SPeter Avalos 
1612856ea928SPeter Avalos 	fwd_desc = format_forward(ftype, fwd);
1613*99e85e0dSPeter Avalos 	debug("Requesting %s %s",
1614*99e85e0dSPeter Avalos 	    cancel_flag ? "cancellation of" : "forwarding of", fwd_desc);
1615856ea928SPeter Avalos 	xfree(fwd_desc);
1616856ea928SPeter Avalos 
1617856ea928SPeter Avalos 	buffer_init(&m);
1618*99e85e0dSPeter Avalos 	buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD);
1619856ea928SPeter Avalos 	buffer_put_int(&m, muxclient_request_id);
1620856ea928SPeter Avalos 	buffer_put_int(&m, ftype);
1621856ea928SPeter Avalos 	buffer_put_cstring(&m,
1622856ea928SPeter Avalos 	    fwd->listen_host == NULL ? "" : fwd->listen_host);
1623856ea928SPeter Avalos 	buffer_put_int(&m, fwd->listen_port);
1624856ea928SPeter Avalos 	buffer_put_cstring(&m,
1625856ea928SPeter Avalos 	    fwd->connect_host == NULL ? "" : fwd->connect_host);
1626856ea928SPeter Avalos 	buffer_put_int(&m, fwd->connect_port);
1627856ea928SPeter Avalos 
1628856ea928SPeter Avalos 	if (mux_client_write_packet(fd, &m) != 0)
1629856ea928SPeter Avalos 		fatal("%s: write packet: %s", __func__, strerror(errno));
1630856ea928SPeter Avalos 
1631856ea928SPeter Avalos 	buffer_clear(&m);
1632856ea928SPeter Avalos 
1633856ea928SPeter Avalos 	/* Read their reply */
1634856ea928SPeter Avalos 	if (mux_client_read_packet(fd, &m) != 0) {
1635856ea928SPeter Avalos 		buffer_free(&m);
1636856ea928SPeter Avalos 		return -1;
1637856ea928SPeter Avalos 	}
1638856ea928SPeter Avalos 
1639856ea928SPeter Avalos 	type = buffer_get_int(&m);
1640856ea928SPeter Avalos 	if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1641856ea928SPeter Avalos 		fatal("%s: out of sequence reply: my id %u theirs %u",
1642856ea928SPeter Avalos 		    __func__, muxclient_request_id, rid);
1643856ea928SPeter Avalos 	switch (type) {
1644856ea928SPeter Avalos 	case MUX_S_OK:
1645856ea928SPeter Avalos 		break;
1646856ea928SPeter Avalos 	case MUX_S_REMOTE_PORT:
1647*99e85e0dSPeter Avalos 		if (cancel_flag)
1648*99e85e0dSPeter Avalos 			fatal("%s: got MUX_S_REMOTE_PORT for cancel", __func__);
1649856ea928SPeter Avalos 		fwd->allocated_port = buffer_get_int(&m);
1650856ea928SPeter Avalos 		logit("Allocated port %u for remote forward to %s:%d",
1651856ea928SPeter Avalos 		    fwd->allocated_port,
1652856ea928SPeter Avalos 		    fwd->connect_host ? fwd->connect_host : "",
1653856ea928SPeter Avalos 		    fwd->connect_port);
1654856ea928SPeter Avalos 		if (muxclient_command == SSHMUX_COMMAND_FORWARD)
1655856ea928SPeter Avalos 			fprintf(stdout, "%u\n", fwd->allocated_port);
1656856ea928SPeter Avalos 		break;
1657856ea928SPeter Avalos 	case MUX_S_PERMISSION_DENIED:
1658856ea928SPeter Avalos 		e = buffer_get_string(&m, NULL);
1659856ea928SPeter Avalos 		buffer_free(&m);
1660856ea928SPeter Avalos 		error("Master refused forwarding request: %s", e);
1661856ea928SPeter Avalos 		return -1;
1662856ea928SPeter Avalos 	case MUX_S_FAILURE:
1663856ea928SPeter Avalos 		e = buffer_get_string(&m, NULL);
1664856ea928SPeter Avalos 		buffer_free(&m);
16659f304aafSPeter Avalos 		error("%s: forwarding request failed: %s", __func__, e);
1666856ea928SPeter Avalos 		return -1;
1667856ea928SPeter Avalos 	default:
1668856ea928SPeter Avalos 		fatal("%s: unexpected response from master 0x%08x",
1669856ea928SPeter Avalos 		    __func__, type);
1670856ea928SPeter Avalos 	}
1671856ea928SPeter Avalos 	buffer_free(&m);
1672856ea928SPeter Avalos 
1673856ea928SPeter Avalos 	muxclient_request_id++;
1674856ea928SPeter Avalos 	return 0;
1675856ea928SPeter Avalos }
1676856ea928SPeter Avalos 
1677856ea928SPeter Avalos static int
1678*99e85e0dSPeter Avalos mux_client_forwards(int fd, int cancel_flag)
1679856ea928SPeter Avalos {
1680*99e85e0dSPeter Avalos 	int i, ret = 0;
1681856ea928SPeter Avalos 
1682*99e85e0dSPeter Avalos 	debug3("%s: %s forwardings: %d local, %d remote", __func__,
1683*99e85e0dSPeter Avalos 	    cancel_flag ? "cancel" : "request",
1684856ea928SPeter Avalos 	    options.num_local_forwards, options.num_remote_forwards);
1685856ea928SPeter Avalos 
1686856ea928SPeter Avalos 	/* XXX ExitOnForwardingFailure */
1687856ea928SPeter Avalos 	for (i = 0; i < options.num_local_forwards; i++) {
1688*99e85e0dSPeter Avalos 		if (mux_client_forward(fd, cancel_flag,
1689856ea928SPeter Avalos 		    options.local_forwards[i].connect_port == 0 ?
1690856ea928SPeter Avalos 		    MUX_FWD_DYNAMIC : MUX_FWD_LOCAL,
1691856ea928SPeter Avalos 		    options.local_forwards + i) != 0)
1692*99e85e0dSPeter Avalos 			ret = -1;
1693856ea928SPeter Avalos 	}
1694856ea928SPeter Avalos 	for (i = 0; i < options.num_remote_forwards; i++) {
1695*99e85e0dSPeter Avalos 		if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE,
1696856ea928SPeter Avalos 		    options.remote_forwards + i) != 0)
1697*99e85e0dSPeter Avalos 			ret = -1;
1698856ea928SPeter Avalos 	}
1699*99e85e0dSPeter Avalos 	return ret;
1700856ea928SPeter Avalos }
1701856ea928SPeter Avalos 
1702856ea928SPeter Avalos static int
1703856ea928SPeter Avalos mux_client_request_session(int fd)
1704856ea928SPeter Avalos {
1705856ea928SPeter Avalos 	Buffer m;
1706856ea928SPeter Avalos 	char *e, *term;
1707856ea928SPeter Avalos 	u_int i, rid, sid, esid, exitval, type, exitval_seen;
1708856ea928SPeter Avalos 	extern char **environ;
17091c188a7fSPeter Avalos 	int devnull, rawmode;
1710856ea928SPeter Avalos 
1711856ea928SPeter Avalos 	debug3("%s: entering", __func__);
1712856ea928SPeter Avalos 
1713856ea928SPeter Avalos 	if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
1714856ea928SPeter Avalos 		error("%s: master alive request failed", __func__);
1715856ea928SPeter Avalos 		return -1;
1716856ea928SPeter Avalos 	}
1717856ea928SPeter Avalos 
1718856ea928SPeter Avalos 	signal(SIGPIPE, SIG_IGN);
1719856ea928SPeter Avalos 
1720856ea928SPeter Avalos 	if (stdin_null_flag) {
1721856ea928SPeter Avalos 		if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
1722856ea928SPeter Avalos 			fatal("open(/dev/null): %s", strerror(errno));
1723856ea928SPeter Avalos 		if (dup2(devnull, STDIN_FILENO) == -1)
1724856ea928SPeter Avalos 			fatal("dup2: %s", strerror(errno));
1725856ea928SPeter Avalos 		if (devnull > STDERR_FILENO)
1726856ea928SPeter Avalos 			close(devnull);
1727856ea928SPeter Avalos 	}
1728856ea928SPeter Avalos 
1729856ea928SPeter Avalos 	term = getenv("TERM");
1730856ea928SPeter Avalos 
1731856ea928SPeter Avalos 	buffer_init(&m);
1732856ea928SPeter Avalos 	buffer_put_int(&m, MUX_C_NEW_SESSION);
1733856ea928SPeter Avalos 	buffer_put_int(&m, muxclient_request_id);
1734856ea928SPeter Avalos 	buffer_put_cstring(&m, ""); /* reserved */
1735856ea928SPeter Avalos 	buffer_put_int(&m, tty_flag);
1736856ea928SPeter Avalos 	buffer_put_int(&m, options.forward_x11);
1737856ea928SPeter Avalos 	buffer_put_int(&m, options.forward_agent);
1738856ea928SPeter Avalos 	buffer_put_int(&m, subsystem_flag);
1739856ea928SPeter Avalos 	buffer_put_int(&m, options.escape_char == SSH_ESCAPECHAR_NONE ?
1740856ea928SPeter Avalos 	    0xffffffff : (u_int)options.escape_char);
1741856ea928SPeter Avalos 	buffer_put_cstring(&m, term == NULL ? "" : term);
1742856ea928SPeter Avalos 	buffer_put_string(&m, buffer_ptr(&command), buffer_len(&command));
1743856ea928SPeter Avalos 
1744856ea928SPeter Avalos 	if (options.num_send_env > 0 && environ != NULL) {
1745856ea928SPeter Avalos 		/* Pass environment */
1746856ea928SPeter Avalos 		for (i = 0; environ[i] != NULL; i++) {
1747856ea928SPeter Avalos 			if (env_permitted(environ[i])) {
1748856ea928SPeter Avalos 				buffer_put_cstring(&m, environ[i]);
1749856ea928SPeter Avalos 			}
1750856ea928SPeter Avalos 		}
1751856ea928SPeter Avalos 	}
1752856ea928SPeter Avalos 
1753856ea928SPeter Avalos 	if (mux_client_write_packet(fd, &m) != 0)
1754856ea928SPeter Avalos 		fatal("%s: write packet: %s", __func__, strerror(errno));
1755856ea928SPeter Avalos 
1756856ea928SPeter Avalos 	/* Send the stdio file descriptors */
1757856ea928SPeter Avalos 	if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
1758856ea928SPeter Avalos 	    mm_send_fd(fd, STDOUT_FILENO) == -1 ||
1759856ea928SPeter Avalos 	    mm_send_fd(fd, STDERR_FILENO) == -1)
1760856ea928SPeter Avalos 		fatal("%s: send fds failed", __func__);
1761856ea928SPeter Avalos 
1762856ea928SPeter Avalos 	debug3("%s: session request sent", __func__);
1763856ea928SPeter Avalos 
1764856ea928SPeter Avalos 	/* Read their reply */
1765856ea928SPeter Avalos 	buffer_clear(&m);
1766856ea928SPeter Avalos 	if (mux_client_read_packet(fd, &m) != 0) {
1767856ea928SPeter Avalos 		error("%s: read from master failed: %s",
1768856ea928SPeter Avalos 		    __func__, strerror(errno));
1769856ea928SPeter Avalos 		buffer_free(&m);
1770856ea928SPeter Avalos 		return -1;
1771856ea928SPeter Avalos 	}
1772856ea928SPeter Avalos 
1773856ea928SPeter Avalos 	type = buffer_get_int(&m);
1774856ea928SPeter Avalos 	if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1775856ea928SPeter Avalos 		fatal("%s: out of sequence reply: my id %u theirs %u",
1776856ea928SPeter Avalos 		    __func__, muxclient_request_id, rid);
1777856ea928SPeter Avalos 	switch (type) {
1778856ea928SPeter Avalos 	case MUX_S_SESSION_OPENED:
1779856ea928SPeter Avalos 		sid = buffer_get_int(&m);
1780856ea928SPeter Avalos 		debug("%s: master session id: %u", __func__, sid);
1781856ea928SPeter Avalos 		break;
1782856ea928SPeter Avalos 	case MUX_S_PERMISSION_DENIED:
1783856ea928SPeter Avalos 		e = buffer_get_string(&m, NULL);
1784856ea928SPeter Avalos 		buffer_free(&m);
17859f304aafSPeter Avalos 		error("Master refused session request: %s", e);
1786856ea928SPeter Avalos 		return -1;
1787856ea928SPeter Avalos 	case MUX_S_FAILURE:
1788856ea928SPeter Avalos 		e = buffer_get_string(&m, NULL);
1789856ea928SPeter Avalos 		buffer_free(&m);
17909f304aafSPeter Avalos 		error("%s: session request failed: %s", __func__, e);
1791856ea928SPeter Avalos 		return -1;
1792856ea928SPeter Avalos 	default:
1793856ea928SPeter Avalos 		buffer_free(&m);
1794856ea928SPeter Avalos 		error("%s: unexpected response from master 0x%08x",
1795856ea928SPeter Avalos 		    __func__, type);
1796856ea928SPeter Avalos 		return -1;
1797856ea928SPeter Avalos 	}
1798856ea928SPeter Avalos 	muxclient_request_id++;
1799856ea928SPeter Avalos 
1800856ea928SPeter Avalos 	signal(SIGHUP, control_client_sighandler);
1801856ea928SPeter Avalos 	signal(SIGINT, control_client_sighandler);
1802856ea928SPeter Avalos 	signal(SIGTERM, control_client_sighandler);
1803856ea928SPeter Avalos 	signal(SIGWINCH, control_client_sigrelay);
1804856ea928SPeter Avalos 
18051c188a7fSPeter Avalos 	rawmode = tty_flag;
1806856ea928SPeter Avalos 	if (tty_flag)
18071c188a7fSPeter Avalos 		enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
1808856ea928SPeter Avalos 
1809856ea928SPeter Avalos 	/*
1810856ea928SPeter Avalos 	 * Stick around until the controlee closes the client_fd.
1811856ea928SPeter Avalos 	 * Before it does, it is expected to write an exit message.
1812856ea928SPeter Avalos 	 * This process must read the value and wait for the closure of
1813856ea928SPeter Avalos 	 * the client_fd; if this one closes early, the multiplex master will
1814856ea928SPeter Avalos 	 * terminate early too (possibly losing data).
1815856ea928SPeter Avalos 	 */
1816856ea928SPeter Avalos 	for (exitval = 255, exitval_seen = 0;;) {
1817856ea928SPeter Avalos 		buffer_clear(&m);
1818856ea928SPeter Avalos 		if (mux_client_read_packet(fd, &m) != 0)
1819856ea928SPeter Avalos 			break;
1820856ea928SPeter Avalos 		type = buffer_get_int(&m);
18211c188a7fSPeter Avalos 		switch (type) {
18221c188a7fSPeter Avalos 		case MUX_S_TTY_ALLOC_FAIL:
1823856ea928SPeter Avalos 			if ((esid = buffer_get_int(&m)) != sid)
18241c188a7fSPeter Avalos 				fatal("%s: tty alloc fail on unknown session: "
18251c188a7fSPeter Avalos 				    "my id %u theirs %u",
1826856ea928SPeter Avalos 				    __func__, sid, esid);
18271c188a7fSPeter Avalos 			leave_raw_mode(options.request_tty ==
18281c188a7fSPeter Avalos 			    REQUEST_TTY_FORCE);
18291c188a7fSPeter Avalos 			rawmode = 0;
18301c188a7fSPeter Avalos 			continue;
18311c188a7fSPeter Avalos 		case MUX_S_EXIT_MESSAGE:
18321c188a7fSPeter Avalos 			if ((esid = buffer_get_int(&m)) != sid)
18331c188a7fSPeter Avalos 				fatal("%s: exit on unknown session: "
18341c188a7fSPeter Avalos 				    "my id %u theirs %u",
18351c188a7fSPeter Avalos 				    __func__, sid, esid);
1836856ea928SPeter Avalos 			if (exitval_seen)
1837856ea928SPeter Avalos 				fatal("%s: exitval sent twice", __func__);
1838856ea928SPeter Avalos 			exitval = buffer_get_int(&m);
1839856ea928SPeter Avalos 			exitval_seen = 1;
18401c188a7fSPeter Avalos 			continue;
18411c188a7fSPeter Avalos 		default:
18421c188a7fSPeter Avalos 			e = buffer_get_string(&m, NULL);
18431c188a7fSPeter Avalos 			fatal("%s: master returned error: %s", __func__, e);
18441c188a7fSPeter Avalos 		}
1845856ea928SPeter Avalos 	}
1846856ea928SPeter Avalos 
1847856ea928SPeter Avalos 	close(fd);
18481c188a7fSPeter Avalos 	if (rawmode)
18491c188a7fSPeter Avalos 		leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
1850856ea928SPeter Avalos 
1851856ea928SPeter Avalos 	if (muxclient_terminate) {
1852856ea928SPeter Avalos 		debug2("Exiting on signal %d", muxclient_terminate);
1853856ea928SPeter Avalos 		exitval = 255;
1854856ea928SPeter Avalos 	} else if (!exitval_seen) {
1855856ea928SPeter Avalos 		debug2("Control master terminated unexpectedly");
1856856ea928SPeter Avalos 		exitval = 255;
1857856ea928SPeter Avalos 	} else
1858856ea928SPeter Avalos 		debug2("Received exit status from master %d", exitval);
1859856ea928SPeter Avalos 
1860856ea928SPeter Avalos 	if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
1861856ea928SPeter Avalos 		fprintf(stderr, "Shared connection to %s closed.\r\n", host);
1862856ea928SPeter Avalos 
1863856ea928SPeter Avalos 	exit(exitval);
1864856ea928SPeter Avalos }
1865856ea928SPeter Avalos 
1866856ea928SPeter Avalos static int
1867856ea928SPeter Avalos mux_client_request_stdio_fwd(int fd)
1868856ea928SPeter Avalos {
1869856ea928SPeter Avalos 	Buffer m;
1870856ea928SPeter Avalos 	char *e;
1871856ea928SPeter Avalos 	u_int type, rid, sid;
1872856ea928SPeter Avalos 	int devnull;
1873856ea928SPeter Avalos 
1874856ea928SPeter Avalos 	debug3("%s: entering", __func__);
1875856ea928SPeter Avalos 
1876856ea928SPeter Avalos 	if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
1877856ea928SPeter Avalos 		error("%s: master alive request failed", __func__);
1878856ea928SPeter Avalos 		return -1;
1879856ea928SPeter Avalos 	}
1880856ea928SPeter Avalos 
1881856ea928SPeter Avalos 	signal(SIGPIPE, SIG_IGN);
1882856ea928SPeter Avalos 
1883856ea928SPeter Avalos 	if (stdin_null_flag) {
1884856ea928SPeter Avalos 		if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
1885856ea928SPeter Avalos 			fatal("open(/dev/null): %s", strerror(errno));
1886856ea928SPeter Avalos 		if (dup2(devnull, STDIN_FILENO) == -1)
1887856ea928SPeter Avalos 			fatal("dup2: %s", strerror(errno));
1888856ea928SPeter Avalos 		if (devnull > STDERR_FILENO)
1889856ea928SPeter Avalos 			close(devnull);
1890856ea928SPeter Avalos 	}
1891856ea928SPeter Avalos 
1892856ea928SPeter Avalos 	buffer_init(&m);
1893856ea928SPeter Avalos 	buffer_put_int(&m, MUX_C_NEW_STDIO_FWD);
1894856ea928SPeter Avalos 	buffer_put_int(&m, muxclient_request_id);
1895856ea928SPeter Avalos 	buffer_put_cstring(&m, ""); /* reserved */
1896856ea928SPeter Avalos 	buffer_put_cstring(&m, stdio_forward_host);
1897856ea928SPeter Avalos 	buffer_put_int(&m, stdio_forward_port);
1898856ea928SPeter Avalos 
1899856ea928SPeter Avalos 	if (mux_client_write_packet(fd, &m) != 0)
1900856ea928SPeter Avalos 		fatal("%s: write packet: %s", __func__, strerror(errno));
1901856ea928SPeter Avalos 
1902856ea928SPeter Avalos 	/* Send the stdio file descriptors */
1903856ea928SPeter Avalos 	if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
1904856ea928SPeter Avalos 	    mm_send_fd(fd, STDOUT_FILENO) == -1)
1905856ea928SPeter Avalos 		fatal("%s: send fds failed", __func__);
1906856ea928SPeter Avalos 
1907856ea928SPeter Avalos 	debug3("%s: stdio forward request sent", __func__);
1908856ea928SPeter Avalos 
1909856ea928SPeter Avalos 	/* Read their reply */
1910856ea928SPeter Avalos 	buffer_clear(&m);
1911856ea928SPeter Avalos 
1912856ea928SPeter Avalos 	if (mux_client_read_packet(fd, &m) != 0) {
1913856ea928SPeter Avalos 		error("%s: read from master failed: %s",
1914856ea928SPeter Avalos 		    __func__, strerror(errno));
1915856ea928SPeter Avalos 		buffer_free(&m);
1916856ea928SPeter Avalos 		return -1;
1917856ea928SPeter Avalos 	}
1918856ea928SPeter Avalos 
1919856ea928SPeter Avalos 	type = buffer_get_int(&m);
1920856ea928SPeter Avalos 	if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1921856ea928SPeter Avalos 		fatal("%s: out of sequence reply: my id %u theirs %u",
1922856ea928SPeter Avalos 		    __func__, muxclient_request_id, rid);
1923856ea928SPeter Avalos 	switch (type) {
1924856ea928SPeter Avalos 	case MUX_S_SESSION_OPENED:
1925856ea928SPeter Avalos 		sid = buffer_get_int(&m);
1926856ea928SPeter Avalos 		debug("%s: master session id: %u", __func__, sid);
1927856ea928SPeter Avalos 		break;
1928856ea928SPeter Avalos 	case MUX_S_PERMISSION_DENIED:
1929856ea928SPeter Avalos 		e = buffer_get_string(&m, NULL);
1930856ea928SPeter Avalos 		buffer_free(&m);
19319f304aafSPeter Avalos 		fatal("Master refused stdio forwarding request: %s", e);
1932856ea928SPeter Avalos 	case MUX_S_FAILURE:
1933856ea928SPeter Avalos 		e = buffer_get_string(&m, NULL);
1934856ea928SPeter Avalos 		buffer_free(&m);
1935856ea928SPeter Avalos 		fatal("%s: stdio forwarding request failed: %s", __func__, e);
1936856ea928SPeter Avalos 	default:
1937856ea928SPeter Avalos 		buffer_free(&m);
1938856ea928SPeter Avalos 		error("%s: unexpected response from master 0x%08x",
1939856ea928SPeter Avalos 		    __func__, type);
1940856ea928SPeter Avalos 		return -1;
1941856ea928SPeter Avalos 	}
1942856ea928SPeter Avalos 	muxclient_request_id++;
1943856ea928SPeter Avalos 
1944856ea928SPeter Avalos 	signal(SIGHUP, control_client_sighandler);
1945856ea928SPeter Avalos 	signal(SIGINT, control_client_sighandler);
1946856ea928SPeter Avalos 	signal(SIGTERM, control_client_sighandler);
1947856ea928SPeter Avalos 	signal(SIGWINCH, control_client_sigrelay);
1948856ea928SPeter Avalos 
1949856ea928SPeter Avalos 	/*
1950856ea928SPeter Avalos 	 * Stick around until the controlee closes the client_fd.
1951856ea928SPeter Avalos 	 */
1952856ea928SPeter Avalos 	buffer_clear(&m);
1953856ea928SPeter Avalos 	if (mux_client_read_packet(fd, &m) != 0) {
1954856ea928SPeter Avalos 		if (errno == EPIPE ||
1955856ea928SPeter Avalos 		    (errno == EINTR && muxclient_terminate != 0))
1956856ea928SPeter Avalos 			return 0;
1957856ea928SPeter Avalos 		fatal("%s: mux_client_read_packet: %s",
1958856ea928SPeter Avalos 		    __func__, strerror(errno));
1959856ea928SPeter Avalos 	}
1960856ea928SPeter Avalos 	fatal("%s: master returned unexpected message %u", __func__, type);
196118de8d7fSPeter Avalos }
196218de8d7fSPeter Avalos 
19631c188a7fSPeter Avalos static void
19641c188a7fSPeter Avalos mux_client_request_stop_listening(int fd)
19651c188a7fSPeter Avalos {
19661c188a7fSPeter Avalos 	Buffer m;
19671c188a7fSPeter Avalos 	char *e;
19681c188a7fSPeter Avalos 	u_int type, rid;
19691c188a7fSPeter Avalos 
19701c188a7fSPeter Avalos 	debug3("%s: entering", __func__);
19711c188a7fSPeter Avalos 
19721c188a7fSPeter Avalos 	buffer_init(&m);
19731c188a7fSPeter Avalos 	buffer_put_int(&m, MUX_C_STOP_LISTENING);
19741c188a7fSPeter Avalos 	buffer_put_int(&m, muxclient_request_id);
19751c188a7fSPeter Avalos 
19761c188a7fSPeter Avalos 	if (mux_client_write_packet(fd, &m) != 0)
19771c188a7fSPeter Avalos 		fatal("%s: write packet: %s", __func__, strerror(errno));
19781c188a7fSPeter Avalos 
19791c188a7fSPeter Avalos 	buffer_clear(&m);
19801c188a7fSPeter Avalos 
19811c188a7fSPeter Avalos 	/* Read their reply */
19821c188a7fSPeter Avalos 	if (mux_client_read_packet(fd, &m) != 0)
19831c188a7fSPeter Avalos 		fatal("%s: read from master failed: %s",
19841c188a7fSPeter Avalos 		    __func__, strerror(errno));
19851c188a7fSPeter Avalos 
19861c188a7fSPeter Avalos 	type = buffer_get_int(&m);
19871c188a7fSPeter Avalos 	if ((rid = buffer_get_int(&m)) != muxclient_request_id)
19881c188a7fSPeter Avalos 		fatal("%s: out of sequence reply: my id %u theirs %u",
19891c188a7fSPeter Avalos 		    __func__, muxclient_request_id, rid);
19901c188a7fSPeter Avalos 	switch (type) {
19911c188a7fSPeter Avalos 	case MUX_S_OK:
19921c188a7fSPeter Avalos 		break;
19931c188a7fSPeter Avalos 	case MUX_S_PERMISSION_DENIED:
19941c188a7fSPeter Avalos 		e = buffer_get_string(&m, NULL);
19951c188a7fSPeter Avalos 		fatal("Master refused stop listening request: %s", e);
19961c188a7fSPeter Avalos 	case MUX_S_FAILURE:
19971c188a7fSPeter Avalos 		e = buffer_get_string(&m, NULL);
19981c188a7fSPeter Avalos 		fatal("%s: stop listening request failed: %s", __func__, e);
19991c188a7fSPeter Avalos 	default:
20001c188a7fSPeter Avalos 		fatal("%s: unexpected response from master 0x%08x",
20011c188a7fSPeter Avalos 		    __func__, type);
20021c188a7fSPeter Avalos 	}
20031c188a7fSPeter Avalos 	buffer_free(&m);
20041c188a7fSPeter Avalos 	muxclient_request_id++;
20051c188a7fSPeter Avalos }
20061c188a7fSPeter Avalos 
200718de8d7fSPeter Avalos /* Multiplex client main loop. */
200818de8d7fSPeter Avalos void
200918de8d7fSPeter Avalos muxclient(const char *path)
201018de8d7fSPeter Avalos {
201118de8d7fSPeter Avalos 	struct sockaddr_un addr;
2012856ea928SPeter Avalos 	socklen_t sun_len;
2013856ea928SPeter Avalos 	int sock;
2014856ea928SPeter Avalos 	u_int pid;
201518de8d7fSPeter Avalos 
2016856ea928SPeter Avalos 	if (muxclient_command == 0) {
2017856ea928SPeter Avalos 		if (stdio_forward_host != NULL)
2018856ea928SPeter Avalos 			muxclient_command = SSHMUX_COMMAND_STDIO_FWD;
2019856ea928SPeter Avalos 		else
202018de8d7fSPeter Avalos 			muxclient_command = SSHMUX_COMMAND_OPEN;
2021856ea928SPeter Avalos 	}
202218de8d7fSPeter Avalos 
202318de8d7fSPeter Avalos 	switch (options.control_master) {
202418de8d7fSPeter Avalos 	case SSHCTL_MASTER_AUTO:
202518de8d7fSPeter Avalos 	case SSHCTL_MASTER_AUTO_ASK:
202618de8d7fSPeter Avalos 		debug("auto-mux: Trying existing master");
202718de8d7fSPeter Avalos 		/* FALLTHROUGH */
202818de8d7fSPeter Avalos 	case SSHCTL_MASTER_NO:
202918de8d7fSPeter Avalos 		break;
203018de8d7fSPeter Avalos 	default:
203118de8d7fSPeter Avalos 		return;
203218de8d7fSPeter Avalos 	}
203318de8d7fSPeter Avalos 
203418de8d7fSPeter Avalos 	memset(&addr, '\0', sizeof(addr));
203518de8d7fSPeter Avalos 	addr.sun_family = AF_UNIX;
2036856ea928SPeter Avalos 	sun_len = offsetof(struct sockaddr_un, sun_path) +
203718de8d7fSPeter Avalos 	    strlen(path) + 1;
203818de8d7fSPeter Avalos 
203918de8d7fSPeter Avalos 	if (strlcpy(addr.sun_path, path,
204018de8d7fSPeter Avalos 	    sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
204118de8d7fSPeter Avalos 		fatal("ControlPath too long");
204218de8d7fSPeter Avalos 
204318de8d7fSPeter Avalos 	if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
204418de8d7fSPeter Avalos 		fatal("%s socket(): %s", __func__, strerror(errno));
204518de8d7fSPeter Avalos 
2046856ea928SPeter Avalos 	if (connect(sock, (struct sockaddr *)&addr, sun_len) == -1) {
2047856ea928SPeter Avalos 		switch (muxclient_command) {
2048856ea928SPeter Avalos 		case SSHMUX_COMMAND_OPEN:
2049856ea928SPeter Avalos 		case SSHMUX_COMMAND_STDIO_FWD:
2050856ea928SPeter Avalos 			break;
2051856ea928SPeter Avalos 		default:
205218de8d7fSPeter Avalos 			fatal("Control socket connect(%.100s): %s", path,
205318de8d7fSPeter Avalos 			    strerror(errno));
205418de8d7fSPeter Avalos 		}
20559f304aafSPeter Avalos 		if (errno == ECONNREFUSED &&
20569f304aafSPeter Avalos 		    options.control_master != SSHCTL_MASTER_NO) {
20579f304aafSPeter Avalos 			debug("Stale control socket %.100s, unlinking", path);
20589f304aafSPeter Avalos 			unlink(path);
20599f304aafSPeter Avalos 		} else if (errno == ENOENT) {
206018de8d7fSPeter Avalos 			debug("Control socket \"%.100s\" does not exist", path);
20619f304aafSPeter Avalos 		} else {
206218de8d7fSPeter Avalos 			error("Control socket connect(%.100s): %s", path,
206318de8d7fSPeter Avalos 			    strerror(errno));
206418de8d7fSPeter Avalos 		}
206518de8d7fSPeter Avalos 		close(sock);
206618de8d7fSPeter Avalos 		return;
206718de8d7fSPeter Avalos 	}
2068856ea928SPeter Avalos 	set_nonblock(sock);
206918de8d7fSPeter Avalos 
2070856ea928SPeter Avalos 	if (mux_client_hello_exchange(sock) != 0) {
2071856ea928SPeter Avalos 		error("%s: master hello exchange failed", __func__);
207218de8d7fSPeter Avalos 		close(sock);
207318de8d7fSPeter Avalos 		return;
207418de8d7fSPeter Avalos 	}
207518de8d7fSPeter Avalos 
207618de8d7fSPeter Avalos 	switch (muxclient_command) {
207718de8d7fSPeter Avalos 	case SSHMUX_COMMAND_ALIVE_CHECK:
2078856ea928SPeter Avalos 		if ((pid = mux_client_request_alive(sock)) == 0)
2079856ea928SPeter Avalos 			fatal("%s: master alive check failed", __func__);
2080856ea928SPeter Avalos 		fprintf(stderr, "Master running (pid=%d)\r\n", pid);
208118de8d7fSPeter Avalos 		exit(0);
208218de8d7fSPeter Avalos 	case SSHMUX_COMMAND_TERMINATE:
2083856ea928SPeter Avalos 		mux_client_request_terminate(sock);
208418de8d7fSPeter Avalos 		fprintf(stderr, "Exit request sent.\r\n");
208518de8d7fSPeter Avalos 		exit(0);
2086856ea928SPeter Avalos 	case SSHMUX_COMMAND_FORWARD:
2087*99e85e0dSPeter Avalos 		if (mux_client_forwards(sock, 0) != 0)
2088856ea928SPeter Avalos 			fatal("%s: master forward request failed", __func__);
2089856ea928SPeter Avalos 		exit(0);
209018de8d7fSPeter Avalos 	case SSHMUX_COMMAND_OPEN:
2091*99e85e0dSPeter Avalos 		if (mux_client_forwards(sock, 0) != 0) {
2092856ea928SPeter Avalos 			error("%s: master forward request failed", __func__);
2093856ea928SPeter Avalos 			return;
209418de8d7fSPeter Avalos 		}
2095856ea928SPeter Avalos 		mux_client_request_session(sock);
2096856ea928SPeter Avalos 		return;
2097856ea928SPeter Avalos 	case SSHMUX_COMMAND_STDIO_FWD:
2098856ea928SPeter Avalos 		mux_client_request_stdio_fwd(sock);
2099856ea928SPeter Avalos 		exit(0);
21001c188a7fSPeter Avalos 	case SSHMUX_COMMAND_STOP:
21011c188a7fSPeter Avalos 		mux_client_request_stop_listening(sock);
21021c188a7fSPeter Avalos 		fprintf(stderr, "Stop listening request sent.\r\n");
21031c188a7fSPeter Avalos 		exit(0);
2104*99e85e0dSPeter Avalos 	case SSHMUX_COMMAND_CANCEL_FWD:
2105*99e85e0dSPeter Avalos 		if (mux_client_forwards(sock, 1) != 0)
2106*99e85e0dSPeter Avalos 			error("%s: master cancel forward request failed",
2107*99e85e0dSPeter Avalos 			    __func__);
2108*99e85e0dSPeter Avalos 		exit(0);
210918de8d7fSPeter Avalos 	default:
211018de8d7fSPeter Avalos 		fatal("unrecognised muxclient_command %d", muxclient_command);
211118de8d7fSPeter Avalos 	}
211218de8d7fSPeter Avalos }
2113