blob: a6bcbbacae38d60fe537305dc9c34f9c49b19a09 [file] [log] [blame]
Damien Millerbc02f162013-04-23 19:25:49 +10001/* $OpenBSD: mux.c,v 1.40 2013/04/22 01:17:18 dtucker Exp $ */
Damien Millerb1cbfa22008-05-19 16:00:08 +10002/*
3 * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* ssh session multiplexing support */
19
Darren Tucker2fb66ca2008-06-13 04:49:33 +100020/*
21 * TODO:
Damien Millere1537f92010-01-26 13:26:22 +110022 * - Better signalling from master to slave, especially passing of
Darren Tucker2fb66ca2008-06-13 04:49:33 +100023 * error messages
Damien Millere1537f92010-01-26 13:26:22 +110024 * - Better fall-back from mux slave error to new connection.
25 * - ExitOnForwardingFailure
26 * - Maybe extension mechanisms for multi-X11/multi-agent forwarding
27 * - Support ~^Z in mux slaves.
28 * - Inspect or control sessions in master.
29 * - If we ever support the "signal" channel request, send signals on
30 * sessions in master.
Darren Tucker2fb66ca2008-06-13 04:49:33 +100031 */
32
Damien Millere1537f92010-01-26 13:26:22 +110033#include "includes.h"
34
Damien Millerb1cbfa22008-05-19 16:00:08 +100035#include <sys/types.h>
36#include <sys/param.h>
37#include <sys/stat.h>
38#include <sys/socket.h>
39#include <sys/un.h>
40
41#include <errno.h>
42#include <fcntl.h>
43#include <signal.h>
44#include <stdarg.h>
45#include <stddef.h>
46#include <stdlib.h>
47#include <stdio.h>
48#include <string.h>
49#include <unistd.h>
Darren Tuckerce38d822008-06-07 06:25:15 +100050#ifdef HAVE_PATHS_H
Damien Millerb1cbfa22008-05-19 16:00:08 +100051#include <paths.h>
Darren Tuckerce38d822008-06-07 06:25:15 +100052#endif
Damien Millerb1cbfa22008-05-19 16:00:08 +100053
Damien Millere1537f92010-01-26 13:26:22 +110054#ifdef HAVE_POLL_H
55#include <poll.h>
56#else
57# ifdef HAVE_SYS_POLL_H
58# include <sys/poll.h>
59# endif
60#endif
61
Damien Millera7058ec2008-05-20 08:57:06 +100062#ifdef HAVE_UTIL_H
63# include <util.h>
64#endif
65
Damien Millerb1cbfa22008-05-19 16:00:08 +100066#include "openbsd-compat/sys-queue.h"
67#include "xmalloc.h"
68#include "log.h"
69#include "ssh.h"
Damien Miller388f6fc2010-05-21 14:57:35 +100070#include "ssh2.h"
Damien Millerb1cbfa22008-05-19 16:00:08 +100071#include "pathnames.h"
72#include "misc.h"
73#include "match.h"
74#include "buffer.h"
75#include "channels.h"
76#include "msg.h"
77#include "packet.h"
78#include "monitor_fdpass.h"
79#include "sshpty.h"
80#include "key.h"
81#include "readconf.h"
82#include "clientloop.h"
83
84/* from ssh.c */
85extern int tty_flag;
86extern Options options;
87extern int stdin_null_flag;
88extern char *host;
Darren Tucker8ec4fd82009-10-07 08:39:57 +110089extern int subsystem_flag;
Damien Millerb1cbfa22008-05-19 16:00:08 +100090extern Buffer command;
Damien Millere1537f92010-01-26 13:26:22 +110091extern volatile sig_atomic_t quit_pending;
92extern char *stdio_forward_host;
93extern int stdio_forward_port;
Damien Millerb1cbfa22008-05-19 16:00:08 +100094
Darren Tucker2fb66ca2008-06-13 04:49:33 +100095/* Context for session open confirmation callback */
96struct mux_session_confirm_ctx {
Damien Millere1537f92010-01-26 13:26:22 +110097 u_int want_tty;
98 u_int want_subsys;
99 u_int want_x_fwd;
100 u_int want_agent_fwd;
Darren Tucker2fb66ca2008-06-13 04:49:33 +1000101 Buffer cmd;
102 char *term;
103 struct termios tio;
104 char **env;
Damien Millerd530f5f2010-05-21 14:57:10 +1000105 u_int rid;
Darren Tucker2fb66ca2008-06-13 04:49:33 +1000106};
107
Damien Miller388f6fc2010-05-21 14:57:35 +1000108/* Context for global channel callback */
109struct mux_channel_confirm_ctx {
110 u_int cid; /* channel id */
111 u_int rid; /* request id */
112 int fid; /* forward id */
113};
114
Damien Millerb1cbfa22008-05-19 16:00:08 +1000115/* fd to control socket */
116int muxserver_sock = -1;
117
Damien Millere1537f92010-01-26 13:26:22 +1100118/* client request id */
119u_int muxclient_request_id = 0;
120
Damien Millerb1cbfa22008-05-19 16:00:08 +1000121/* Multiplexing control command */
122u_int muxclient_command = 0;
123
124/* Set when signalled. */
125static volatile sig_atomic_t muxclient_terminate = 0;
126
127/* PID of multiplex server */
128static u_int muxserver_pid = 0;
129
Damien Millere1537f92010-01-26 13:26:22 +1100130static Channel *mux_listener_channel = NULL;
Damien Millerb1cbfa22008-05-19 16:00:08 +1000131
Damien Millere1537f92010-01-26 13:26:22 +1100132struct mux_master_state {
133 int hello_rcvd;
134};
135
136/* mux protocol messages */
137#define MUX_MSG_HELLO 0x00000001
138#define MUX_C_NEW_SESSION 0x10000002
139#define MUX_C_ALIVE_CHECK 0x10000004
140#define MUX_C_TERMINATE 0x10000005
141#define MUX_C_OPEN_FWD 0x10000006
142#define MUX_C_CLOSE_FWD 0x10000007
143#define MUX_C_NEW_STDIO_FWD 0x10000008
Damien Miller6c3eec72011-05-05 14:16:22 +1000144#define MUX_C_STOP_LISTENING 0x10000009
Damien Millere1537f92010-01-26 13:26:22 +1100145#define MUX_S_OK 0x80000001
146#define MUX_S_PERMISSION_DENIED 0x80000002
147#define MUX_S_FAILURE 0x80000003
148#define MUX_S_EXIT_MESSAGE 0x80000004
149#define MUX_S_ALIVE 0x80000005
150#define MUX_S_SESSION_OPENED 0x80000006
Damien Miller388f6fc2010-05-21 14:57:35 +1000151#define MUX_S_REMOTE_PORT 0x80000007
Damien Miller555f3b82011-05-15 08:48:05 +1000152#define MUX_S_TTY_ALLOC_FAIL 0x80000008
Damien Millere1537f92010-01-26 13:26:22 +1100153
154/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */
155#define MUX_FWD_LOCAL 1
156#define MUX_FWD_REMOTE 2
157#define MUX_FWD_DYNAMIC 3
158
Damien Millerd530f5f2010-05-21 14:57:10 +1000159static void mux_session_confirm(int, int, void *);
Damien Millere1537f92010-01-26 13:26:22 +1100160
161static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *);
162static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *);
163static int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *);
164static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *);
165static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *);
166static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *);
167static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *);
Damien Miller6c3eec72011-05-05 14:16:22 +1000168static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *);
Damien Millere1537f92010-01-26 13:26:22 +1100169
170static const struct {
171 u_int type;
172 int (*handler)(u_int, Channel *, Buffer *, Buffer *);
173} mux_master_handlers[] = {
174 { MUX_MSG_HELLO, process_mux_master_hello },
175 { MUX_C_NEW_SESSION, process_mux_new_session },
176 { MUX_C_ALIVE_CHECK, process_mux_alive_check },
177 { MUX_C_TERMINATE, process_mux_terminate },
178 { MUX_C_OPEN_FWD, process_mux_open_fwd },
179 { MUX_C_CLOSE_FWD, process_mux_close_fwd },
180 { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd },
Damien Miller6c3eec72011-05-05 14:16:22 +1000181 { MUX_C_STOP_LISTENING, process_mux_stop_listening },
Damien Millere1537f92010-01-26 13:26:22 +1100182 { 0, NULL }
183};
184
185/* Cleanup callback fired on closure of mux slave _session_ channel */
186/* ARGSUSED */
Darren Tucker66cb0e02012-09-06 21:19:05 +1000187void
Damien Millere1537f92010-01-26 13:26:22 +1100188mux_master_session_cleanup_cb(int cid, void *unused)
189{
190 Channel *cc, *c = channel_by_id(cid);
191
192 debug3("%s: entering for channel %d", __func__, cid);
193 if (c == NULL)
194 fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
195 if (c->ctl_chan != -1) {
196 if ((cc = channel_by_id(c->ctl_chan)) == NULL)
197 fatal("%s: channel %d missing control channel %d",
198 __func__, c->self, c->ctl_chan);
199 c->ctl_chan = -1;
200 cc->remote_id = -1;
201 chan_rcvd_oclose(cc);
202 }
203 channel_cancel_cleanup(c->self);
204}
205
206/* Cleanup callback fired on closure of mux slave _control_ channel */
207/* ARGSUSED */
208static void
209mux_master_control_cleanup_cb(int cid, void *unused)
210{
211 Channel *sc, *c = channel_by_id(cid);
212
213 debug3("%s: entering for channel %d", __func__, cid);
214 if (c == NULL)
215 fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
216 if (c->remote_id != -1) {
217 if ((sc = channel_by_id(c->remote_id)) == NULL)
Damien Miller601a23c2010-04-16 15:54:01 +1000218 fatal("%s: channel %d missing session channel %d",
Damien Millere1537f92010-01-26 13:26:22 +1100219 __func__, c->self, c->remote_id);
220 c->remote_id = -1;
221 sc->ctl_chan = -1;
Damien Miller172859c2013-04-23 15:19:27 +1000222 if (sc->type != SSH_CHANNEL_OPEN &&
223 sc->type != SSH_CHANNEL_OPENING) {
Damien Millera21cdfa2010-01-28 06:26:59 +1100224 debug2("%s: channel %d: not open", __func__, sc->self);
Damien Miller133d9d32010-01-30 17:30:04 +1100225 chan_mark_dead(sc);
Damien Millera21cdfa2010-01-28 06:26:59 +1100226 } else {
Damien Miller0dac03f2010-01-30 17:36:33 +1100227 if (sc->istate == CHAN_INPUT_OPEN)
228 chan_read_failed(sc);
229 if (sc->ostate == CHAN_OUTPUT_OPEN)
230 chan_write_failed(sc);
Damien Millera21cdfa2010-01-28 06:26:59 +1100231 }
Damien Millere1537f92010-01-26 13:26:22 +1100232 }
233 channel_cancel_cleanup(c->self);
234}
235
236/* Check mux client environment variables before passing them to mux master. */
237static int
238env_permitted(char *env)
239{
240 int i, ret;
241 char name[1024], *cp;
242
243 if ((cp = strchr(env, '=')) == NULL || cp == env)
244 return 0;
245 ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
246 if (ret <= 0 || (size_t)ret >= sizeof(name)) {
247 error("env_permitted: name '%.100s...' too long", env);
248 return 0;
249 }
250
251 for (i = 0; i < options.num_send_env; i++)
252 if (match_pattern(name, options.send_env[i]))
253 return 1;
254
255 return 0;
256}
257
258/* Mux master protocol message handlers */
259
260static int
261process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r)
262{
263 u_int ver;
264 struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
265
266 if (state == NULL)
267 fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self);
268 if (state->hello_rcvd) {
269 error("%s: HELLO received twice", __func__);
270 return -1;
271 }
272 if (buffer_get_int_ret(&ver, m) != 0) {
273 malf:
274 error("%s: malformed message", __func__);
275 return -1;
276 }
277 if (ver != SSHMUX_VER) {
278 error("Unsupported multiplexing protocol version %d "
279 "(expected %d)", ver, SSHMUX_VER);
280 return -1;
281 }
282 debug2("%s: channel %d slave version %u", __func__, c->self, ver);
283
284 /* No extensions are presently defined */
285 while (buffer_len(m) > 0) {
286 char *name = buffer_get_string_ret(m, NULL);
287 char *value = buffer_get_string_ret(m, NULL);
288
289 if (name == NULL || value == NULL) {
290 if (name != NULL)
291 xfree(name);
292 goto malf;
293 }
294 debug2("Unrecognised slave extension \"%s\"", name);
295 xfree(name);
296 xfree(value);
297 }
298 state->hello_rcvd = 1;
299 return 0;
300}
301
302static int
303process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
304{
305 Channel *nc;
306 struct mux_session_confirm_ctx *cctx;
307 char *reserved, *cmd, *cp;
308 u_int i, j, len, env_len, escape_char, window, packetmax;
309 int new_fd[3];
310
311 /* Reply for SSHMUX_COMMAND_OPEN */
312 cctx = xcalloc(1, sizeof(*cctx));
313 cctx->term = NULL;
Damien Millerd530f5f2010-05-21 14:57:10 +1000314 cctx->rid = rid;
Damien Millere1537f92010-01-26 13:26:22 +1100315 cmd = reserved = NULL;
Damien Millerab523b02012-07-06 13:44:43 +1000316 cctx->env = NULL;
317 env_len = 0;
Damien Millere1537f92010-01-26 13:26:22 +1100318 if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
319 buffer_get_int_ret(&cctx->want_tty, m) != 0 ||
320 buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 ||
321 buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 ||
322 buffer_get_int_ret(&cctx->want_subsys, m) != 0 ||
323 buffer_get_int_ret(&escape_char, m) != 0 ||
324 (cctx->term = buffer_get_string_ret(m, &len)) == NULL ||
325 (cmd = buffer_get_string_ret(m, &len)) == NULL) {
326 malf:
327 if (cmd != NULL)
328 xfree(cmd);
329 if (reserved != NULL)
330 xfree(reserved);
Damien Millerab523b02012-07-06 13:44:43 +1000331 for (j = 0; j < env_len; j++)
332 xfree(cctx->env[j]);
333 if (env_len > 0)
334 xfree(cctx->env);
Damien Millere1537f92010-01-26 13:26:22 +1100335 if (cctx->term != NULL)
336 xfree(cctx->term);
Damien Millerab523b02012-07-06 13:44:43 +1000337 xfree(cctx);
Damien Millere1537f92010-01-26 13:26:22 +1100338 error("%s: malformed message", __func__);
339 return -1;
340 }
341 xfree(reserved);
342 reserved = NULL;
343
Damien Millere1537f92010-01-26 13:26:22 +1100344 while (buffer_len(m) > 0) {
345#define MUX_MAX_ENV_VARS 4096
Damien Miller2ec03422012-02-11 08:16:28 +1100346 if ((cp = buffer_get_string_ret(m, &len)) == NULL)
Damien Millere1537f92010-01-26 13:26:22 +1100347 goto malf;
Damien Millere1537f92010-01-26 13:26:22 +1100348 if (!env_permitted(cp)) {
349 xfree(cp);
350 continue;
351 }
352 cctx->env = xrealloc(cctx->env, env_len + 2,
353 sizeof(*cctx->env));
354 cctx->env[env_len++] = cp;
355 cctx->env[env_len] = NULL;
356 if (env_len > MUX_MAX_ENV_VARS) {
357 error(">%d environment variables received, ignoring "
358 "additional", MUX_MAX_ENV_VARS);
359 break;
360 }
361 }
362
363 debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, "
364 "term \"%s\", cmd \"%s\", env %u", __func__, c->self,
365 cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd,
366 cctx->want_subsys, cctx->term, cmd, env_len);
367
368 buffer_init(&cctx->cmd);
369 buffer_append(&cctx->cmd, cmd, strlen(cmd));
370 xfree(cmd);
371 cmd = NULL;
372
373 /* Gather fds from client */
374 for(i = 0; i < 3; i++) {
375 if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
376 error("%s: failed to receive fd %d from slave",
377 __func__, i);
378 for (j = 0; j < i; j++)
379 close(new_fd[j]);
380 for (j = 0; j < env_len; j++)
381 xfree(cctx->env[j]);
382 if (env_len > 0)
383 xfree(cctx->env);
384 xfree(cctx->term);
385 buffer_free(&cctx->cmd);
386 xfree(cctx);
387
388 /* prepare reply */
389 buffer_put_int(r, MUX_S_FAILURE);
390 buffer_put_int(r, rid);
391 buffer_put_cstring(r,
392 "did not receive file descriptors");
393 return -1;
394 }
395 }
396
397 debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
398 new_fd[0], new_fd[1], new_fd[2]);
399
400 /* XXX support multiple child sessions in future */
401 if (c->remote_id != -1) {
402 debug2("%s: session already open", __func__);
403 /* prepare reply */
404 buffer_put_int(r, MUX_S_FAILURE);
405 buffer_put_int(r, rid);
406 buffer_put_cstring(r, "Multiple sessions not supported");
407 cleanup:
408 close(new_fd[0]);
409 close(new_fd[1]);
410 close(new_fd[2]);
411 xfree(cctx->term);
412 if (env_len != 0) {
413 for (i = 0; i < env_len; i++)
414 xfree(cctx->env[i]);
415 xfree(cctx->env);
416 }
417 buffer_free(&cctx->cmd);
Damien Millerab523b02012-07-06 13:44:43 +1000418 xfree(cctx);
Damien Millere1537f92010-01-26 13:26:22 +1100419 return 0;
420 }
421
422 if (options.control_master == SSHCTL_MASTER_ASK ||
423 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
424 if (!ask_permission("Allow shared connection to %s? ", host)) {
425 debug2("%s: session refused by user", __func__);
426 /* prepare reply */
427 buffer_put_int(r, MUX_S_PERMISSION_DENIED);
428 buffer_put_int(r, rid);
429 buffer_put_cstring(r, "Permission denied");
430 goto cleanup;
431 }
432 }
433
434 /* Try to pick up ttymodes from client before it goes raw */
435 if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
436 error("%s: tcgetattr: %s", __func__, strerror(errno));
437
438 /* enable nonblocking unless tty */
439 if (!isatty(new_fd[0]))
440 set_nonblock(new_fd[0]);
441 if (!isatty(new_fd[1]))
442 set_nonblock(new_fd[1]);
443 if (!isatty(new_fd[2]))
444 set_nonblock(new_fd[2]);
445
446 window = CHAN_SES_WINDOW_DEFAULT;
447 packetmax = CHAN_SES_PACKET_DEFAULT;
448 if (cctx->want_tty) {
449 window >>= 1;
450 packetmax >>= 1;
451 }
452
453 nc = channel_new("session", SSH_CHANNEL_OPENING,
454 new_fd[0], new_fd[1], new_fd[2], window, packetmax,
455 CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
456
457 nc->ctl_chan = c->self; /* link session -> control channel */
458 c->remote_id = nc->self; /* link control -> session channel */
459
460 if (cctx->want_tty && escape_char != 0xffffffff) {
461 channel_register_filter(nc->self,
462 client_simple_escape_filter, NULL,
463 client_filter_cleanup,
464 client_new_escape_filter_ctx((int)escape_char));
465 }
466
467 debug2("%s: channel_new: %d linked to control channel %d",
468 __func__, nc->self, nc->ctl_chan);
469
470 channel_send_open(nc->self);
471 channel_register_open_confirm(nc->self, mux_session_confirm, cctx);
Damien Millerd530f5f2010-05-21 14:57:10 +1000472 c->mux_pause = 1; /* stop handling messages until open_confirm done */
Damien Miller85c50d72010-05-10 11:53:02 +1000473 channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
Damien Millere1537f92010-01-26 13:26:22 +1100474
Damien Millerd530f5f2010-05-21 14:57:10 +1000475 /* reply is deferred, sent by mux_session_confirm */
Damien Millere1537f92010-01-26 13:26:22 +1100476 return 0;
477}
478
479static int
480process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r)
481{
482 debug2("%s: channel %d: alive check", __func__, c->self);
483
484 /* prepare reply */
485 buffer_put_int(r, MUX_S_ALIVE);
486 buffer_put_int(r, rid);
487 buffer_put_int(r, (u_int)getpid());
488
489 return 0;
490}
491
492static int
493process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r)
494{
495 debug2("%s: channel %d: terminate request", __func__, c->self);
496
497 if (options.control_master == SSHCTL_MASTER_ASK ||
498 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
499 if (!ask_permission("Terminate shared connection to %s? ",
500 host)) {
501 debug2("%s: termination refused by user", __func__);
502 buffer_put_int(r, MUX_S_PERMISSION_DENIED);
503 buffer_put_int(r, rid);
504 buffer_put_cstring(r, "Permission denied");
505 return 0;
506 }
507 }
508
509 quit_pending = 1;
510 buffer_put_int(r, MUX_S_OK);
511 buffer_put_int(r, rid);
512 /* XXX exit happens too soon - message never makes it to client */
513 return 0;
514}
515
516static char *
517format_forward(u_int ftype, Forward *fwd)
518{
519 char *ret;
520
521 switch (ftype) {
522 case MUX_FWD_LOCAL:
523 xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d",
524 (fwd->listen_host == NULL) ?
525 (options.gateway_ports ? "*" : "LOCALHOST") :
526 fwd->listen_host, fwd->listen_port,
527 fwd->connect_host, fwd->connect_port);
528 break;
529 case MUX_FWD_DYNAMIC:
530 xasprintf(&ret, "dynamic forward %.200s:%d -> *",
531 (fwd->listen_host == NULL) ?
532 (options.gateway_ports ? "*" : "LOCALHOST") :
533 fwd->listen_host, fwd->listen_port);
534 break;
535 case MUX_FWD_REMOTE:
536 xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d",
537 (fwd->listen_host == NULL) ?
538 "LOCALHOST" : fwd->listen_host,
539 fwd->listen_port,
540 fwd->connect_host, fwd->connect_port);
541 break;
542 default:
543 fatal("%s: unknown forward type %u", __func__, ftype);
544 }
545 return ret;
546}
547
548static int
549compare_host(const char *a, const char *b)
550{
551 if (a == NULL && b == NULL)
552 return 1;
553 if (a == NULL || b == NULL)
554 return 0;
555 return strcmp(a, b) == 0;
556}
557
558static int
559compare_forward(Forward *a, Forward *b)
560{
561 if (!compare_host(a->listen_host, b->listen_host))
562 return 0;
563 if (a->listen_port != b->listen_port)
564 return 0;
565 if (!compare_host(a->connect_host, b->connect_host))
566 return 0;
567 if (a->connect_port != b->connect_port)
568 return 0;
569
570 return 1;
571}
572
Damien Miller388f6fc2010-05-21 14:57:35 +1000573static void
574mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
575{
576 struct mux_channel_confirm_ctx *fctx = ctxt;
577 char *failmsg = NULL;
578 Forward *rfwd;
579 Channel *c;
580 Buffer out;
581
582 if ((c = channel_by_id(fctx->cid)) == NULL) {
583 /* no channel for reply */
584 error("%s: unknown channel", __func__);
585 return;
586 }
587 buffer_init(&out);
588 if (fctx->fid >= options.num_remote_forwards) {
589 xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid);
590 goto fail;
591 }
592 rfwd = &options.remote_forwards[fctx->fid];
593 debug("%s: %s for: listen %d, connect %s:%d", __func__,
594 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
595 rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
596 if (type == SSH2_MSG_REQUEST_SUCCESS) {
597 if (rfwd->listen_port == 0) {
598 rfwd->allocated_port = packet_get_int();
599 logit("Allocated port %u for mux remote forward"
600 " to %s:%d", rfwd->allocated_port,
601 rfwd->connect_host, rfwd->connect_port);
602 buffer_put_int(&out, MUX_S_REMOTE_PORT);
603 buffer_put_int(&out, fctx->rid);
604 buffer_put_int(&out, rfwd->allocated_port);
Darren Tucker68afb8c2011-10-02 18:59:03 +1100605 channel_update_permitted_opens(rfwd->handle,
606 rfwd->allocated_port);
Damien Miller388f6fc2010-05-21 14:57:35 +1000607 } else {
608 buffer_put_int(&out, MUX_S_OK);
609 buffer_put_int(&out, fctx->rid);
610 }
611 goto out;
612 } else {
Darren Tucker68afb8c2011-10-02 18:59:03 +1100613 if (rfwd->listen_port == 0)
614 channel_update_permitted_opens(rfwd->handle, -1);
Damien Miller388f6fc2010-05-21 14:57:35 +1000615 xasprintf(&failmsg, "remote port forwarding failed for "
616 "listen port %d", rfwd->listen_port);
617 }
618 fail:
619 error("%s: %s", __func__, failmsg);
620 buffer_put_int(&out, MUX_S_FAILURE);
621 buffer_put_int(&out, fctx->rid);
622 buffer_put_cstring(&out, failmsg);
623 xfree(failmsg);
624 out:
625 buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out));
626 buffer_free(&out);
627 if (c->mux_pause <= 0)
628 fatal("%s: mux_pause %d", __func__, c->mux_pause);
629 c->mux_pause = 0; /* start processing messages again */
630}
631
Damien Millere1537f92010-01-26 13:26:22 +1100632static int
633process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
634{
635 Forward fwd;
636 char *fwd_desc = NULL;
637 u_int ftype;
638 int i, ret = 0, freefwd = 1;
639
640 fwd.listen_host = fwd.connect_host = NULL;
641 if (buffer_get_int_ret(&ftype, m) != 0 ||
642 (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
643 buffer_get_int_ret(&fwd.listen_port, m) != 0 ||
644 (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
645 buffer_get_int_ret(&fwd.connect_port, m) != 0) {
646 error("%s: malformed message", __func__);
647 ret = -1;
648 goto out;
649 }
650
651 if (*fwd.listen_host == '\0') {
652 xfree(fwd.listen_host);
653 fwd.listen_host = NULL;
654 }
655 if (*fwd.connect_host == '\0') {
656 xfree(fwd.connect_host);
657 fwd.connect_host = NULL;
658 }
659
660 debug2("%s: channel %d: request %s", __func__, c->self,
661 (fwd_desc = format_forward(ftype, &fwd)));
662
663 if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE &&
664 ftype != MUX_FWD_DYNAMIC) {
665 logit("%s: invalid forwarding type %u", __func__, ftype);
666 invalid:
Damien Miller388f6fc2010-05-21 14:57:35 +1000667 if (fwd.listen_host)
668 xfree(fwd.listen_host);
669 if (fwd.connect_host)
670 xfree(fwd.connect_host);
Damien Millere1537f92010-01-26 13:26:22 +1100671 buffer_put_int(r, MUX_S_FAILURE);
672 buffer_put_int(r, rid);
673 buffer_put_cstring(r, "Invalid forwarding request");
674 return 0;
675 }
Damien Miller388f6fc2010-05-21 14:57:35 +1000676 if (fwd.listen_port >= 65536) {
Damien Millere1537f92010-01-26 13:26:22 +1100677 logit("%s: invalid listen port %u", __func__,
678 fwd.listen_port);
679 goto invalid;
680 }
681 if (fwd.connect_port >= 65536 || (ftype != MUX_FWD_DYNAMIC &&
682 ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) {
683 logit("%s: invalid connect port %u", __func__,
684 fwd.connect_port);
685 goto invalid;
686 }
687 if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL) {
688 logit("%s: missing connect host", __func__);
689 goto invalid;
690 }
691
692 /* Skip forwards that have already been requested */
693 switch (ftype) {
694 case MUX_FWD_LOCAL:
695 case MUX_FWD_DYNAMIC:
696 for (i = 0; i < options.num_local_forwards; i++) {
697 if (compare_forward(&fwd,
698 options.local_forwards + i)) {
699 exists:
700 debug2("%s: found existing forwarding",
701 __func__);
702 buffer_put_int(r, MUX_S_OK);
703 buffer_put_int(r, rid);
704 goto out;
705 }
706 }
707 break;
708 case MUX_FWD_REMOTE:
709 for (i = 0; i < options.num_remote_forwards; i++) {
710 if (compare_forward(&fwd,
Damien Miller388f6fc2010-05-21 14:57:35 +1000711 options.remote_forwards + i)) {
712 if (fwd.listen_port != 0)
713 goto exists;
714 debug2("%s: found allocated port",
715 __func__);
716 buffer_put_int(r, MUX_S_REMOTE_PORT);
717 buffer_put_int(r, rid);
718 buffer_put_int(r,
719 options.remote_forwards[i].allocated_port);
720 goto out;
721 }
Damien Millere1537f92010-01-26 13:26:22 +1100722 }
723 break;
724 }
725
726 if (options.control_master == SSHCTL_MASTER_ASK ||
727 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
728 if (!ask_permission("Open %s on %s?", fwd_desc, host)) {
729 debug2("%s: forwarding refused by user", __func__);
730 buffer_put_int(r, MUX_S_PERMISSION_DENIED);
731 buffer_put_int(r, rid);
732 buffer_put_cstring(r, "Permission denied");
733 goto out;
734 }
735 }
736
737 if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) {
Damien Miller73298f42013-01-09 15:55:50 +1100738 if (!channel_setup_local_fwd_listener(fwd.listen_host,
Damien Millere1537f92010-01-26 13:26:22 +1100739 fwd.listen_port, fwd.connect_host, fwd.connect_port,
Damien Miller73298f42013-01-09 15:55:50 +1100740 options.gateway_ports)) {
Damien Millere1537f92010-01-26 13:26:22 +1100741 fail:
742 logit("slave-requested %s failed", fwd_desc);
743 buffer_put_int(r, MUX_S_FAILURE);
744 buffer_put_int(r, rid);
745 buffer_put_cstring(r, "Port forwarding failed");
746 goto out;
747 }
748 add_local_forward(&options, &fwd);
749 freefwd = 0;
750 } else {
Damien Miller388f6fc2010-05-21 14:57:35 +1000751 struct mux_channel_confirm_ctx *fctx;
752
Darren Tucker68afb8c2011-10-02 18:59:03 +1100753 fwd.handle = channel_request_remote_forwarding(fwd.listen_host,
754 fwd.listen_port, fwd.connect_host, fwd.connect_port);
755 if (fwd.handle < 0)
Damien Millere1537f92010-01-26 13:26:22 +1100756 goto fail;
757 add_remote_forward(&options, &fwd);
Damien Miller388f6fc2010-05-21 14:57:35 +1000758 fctx = xcalloc(1, sizeof(*fctx));
759 fctx->cid = c->self;
760 fctx->rid = rid;
Damien Miller232cfb12010-06-26 09:50:30 +1000761 fctx->fid = options.num_remote_forwards - 1;
Damien Miller388f6fc2010-05-21 14:57:35 +1000762 client_register_global_confirm(mux_confirm_remote_forward,
763 fctx);
Damien Millere1537f92010-01-26 13:26:22 +1100764 freefwd = 0;
Damien Miller388f6fc2010-05-21 14:57:35 +1000765 c->mux_pause = 1; /* wait for mux_confirm_remote_forward */
766 /* delayed reply in mux_confirm_remote_forward */
767 goto out;
Damien Millere1537f92010-01-26 13:26:22 +1100768 }
769 buffer_put_int(r, MUX_S_OK);
770 buffer_put_int(r, rid);
771 out:
772 if (fwd_desc != NULL)
773 xfree(fwd_desc);
774 if (freefwd) {
775 if (fwd.listen_host != NULL)
776 xfree(fwd.listen_host);
777 if (fwd.connect_host != NULL)
778 xfree(fwd.connect_host);
779 }
780 return ret;
781}
782
783static int
784process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
785{
Damien Millerf6dff7c2011-09-22 21:38:52 +1000786 Forward fwd, *found_fwd;
Damien Millere1537f92010-01-26 13:26:22 +1100787 char *fwd_desc = NULL;
Damien Millerf6dff7c2011-09-22 21:38:52 +1000788 const char *error_reason = NULL;
Damien Millere1537f92010-01-26 13:26:22 +1100789 u_int ftype;
Darren Tucker68afb8c2011-10-02 18:59:03 +1100790 int i, listen_port, ret = 0;
Damien Millere1537f92010-01-26 13:26:22 +1100791
792 fwd.listen_host = fwd.connect_host = NULL;
793 if (buffer_get_int_ret(&ftype, m) != 0 ||
794 (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
795 buffer_get_int_ret(&fwd.listen_port, m) != 0 ||
796 (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
797 buffer_get_int_ret(&fwd.connect_port, m) != 0) {
798 error("%s: malformed message", __func__);
799 ret = -1;
800 goto out;
801 }
802
803 if (*fwd.listen_host == '\0') {
804 xfree(fwd.listen_host);
805 fwd.listen_host = NULL;
806 }
807 if (*fwd.connect_host == '\0') {
808 xfree(fwd.connect_host);
809 fwd.connect_host = NULL;
810 }
811
Damien Millerf6dff7c2011-09-22 21:38:52 +1000812 debug2("%s: channel %d: request cancel %s", __func__, c->self,
Damien Millere1537f92010-01-26 13:26:22 +1100813 (fwd_desc = format_forward(ftype, &fwd)));
814
Damien Millerf6dff7c2011-09-22 21:38:52 +1000815 /* make sure this has been requested */
816 found_fwd = NULL;
817 switch (ftype) {
818 case MUX_FWD_LOCAL:
819 case MUX_FWD_DYNAMIC:
820 for (i = 0; i < options.num_local_forwards; i++) {
821 if (compare_forward(&fwd,
822 options.local_forwards + i)) {
823 found_fwd = options.local_forwards + i;
824 break;
825 }
826 }
827 break;
828 case MUX_FWD_REMOTE:
829 for (i = 0; i < options.num_remote_forwards; i++) {
830 if (compare_forward(&fwd,
831 options.remote_forwards + i)) {
832 found_fwd = options.remote_forwards + i;
833 break;
834 }
835 }
836 break;
837 }
Damien Millere1537f92010-01-26 13:26:22 +1100838
Damien Millerf6dff7c2011-09-22 21:38:52 +1000839 if (found_fwd == NULL)
840 error_reason = "port not forwarded";
841 else if (ftype == MUX_FWD_REMOTE) {
842 /*
843 * This shouldn't fail unless we confused the host/port
844 * between options.remote_forwards and permitted_opens.
Darren Tucker68afb8c2011-10-02 18:59:03 +1100845 * However, for dynamic allocated listen ports we need
846 * to lookup the actual listen port.
Damien Millerf6dff7c2011-09-22 21:38:52 +1000847 */
Darren Tucker68afb8c2011-10-02 18:59:03 +1100848 listen_port = (fwd.listen_port == 0) ?
849 found_fwd->allocated_port : fwd.listen_port;
Damien Millerf6dff7c2011-09-22 21:38:52 +1000850 if (channel_request_rforward_cancel(fwd.listen_host,
Darren Tucker68afb8c2011-10-02 18:59:03 +1100851 listen_port) == -1)
Damien Millerf6dff7c2011-09-22 21:38:52 +1000852 error_reason = "port not in permitted opens";
853 } else { /* local and dynamic forwards */
854 /* Ditto */
855 if (channel_cancel_lport_listener(fwd.listen_host,
856 fwd.listen_port, fwd.connect_port,
857 options.gateway_ports) == -1)
858 error_reason = "port not found";
859 }
860
861 if (error_reason == NULL) {
862 buffer_put_int(r, MUX_S_OK);
863 buffer_put_int(r, rid);
864
865 if (found_fwd->listen_host != NULL)
866 xfree(found_fwd->listen_host);
867 if (found_fwd->connect_host != NULL)
868 xfree(found_fwd->connect_host);
869 found_fwd->listen_host = found_fwd->connect_host = NULL;
870 found_fwd->listen_port = found_fwd->connect_port = 0;
871 } else {
872 buffer_put_int(r, MUX_S_FAILURE);
873 buffer_put_int(r, rid);
874 buffer_put_cstring(r, error_reason);
875 }
Damien Millere1537f92010-01-26 13:26:22 +1100876 out:
877 if (fwd_desc != NULL)
878 xfree(fwd_desc);
879 if (fwd.listen_host != NULL)
880 xfree(fwd.listen_host);
881 if (fwd.connect_host != NULL)
882 xfree(fwd.connect_host);
883
884 return ret;
885}
886
887static int
888process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
889{
890 Channel *nc;
891 char *reserved, *chost;
892 u_int cport, i, j;
893 int new_fd[2];
894
895 chost = reserved = NULL;
896 if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
897 (chost = buffer_get_string_ret(m, NULL)) == NULL ||
898 buffer_get_int_ret(&cport, m) != 0) {
899 if (reserved != NULL)
900 xfree(reserved);
901 if (chost != NULL)
902 xfree(chost);
903 error("%s: malformed message", __func__);
904 return -1;
905 }
906 xfree(reserved);
907
908 debug2("%s: channel %d: request stdio fwd to %s:%u",
909 __func__, c->self, chost, cport);
910
911 /* Gather fds from client */
912 for(i = 0; i < 2; i++) {
913 if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
914 error("%s: failed to receive fd %d from slave",
915 __func__, i);
916 for (j = 0; j < i; j++)
917 close(new_fd[j]);
918 xfree(chost);
919
920 /* prepare reply */
921 buffer_put_int(r, MUX_S_FAILURE);
922 buffer_put_int(r, rid);
923 buffer_put_cstring(r,
924 "did not receive file descriptors");
925 return -1;
926 }
927 }
928
929 debug3("%s: got fds stdin %d, stdout %d", __func__,
930 new_fd[0], new_fd[1]);
931
932 /* XXX support multiple child sessions in future */
933 if (c->remote_id != -1) {
934 debug2("%s: session already open", __func__);
935 /* prepare reply */
936 buffer_put_int(r, MUX_S_FAILURE);
937 buffer_put_int(r, rid);
938 buffer_put_cstring(r, "Multiple sessions not supported");
939 cleanup:
940 close(new_fd[0]);
941 close(new_fd[1]);
942 xfree(chost);
943 return 0;
944 }
945
946 if (options.control_master == SSHCTL_MASTER_ASK ||
947 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
Damien Miller68512c02010-10-21 15:21:11 +1100948 if (!ask_permission("Allow forward to %s:%u? ",
Damien Millere1537f92010-01-26 13:26:22 +1100949 chost, cport)) {
950 debug2("%s: stdio fwd refused by user", __func__);
951 /* prepare reply */
952 buffer_put_int(r, MUX_S_PERMISSION_DENIED);
953 buffer_put_int(r, rid);
954 buffer_put_cstring(r, "Permission denied");
955 goto cleanup;
956 }
957 }
958
959 /* enable nonblocking unless tty */
960 if (!isatty(new_fd[0]))
961 set_nonblock(new_fd[0]);
962 if (!isatty(new_fd[1]))
963 set_nonblock(new_fd[1]);
964
965 nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]);
966
967 nc->ctl_chan = c->self; /* link session -> control channel */
968 c->remote_id = nc->self; /* link control -> session channel */
969
970 debug2("%s: channel_new: %d linked to control channel %d",
971 __func__, nc->self, nc->ctl_chan);
972
Damien Miller85c50d72010-05-10 11:53:02 +1000973 channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
Damien Millere1537f92010-01-26 13:26:22 +1100974
975 /* prepare reply */
976 /* XXX defer until channel confirmed */
977 buffer_put_int(r, MUX_S_SESSION_OPENED);
978 buffer_put_int(r, rid);
979 buffer_put_int(r, nc->self);
980
981 return 0;
982}
983
Damien Miller6c3eec72011-05-05 14:16:22 +1000984static int
985process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
986{
987 debug("%s: channel %d: stop listening", __func__, c->self);
988
989 if (options.control_master == SSHCTL_MASTER_ASK ||
990 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
991 if (!ask_permission("Disable further multiplexing on shared "
992 "connection to %s? ", host)) {
993 debug2("%s: stop listen refused by user", __func__);
994 buffer_put_int(r, MUX_S_PERMISSION_DENIED);
995 buffer_put_int(r, rid);
996 buffer_put_cstring(r, "Permission denied");
997 return 0;
998 }
999 }
1000
1001 if (mux_listener_channel != NULL) {
1002 channel_free(mux_listener_channel);
1003 client_stop_mux();
1004 xfree(options.control_path);
1005 options.control_path = NULL;
1006 mux_listener_channel = NULL;
1007 muxserver_sock = -1;
1008 }
1009
1010 /* prepare reply */
1011 buffer_put_int(r, MUX_S_OK);
1012 buffer_put_int(r, rid);
1013
1014 return 0;
1015}
1016
Damien Millere1537f92010-01-26 13:26:22 +11001017/* Channel callbacks fired on read/write from mux slave fd */
1018static int
1019mux_master_read_cb(Channel *c)
1020{
1021 struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
1022 Buffer in, out;
1023 void *ptr;
1024 u_int type, rid, have, i;
1025 int ret = -1;
1026
1027 /* Setup ctx and */
1028 if (c->mux_ctx == NULL) {
Damien Millerc094d1e2010-06-26 09:36:34 +10001029 state = xcalloc(1, sizeof(*state));
Damien Millere1537f92010-01-26 13:26:22 +11001030 c->mux_ctx = state;
1031 channel_register_cleanup(c->self,
1032 mux_master_control_cleanup_cb, 0);
1033
1034 /* Send hello */
1035 buffer_init(&out);
1036 buffer_put_int(&out, MUX_MSG_HELLO);
1037 buffer_put_int(&out, SSHMUX_VER);
1038 /* no extensions */
1039 buffer_put_string(&c->output, buffer_ptr(&out),
1040 buffer_len(&out));
1041 buffer_free(&out);
1042 debug3("%s: channel %d: hello sent", __func__, c->self);
1043 return 0;
1044 }
1045
1046 buffer_init(&in);
1047 buffer_init(&out);
1048
1049 /* Channel code ensures that we receive whole packets */
1050 if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) {
1051 malf:
1052 error("%s: malformed message", __func__);
1053 goto out;
1054 }
1055 buffer_append(&in, ptr, have);
1056
1057 if (buffer_get_int_ret(&type, &in) != 0)
1058 goto malf;
1059 debug3("%s: channel %d packet type 0x%08x len %u",
1060 __func__, c->self, type, buffer_len(&in));
1061
1062 if (type == MUX_MSG_HELLO)
1063 rid = 0;
1064 else {
1065 if (!state->hello_rcvd) {
1066 error("%s: expected MUX_MSG_HELLO(0x%08x), "
1067 "received 0x%08x", __func__, MUX_MSG_HELLO, type);
1068 goto out;
1069 }
1070 if (buffer_get_int_ret(&rid, &in) != 0)
1071 goto malf;
1072 }
1073
1074 for (i = 0; mux_master_handlers[i].handler != NULL; i++) {
1075 if (type == mux_master_handlers[i].type) {
1076 ret = mux_master_handlers[i].handler(rid, c, &in, &out);
1077 break;
1078 }
1079 }
1080 if (mux_master_handlers[i].handler == NULL) {
1081 error("%s: unsupported mux message 0x%08x", __func__, type);
1082 buffer_put_int(&out, MUX_S_FAILURE);
1083 buffer_put_int(&out, rid);
1084 buffer_put_cstring(&out, "unsupported request");
1085 ret = 0;
1086 }
1087 /* Enqueue reply packet */
1088 if (buffer_len(&out) != 0) {
1089 buffer_put_string(&c->output, buffer_ptr(&out),
1090 buffer_len(&out));
1091 }
1092 out:
1093 buffer_free(&in);
1094 buffer_free(&out);
1095 return ret;
1096}
1097
1098void
1099mux_exit_message(Channel *c, int exitval)
1100{
1101 Buffer m;
1102 Channel *mux_chan;
1103
Damien Millerbc02f162013-04-23 19:25:49 +10001104 debug3("%s: channel %d: exit message, exitval %d", __func__, c->self,
Damien Millere1537f92010-01-26 13:26:22 +11001105 exitval);
1106
1107 if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
1108 fatal("%s: channel %d missing mux channel %d",
1109 __func__, c->self, c->ctl_chan);
1110
1111 /* Append exit message packet to control socket output queue */
1112 buffer_init(&m);
1113 buffer_put_int(&m, MUX_S_EXIT_MESSAGE);
1114 buffer_put_int(&m, c->self);
1115 buffer_put_int(&m, exitval);
1116
1117 buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
1118 buffer_free(&m);
1119}
Damien Millerb1cbfa22008-05-19 16:00:08 +10001120
Damien Miller555f3b82011-05-15 08:48:05 +10001121void
1122mux_tty_alloc_failed(Channel *c)
1123{
1124 Buffer m;
1125 Channel *mux_chan;
1126
1127 debug3("%s: channel %d: TTY alloc failed", __func__, c->self);
1128
1129 if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
1130 fatal("%s: channel %d missing mux channel %d",
1131 __func__, c->self, c->ctl_chan);
1132
1133 /* Append exit message packet to control socket output queue */
1134 buffer_init(&m);
1135 buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL);
1136 buffer_put_int(&m, c->self);
1137
1138 buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
1139 buffer_free(&m);
1140}
1141
Damien Millerb1cbfa22008-05-19 16:00:08 +10001142/* Prepare a mux master to listen on a Unix domain socket. */
1143void
1144muxserver_listen(void)
1145{
1146 struct sockaddr_un addr;
Damien Millere1537f92010-01-26 13:26:22 +11001147 socklen_t sun_len;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001148 mode_t old_umask;
Damien Miller603134e2010-09-24 22:07:55 +10001149 char *orig_control_path = options.control_path;
1150 char rbuf[16+1];
1151 u_int i, r;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001152
1153 if (options.control_path == NULL ||
1154 options.control_master == SSHCTL_MASTER_NO)
1155 return;
1156
1157 debug("setting up multiplex master socket");
1158
Damien Miller603134e2010-09-24 22:07:55 +10001159 /*
1160 * Use a temporary path before listen so we can pseudo-atomically
1161 * establish the listening socket in its final location to avoid
1162 * other processes racing in between bind() and listen() and hitting
1163 * an unready socket.
1164 */
1165 for (i = 0; i < sizeof(rbuf) - 1; i++) {
1166 r = arc4random_uniform(26+26+10);
1167 rbuf[i] = (r < 26) ? 'a' + r :
1168 (r < 26*2) ? 'A' + r - 26 :
1169 '0' + r - 26 - 26;
1170 }
1171 rbuf[sizeof(rbuf) - 1] = '\0';
1172 options.control_path = NULL;
1173 xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf);
1174 debug3("%s: temporary control path %s", __func__, options.control_path);
1175
Damien Millerb1cbfa22008-05-19 16:00:08 +10001176 memset(&addr, '\0', sizeof(addr));
1177 addr.sun_family = AF_UNIX;
Damien Millere1537f92010-01-26 13:26:22 +11001178 sun_len = offsetof(struct sockaddr_un, sun_path) +
Damien Millerb1cbfa22008-05-19 16:00:08 +10001179 strlen(options.control_path) + 1;
1180
1181 if (strlcpy(addr.sun_path, options.control_path,
Damien Miller60432d82011-05-15 08:34:46 +10001182 sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) {
1183 error("ControlPath \"%s\" too long for Unix domain socket",
1184 options.control_path);
1185 goto disable_mux_master;
1186 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10001187
1188 if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1189 fatal("%s socket(): %s", __func__, strerror(errno));
1190
1191 old_umask = umask(0177);
Damien Millere1537f92010-01-26 13:26:22 +11001192 if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) {
Darren Tuckerca19bfe2008-06-13 10:24:03 +10001193 if (errno == EINVAL || errno == EADDRINUSE) {
1194 error("ControlSocket %s already exists, "
1195 "disabling multiplexing", options.control_path);
Damien Miller603134e2010-09-24 22:07:55 +10001196 disable_mux_master:
Damien Miller60432d82011-05-15 08:34:46 +10001197 if (muxserver_sock != -1) {
1198 close(muxserver_sock);
1199 muxserver_sock = -1;
1200 }
Damien Miller2e7decf2012-06-20 21:52:00 +10001201 xfree(orig_control_path);
Darren Tuckerca19bfe2008-06-13 10:24:03 +10001202 xfree(options.control_path);
1203 options.control_path = NULL;
1204 options.control_master = SSHCTL_MASTER_NO;
1205 return;
1206 } else
Damien Millerb1cbfa22008-05-19 16:00:08 +10001207 fatal("%s bind(): %s", __func__, strerror(errno));
1208 }
1209 umask(old_umask);
1210
1211 if (listen(muxserver_sock, 64) == -1)
1212 fatal("%s listen(): %s", __func__, strerror(errno));
1213
Damien Miller603134e2010-09-24 22:07:55 +10001214 /* Now atomically "move" the mux socket into position */
1215 if (link(options.control_path, orig_control_path) != 0) {
1216 if (errno != EEXIST) {
1217 fatal("%s: link mux listener %s => %s: %s", __func__,
1218 options.control_path, orig_control_path,
1219 strerror(errno));
1220 }
1221 error("ControlSocket %s already exists, disabling multiplexing",
1222 orig_control_path);
Damien Miller603134e2010-09-24 22:07:55 +10001223 unlink(options.control_path);
1224 goto disable_mux_master;
1225 }
1226 unlink(options.control_path);
1227 xfree(options.control_path);
1228 options.control_path = orig_control_path;
1229
Damien Millerb1cbfa22008-05-19 16:00:08 +10001230 set_nonblock(muxserver_sock);
Damien Millere1537f92010-01-26 13:26:22 +11001231
1232 mux_listener_channel = channel_new("mux listener",
1233 SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1,
1234 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
Damien Miller603134e2010-09-24 22:07:55 +10001235 0, options.control_path, 1);
Damien Millere1537f92010-01-26 13:26:22 +11001236 mux_listener_channel->mux_rcb = mux_master_read_cb;
1237 debug3("%s: mux listener channel %d fd %d", __func__,
1238 mux_listener_channel->self, mux_listener_channel->sock);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001239}
1240
1241/* Callback on open confirmation in mux master for a mux client session. */
1242static void
Damien Millerd530f5f2010-05-21 14:57:10 +10001243mux_session_confirm(int id, int success, void *arg)
Damien Millerb1cbfa22008-05-19 16:00:08 +10001244{
1245 struct mux_session_confirm_ctx *cctx = arg;
1246 const char *display;
Damien Millerd530f5f2010-05-21 14:57:10 +10001247 Channel *c, *cc;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001248 int i;
Damien Millerd530f5f2010-05-21 14:57:10 +10001249 Buffer reply;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001250
1251 if (cctx == NULL)
1252 fatal("%s: cctx == NULL", __func__);
Damien Millere1537f92010-01-26 13:26:22 +11001253 if ((c = channel_by_id(id)) == NULL)
Damien Millerb1cbfa22008-05-19 16:00:08 +10001254 fatal("%s: no channel for id %d", __func__, id);
Damien Millerd530f5f2010-05-21 14:57:10 +10001255 if ((cc = channel_by_id(c->ctl_chan)) == NULL)
1256 fatal("%s: channel %d lacks control channel %d", __func__,
1257 id, c->ctl_chan);
1258
1259 if (!success) {
1260 debug3("%s: sending failure reply", __func__);
1261 /* prepare reply */
1262 buffer_init(&reply);
1263 buffer_put_int(&reply, MUX_S_FAILURE);
1264 buffer_put_int(&reply, cctx->rid);
1265 buffer_put_cstring(&reply, "Session open refused by peer");
1266 goto done;
1267 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10001268
1269 display = getenv("DISPLAY");
1270 if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
1271 char *proto, *data;
Damien Miller1ab6a512010-06-26 10:02:24 +10001272
Damien Millerb1cbfa22008-05-19 16:00:08 +10001273 /* Get reasonable local authentication information. */
1274 client_x11_get_proto(display, options.xauth_location,
Damien Miller1ab6a512010-06-26 10:02:24 +10001275 options.forward_x11_trusted, options.forward_x11_timeout,
1276 &proto, &data);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001277 /* Request forwarding with authentication spoofing. */
Damien Miller1ab6a512010-06-26 10:02:24 +10001278 debug("Requesting X11 forwarding with authentication "
1279 "spoofing.");
Damien Miller6d7b4372011-06-23 08:31:57 +10001280 x11_request_forwarding_with_spoofing(id, display, proto,
1281 data, 1);
1282 client_expect_confirm(id, "X11 forwarding", CONFIRM_WARN);
1283 /* XXX exit_on_forward_failure */
Damien Millerb1cbfa22008-05-19 16:00:08 +10001284 }
1285
1286 if (cctx->want_agent_fwd && options.forward_agent) {
1287 debug("Requesting authentication agent forwarding.");
1288 channel_request_start(id, "auth-agent-req@openssh.com", 0);
1289 packet_send();
1290 }
1291
1292 client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
1293 cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);
1294
Damien Millerd530f5f2010-05-21 14:57:10 +10001295 debug3("%s: sending success reply", __func__);
1296 /* prepare reply */
1297 buffer_init(&reply);
1298 buffer_put_int(&reply, MUX_S_SESSION_OPENED);
1299 buffer_put_int(&reply, cctx->rid);
1300 buffer_put_int(&reply, c->self);
1301
1302 done:
1303 /* Send reply */
1304 buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
1305 buffer_free(&reply);
1306
1307 if (cc->mux_pause <= 0)
1308 fatal("%s: mux_pause %d", __func__, cc->mux_pause);
1309 cc->mux_pause = 0; /* start processing messages again */
Damien Millerb1cbfa22008-05-19 16:00:08 +10001310 c->open_confirm_ctx = NULL;
1311 buffer_free(&cctx->cmd);
1312 xfree(cctx->term);
1313 if (cctx->env != NULL) {
1314 for (i = 0; cctx->env[i] != NULL; i++)
1315 xfree(cctx->env[i]);
1316 xfree(cctx->env);
1317 }
1318 xfree(cctx);
1319}
1320
Damien Millerb1cbfa22008-05-19 16:00:08 +10001321/* ** Multiplexing client support */
1322
1323/* Exit signal handler */
1324static void
1325control_client_sighandler(int signo)
1326{
1327 muxclient_terminate = signo;
1328}
1329
1330/*
1331 * Relay signal handler - used to pass some signals from mux client to
1332 * mux master.
1333 */
1334static void
1335control_client_sigrelay(int signo)
1336{
1337 int save_errno = errno;
1338
1339 if (muxserver_pid > 1)
1340 kill(muxserver_pid, signo);
1341
1342 errno = save_errno;
1343}
1344
Damien Millerb1cbfa22008-05-19 16:00:08 +10001345static int
Damien Millere1537f92010-01-26 13:26:22 +11001346mux_client_read(int fd, Buffer *b, u_int need)
Damien Millerb1cbfa22008-05-19 16:00:08 +10001347{
Damien Millere1537f92010-01-26 13:26:22 +11001348 u_int have;
1349 ssize_t len;
1350 u_char *p;
1351 struct pollfd pfd;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001352
Damien Millere1537f92010-01-26 13:26:22 +11001353 pfd.fd = fd;
1354 pfd.events = POLLIN;
1355 p = buffer_append_space(b, need);
1356 for (have = 0; have < need; ) {
1357 if (muxclient_terminate) {
1358 errno = EINTR;
1359 return -1;
1360 }
1361 len = read(fd, p + have, need - have);
1362 if (len < 0) {
1363 switch (errno) {
1364#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1365 case EWOULDBLOCK:
1366#endif
1367 case EAGAIN:
1368 (void)poll(&pfd, 1, -1);
1369 /* FALLTHROUGH */
1370 case EINTR:
1371 continue;
1372 default:
1373 return -1;
1374 }
1375 }
1376 if (len == 0) {
1377 errno = EPIPE;
1378 return -1;
1379 }
1380 have += (u_int)len;
1381 }
1382 return 0;
1383}
Damien Millerb1cbfa22008-05-19 16:00:08 +10001384
Damien Millere1537f92010-01-26 13:26:22 +11001385static int
1386mux_client_write_packet(int fd, Buffer *m)
1387{
1388 Buffer queue;
1389 u_int have, need;
1390 int oerrno, len;
1391 u_char *ptr;
1392 struct pollfd pfd;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001393
Damien Millere1537f92010-01-26 13:26:22 +11001394 pfd.fd = fd;
1395 pfd.events = POLLOUT;
1396 buffer_init(&queue);
1397 buffer_put_string(&queue, buffer_ptr(m), buffer_len(m));
1398
1399 need = buffer_len(&queue);
1400 ptr = buffer_ptr(&queue);
1401
1402 for (have = 0; have < need; ) {
1403 if (muxclient_terminate) {
1404 buffer_free(&queue);
1405 errno = EINTR;
1406 return -1;
1407 }
1408 len = write(fd, ptr + have, need - have);
1409 if (len < 0) {
1410 switch (errno) {
1411#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1412 case EWOULDBLOCK:
1413#endif
1414 case EAGAIN:
1415 (void)poll(&pfd, 1, -1);
1416 /* FALLTHROUGH */
1417 case EINTR:
1418 continue;
1419 default:
1420 oerrno = errno;
1421 buffer_free(&queue);
1422 errno = oerrno;
1423 return -1;
1424 }
1425 }
1426 if (len == 0) {
1427 buffer_free(&queue);
1428 errno = EPIPE;
1429 return -1;
1430 }
1431 have += (u_int)len;
1432 }
1433 buffer_free(&queue);
1434 return 0;
1435}
1436
1437static int
1438mux_client_read_packet(int fd, Buffer *m)
1439{
1440 Buffer queue;
1441 u_int need, have;
1442 void *ptr;
1443 int oerrno;
1444
1445 buffer_init(&queue);
1446 if (mux_client_read(fd, &queue, 4) != 0) {
1447 if ((oerrno = errno) == EPIPE)
1448 debug3("%s: read header failed: %s", __func__, strerror(errno));
1449 errno = oerrno;
1450 return -1;
1451 }
1452 need = get_u32(buffer_ptr(&queue));
1453 if (mux_client_read(fd, &queue, need) != 0) {
1454 oerrno = errno;
1455 debug3("%s: read body failed: %s", __func__, strerror(errno));
1456 errno = oerrno;
1457 return -1;
1458 }
1459 ptr = buffer_get_string_ptr(&queue, &have);
1460 buffer_append(m, ptr, have);
1461 buffer_free(&queue);
1462 return 0;
1463}
1464
1465static int
1466mux_client_hello_exchange(int fd)
1467{
1468 Buffer m;
1469 u_int type, ver;
1470
1471 buffer_init(&m);
1472 buffer_put_int(&m, MUX_MSG_HELLO);
1473 buffer_put_int(&m, SSHMUX_VER);
1474 /* no extensions */
1475
1476 if (mux_client_write_packet(fd, &m) != 0)
1477 fatal("%s: write packet: %s", __func__, strerror(errno));
1478
1479 buffer_clear(&m);
1480
1481 /* Read their HELLO */
1482 if (mux_client_read_packet(fd, &m) != 0) {
1483 buffer_free(&m);
1484 return -1;
1485 }
1486
1487 type = buffer_get_int(&m);
1488 if (type != MUX_MSG_HELLO)
1489 fatal("%s: expected HELLO (%u) received %u",
1490 __func__, MUX_MSG_HELLO, type);
1491 ver = buffer_get_int(&m);
1492 if (ver != SSHMUX_VER)
1493 fatal("Unsupported multiplexing protocol version %d "
1494 "(expected %d)", ver, SSHMUX_VER);
1495 debug2("%s: master version %u", __func__, ver);
1496 /* No extensions are presently defined */
1497 while (buffer_len(&m) > 0) {
1498 char *name = buffer_get_string(&m, NULL);
1499 char *value = buffer_get_string(&m, NULL);
1500
1501 debug2("Unrecognised master extension \"%s\"", name);
1502 xfree(name);
1503 xfree(value);
1504 }
1505 buffer_free(&m);
1506 return 0;
1507}
1508
1509static u_int
1510mux_client_request_alive(int fd)
1511{
1512 Buffer m;
1513 char *e;
1514 u_int pid, type, rid;
1515
1516 debug3("%s: entering", __func__);
1517
1518 buffer_init(&m);
1519 buffer_put_int(&m, MUX_C_ALIVE_CHECK);
1520 buffer_put_int(&m, muxclient_request_id);
1521
1522 if (mux_client_write_packet(fd, &m) != 0)
1523 fatal("%s: write packet: %s", __func__, strerror(errno));
1524
1525 buffer_clear(&m);
1526
1527 /* Read their reply */
1528 if (mux_client_read_packet(fd, &m) != 0) {
1529 buffer_free(&m);
1530 return 0;
1531 }
1532
1533 type = buffer_get_int(&m);
1534 if (type != MUX_S_ALIVE) {
1535 e = buffer_get_string(&m, NULL);
1536 fatal("%s: master returned error: %s", __func__, e);
1537 }
1538
1539 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1540 fatal("%s: out of sequence reply: my id %u theirs %u",
1541 __func__, muxclient_request_id, rid);
1542 pid = buffer_get_int(&m);
1543 buffer_free(&m);
1544
1545 debug3("%s: done pid = %u", __func__, pid);
1546
1547 muxclient_request_id++;
1548
1549 return pid;
1550}
1551
1552static void
1553mux_client_request_terminate(int fd)
1554{
1555 Buffer m;
1556 char *e;
1557 u_int type, rid;
1558
1559 debug3("%s: entering", __func__);
1560
1561 buffer_init(&m);
1562 buffer_put_int(&m, MUX_C_TERMINATE);
1563 buffer_put_int(&m, muxclient_request_id);
1564
1565 if (mux_client_write_packet(fd, &m) != 0)
1566 fatal("%s: write packet: %s", __func__, strerror(errno));
1567
1568 buffer_clear(&m);
1569
1570 /* Read their reply */
1571 if (mux_client_read_packet(fd, &m) != 0) {
1572 /* Remote end exited already */
1573 if (errno == EPIPE) {
1574 buffer_free(&m);
1575 return;
1576 }
1577 fatal("%s: read from master failed: %s",
1578 __func__, strerror(errno));
1579 }
1580
1581 type = buffer_get_int(&m);
1582 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1583 fatal("%s: out of sequence reply: my id %u theirs %u",
1584 __func__, muxclient_request_id, rid);
1585 switch (type) {
1586 case MUX_S_OK:
1587 break;
1588 case MUX_S_PERMISSION_DENIED:
1589 e = buffer_get_string(&m, NULL);
1590 fatal("Master refused termination request: %s", e);
1591 case MUX_S_FAILURE:
1592 e = buffer_get_string(&m, NULL);
1593 fatal("%s: termination request failed: %s", __func__, e);
1594 default:
1595 fatal("%s: unexpected response from master 0x%08x",
1596 __func__, type);
1597 }
1598 buffer_free(&m);
1599 muxclient_request_id++;
1600}
1601
1602static int
Damien Millerf6dff7c2011-09-22 21:38:52 +10001603mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd)
Damien Millere1537f92010-01-26 13:26:22 +11001604{
1605 Buffer m;
1606 char *e, *fwd_desc;
1607 u_int type, rid;
1608
1609 fwd_desc = format_forward(ftype, fwd);
Damien Millerf6dff7c2011-09-22 21:38:52 +10001610 debug("Requesting %s %s",
1611 cancel_flag ? "cancellation of" : "forwarding of", fwd_desc);
Damien Millere1537f92010-01-26 13:26:22 +11001612 xfree(fwd_desc);
1613
1614 buffer_init(&m);
Damien Millerf6dff7c2011-09-22 21:38:52 +10001615 buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD);
Damien Millere1537f92010-01-26 13:26:22 +11001616 buffer_put_int(&m, muxclient_request_id);
1617 buffer_put_int(&m, ftype);
1618 buffer_put_cstring(&m,
1619 fwd->listen_host == NULL ? "" : fwd->listen_host);
1620 buffer_put_int(&m, fwd->listen_port);
1621 buffer_put_cstring(&m,
1622 fwd->connect_host == NULL ? "" : fwd->connect_host);
1623 buffer_put_int(&m, fwd->connect_port);
1624
1625 if (mux_client_write_packet(fd, &m) != 0)
1626 fatal("%s: write packet: %s", __func__, strerror(errno));
1627
1628 buffer_clear(&m);
1629
1630 /* Read their reply */
1631 if (mux_client_read_packet(fd, &m) != 0) {
1632 buffer_free(&m);
1633 return -1;
1634 }
1635
1636 type = buffer_get_int(&m);
1637 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1638 fatal("%s: out of sequence reply: my id %u theirs %u",
1639 __func__, muxclient_request_id, rid);
1640 switch (type) {
1641 case MUX_S_OK:
1642 break;
Damien Miller388f6fc2010-05-21 14:57:35 +10001643 case MUX_S_REMOTE_PORT:
Damien Millerf6dff7c2011-09-22 21:38:52 +10001644 if (cancel_flag)
1645 fatal("%s: got MUX_S_REMOTE_PORT for cancel", __func__);
Damien Miller388f6fc2010-05-21 14:57:35 +10001646 fwd->allocated_port = buffer_get_int(&m);
1647 logit("Allocated port %u for remote forward to %s:%d",
1648 fwd->allocated_port,
1649 fwd->connect_host ? fwd->connect_host : "",
1650 fwd->connect_port);
1651 if (muxclient_command == SSHMUX_COMMAND_FORWARD)
1652 fprintf(stdout, "%u\n", fwd->allocated_port);
1653 break;
Damien Millere1537f92010-01-26 13:26:22 +11001654 case MUX_S_PERMISSION_DENIED:
1655 e = buffer_get_string(&m, NULL);
1656 buffer_free(&m);
1657 error("Master refused forwarding request: %s", e);
1658 return -1;
1659 case MUX_S_FAILURE:
1660 e = buffer_get_string(&m, NULL);
1661 buffer_free(&m);
Damien Miller445c9a52011-01-14 12:01:29 +11001662 error("%s: forwarding request failed: %s", __func__, e);
Damien Millere1537f92010-01-26 13:26:22 +11001663 return -1;
1664 default:
1665 fatal("%s: unexpected response from master 0x%08x",
1666 __func__, type);
1667 }
1668 buffer_free(&m);
1669
1670 muxclient_request_id++;
1671 return 0;
1672}
1673
1674static int
Damien Millerf6dff7c2011-09-22 21:38:52 +10001675mux_client_forwards(int fd, int cancel_flag)
Damien Millere1537f92010-01-26 13:26:22 +11001676{
Damien Millerf6dff7c2011-09-22 21:38:52 +10001677 int i, ret = 0;
Damien Millere1537f92010-01-26 13:26:22 +11001678
Damien Millerf6dff7c2011-09-22 21:38:52 +10001679 debug3("%s: %s forwardings: %d local, %d remote", __func__,
1680 cancel_flag ? "cancel" : "request",
Damien Millere1537f92010-01-26 13:26:22 +11001681 options.num_local_forwards, options.num_remote_forwards);
1682
1683 /* XXX ExitOnForwardingFailure */
1684 for (i = 0; i < options.num_local_forwards; i++) {
Damien Millerf6dff7c2011-09-22 21:38:52 +10001685 if (mux_client_forward(fd, cancel_flag,
Damien Millere1537f92010-01-26 13:26:22 +11001686 options.local_forwards[i].connect_port == 0 ?
1687 MUX_FWD_DYNAMIC : MUX_FWD_LOCAL,
1688 options.local_forwards + i) != 0)
Damien Millerf6dff7c2011-09-22 21:38:52 +10001689 ret = -1;
Damien Millere1537f92010-01-26 13:26:22 +11001690 }
1691 for (i = 0; i < options.num_remote_forwards; i++) {
Damien Millerf6dff7c2011-09-22 21:38:52 +10001692 if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE,
Damien Millere1537f92010-01-26 13:26:22 +11001693 options.remote_forwards + i) != 0)
Damien Millerf6dff7c2011-09-22 21:38:52 +10001694 ret = -1;
Damien Millere1537f92010-01-26 13:26:22 +11001695 }
Damien Millerf6dff7c2011-09-22 21:38:52 +10001696 return ret;
Damien Millere1537f92010-01-26 13:26:22 +11001697}
1698
1699static int
1700mux_client_request_session(int fd)
1701{
1702 Buffer m;
1703 char *e, *term;
1704 u_int i, rid, sid, esid, exitval, type, exitval_seen;
1705 extern char **environ;
Damien Miller555f3b82011-05-15 08:48:05 +10001706 int devnull, rawmode;
Damien Millere1537f92010-01-26 13:26:22 +11001707
1708 debug3("%s: entering", __func__);
1709
1710 if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
1711 error("%s: master alive request failed", __func__);
1712 return -1;
1713 }
1714
1715 signal(SIGPIPE, SIG_IGN);
1716
1717 if (stdin_null_flag) {
1718 if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
1719 fatal("open(/dev/null): %s", strerror(errno));
1720 if (dup2(devnull, STDIN_FILENO) == -1)
1721 fatal("dup2: %s", strerror(errno));
1722 if (devnull > STDERR_FILENO)
1723 close(devnull);
1724 }
1725
1726 term = getenv("TERM");
1727
1728 buffer_init(&m);
1729 buffer_put_int(&m, MUX_C_NEW_SESSION);
1730 buffer_put_int(&m, muxclient_request_id);
1731 buffer_put_cstring(&m, ""); /* reserved */
1732 buffer_put_int(&m, tty_flag);
1733 buffer_put_int(&m, options.forward_x11);
1734 buffer_put_int(&m, options.forward_agent);
1735 buffer_put_int(&m, subsystem_flag);
1736 buffer_put_int(&m, options.escape_char == SSH_ESCAPECHAR_NONE ?
1737 0xffffffff : (u_int)options.escape_char);
1738 buffer_put_cstring(&m, term == NULL ? "" : term);
1739 buffer_put_string(&m, buffer_ptr(&command), buffer_len(&command));
1740
1741 if (options.num_send_env > 0 && environ != NULL) {
1742 /* Pass environment */
1743 for (i = 0; environ[i] != NULL; i++) {
1744 if (env_permitted(environ[i])) {
1745 buffer_put_cstring(&m, environ[i]);
1746 }
1747 }
1748 }
1749
1750 if (mux_client_write_packet(fd, &m) != 0)
1751 fatal("%s: write packet: %s", __func__, strerror(errno));
1752
1753 /* Send the stdio file descriptors */
1754 if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
1755 mm_send_fd(fd, STDOUT_FILENO) == -1 ||
1756 mm_send_fd(fd, STDERR_FILENO) == -1)
1757 fatal("%s: send fds failed", __func__);
1758
1759 debug3("%s: session request sent", __func__);
1760
1761 /* Read their reply */
1762 buffer_clear(&m);
1763 if (mux_client_read_packet(fd, &m) != 0) {
1764 error("%s: read from master failed: %s",
1765 __func__, strerror(errno));
1766 buffer_free(&m);
1767 return -1;
1768 }
1769
1770 type = buffer_get_int(&m);
1771 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1772 fatal("%s: out of sequence reply: my id %u theirs %u",
1773 __func__, muxclient_request_id, rid);
1774 switch (type) {
1775 case MUX_S_SESSION_OPENED:
1776 sid = buffer_get_int(&m);
1777 debug("%s: master session id: %u", __func__, sid);
1778 break;
1779 case MUX_S_PERMISSION_DENIED:
1780 e = buffer_get_string(&m, NULL);
1781 buffer_free(&m);
Damien Miller445c9a52011-01-14 12:01:29 +11001782 error("Master refused session request: %s", e);
Damien Millere1537f92010-01-26 13:26:22 +11001783 return -1;
1784 case MUX_S_FAILURE:
1785 e = buffer_get_string(&m, NULL);
1786 buffer_free(&m);
Damien Miller445c9a52011-01-14 12:01:29 +11001787 error("%s: session request failed: %s", __func__, e);
Damien Millere1537f92010-01-26 13:26:22 +11001788 return -1;
1789 default:
1790 buffer_free(&m);
1791 error("%s: unexpected response from master 0x%08x",
1792 __func__, type);
1793 return -1;
1794 }
1795 muxclient_request_id++;
1796
1797 signal(SIGHUP, control_client_sighandler);
1798 signal(SIGINT, control_client_sighandler);
1799 signal(SIGTERM, control_client_sighandler);
1800 signal(SIGWINCH, control_client_sigrelay);
1801
Damien Miller555f3b82011-05-15 08:48:05 +10001802 rawmode = tty_flag;
Damien Millere1537f92010-01-26 13:26:22 +11001803 if (tty_flag)
Damien Miller21771e22011-05-15 08:45:50 +10001804 enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
Damien Millere1537f92010-01-26 13:26:22 +11001805
1806 /*
1807 * Stick around until the controlee closes the client_fd.
1808 * Before it does, it is expected to write an exit message.
1809 * This process must read the value and wait for the closure of
1810 * the client_fd; if this one closes early, the multiplex master will
1811 * terminate early too (possibly losing data).
1812 */
1813 for (exitval = 255, exitval_seen = 0;;) {
1814 buffer_clear(&m);
1815 if (mux_client_read_packet(fd, &m) != 0)
1816 break;
1817 type = buffer_get_int(&m);
Damien Miller555f3b82011-05-15 08:48:05 +10001818 switch (type) {
1819 case MUX_S_TTY_ALLOC_FAIL:
1820 if ((esid = buffer_get_int(&m)) != sid)
1821 fatal("%s: tty alloc fail on unknown session: "
1822 "my id %u theirs %u",
1823 __func__, sid, esid);
1824 leave_raw_mode(options.request_tty ==
1825 REQUEST_TTY_FORCE);
1826 rawmode = 0;
1827 continue;
1828 case MUX_S_EXIT_MESSAGE:
1829 if ((esid = buffer_get_int(&m)) != sid)
1830 fatal("%s: exit on unknown session: "
1831 "my id %u theirs %u",
1832 __func__, sid, esid);
1833 if (exitval_seen)
1834 fatal("%s: exitval sent twice", __func__);
1835 exitval = buffer_get_int(&m);
1836 exitval_seen = 1;
1837 continue;
1838 default:
Damien Millere1537f92010-01-26 13:26:22 +11001839 e = buffer_get_string(&m, NULL);
1840 fatal("%s: master returned error: %s", __func__, e);
1841 }
Damien Millere1537f92010-01-26 13:26:22 +11001842 }
1843
1844 close(fd);
Damien Miller555f3b82011-05-15 08:48:05 +10001845 if (rawmode)
1846 leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
Damien Millere1537f92010-01-26 13:26:22 +11001847
1848 if (muxclient_terminate) {
1849 debug2("Exiting on signal %d", muxclient_terminate);
1850 exitval = 255;
1851 } else if (!exitval_seen) {
1852 debug2("Control master terminated unexpectedly");
1853 exitval = 255;
1854 } else
1855 debug2("Received exit status from master %d", exitval);
1856
1857 if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
1858 fprintf(stderr, "Shared connection to %s closed.\r\n", host);
1859
1860 exit(exitval);
1861}
1862
1863static int
1864mux_client_request_stdio_fwd(int fd)
1865{
1866 Buffer m;
1867 char *e;
1868 u_int type, rid, sid;
1869 int devnull;
1870
1871 debug3("%s: entering", __func__);
1872
1873 if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
1874 error("%s: master alive request failed", __func__);
1875 return -1;
1876 }
1877
1878 signal(SIGPIPE, SIG_IGN);
1879
1880 if (stdin_null_flag) {
1881 if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
1882 fatal("open(/dev/null): %s", strerror(errno));
1883 if (dup2(devnull, STDIN_FILENO) == -1)
1884 fatal("dup2: %s", strerror(errno));
1885 if (devnull > STDERR_FILENO)
1886 close(devnull);
1887 }
1888
1889 buffer_init(&m);
1890 buffer_put_int(&m, MUX_C_NEW_STDIO_FWD);
1891 buffer_put_int(&m, muxclient_request_id);
1892 buffer_put_cstring(&m, ""); /* reserved */
1893 buffer_put_cstring(&m, stdio_forward_host);
1894 buffer_put_int(&m, stdio_forward_port);
1895
1896 if (mux_client_write_packet(fd, &m) != 0)
1897 fatal("%s: write packet: %s", __func__, strerror(errno));
1898
1899 /* Send the stdio file descriptors */
1900 if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
1901 mm_send_fd(fd, STDOUT_FILENO) == -1)
1902 fatal("%s: send fds failed", __func__);
1903
1904 debug3("%s: stdio forward request sent", __func__);
1905
1906 /* Read their reply */
1907 buffer_clear(&m);
1908
1909 if (mux_client_read_packet(fd, &m) != 0) {
1910 error("%s: read from master failed: %s",
1911 __func__, strerror(errno));
1912 buffer_free(&m);
1913 return -1;
1914 }
1915
1916 type = buffer_get_int(&m);
1917 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1918 fatal("%s: out of sequence reply: my id %u theirs %u",
1919 __func__, muxclient_request_id, rid);
1920 switch (type) {
1921 case MUX_S_SESSION_OPENED:
1922 sid = buffer_get_int(&m);
1923 debug("%s: master session id: %u", __func__, sid);
1924 break;
1925 case MUX_S_PERMISSION_DENIED:
1926 e = buffer_get_string(&m, NULL);
1927 buffer_free(&m);
Damien Miller445c9a52011-01-14 12:01:29 +11001928 fatal("Master refused stdio forwarding request: %s", e);
Damien Millere1537f92010-01-26 13:26:22 +11001929 case MUX_S_FAILURE:
1930 e = buffer_get_string(&m, NULL);
1931 buffer_free(&m);
1932 fatal("%s: stdio forwarding request failed: %s", __func__, e);
1933 default:
1934 buffer_free(&m);
1935 error("%s: unexpected response from master 0x%08x",
1936 __func__, type);
1937 return -1;
1938 }
1939 muxclient_request_id++;
1940
1941 signal(SIGHUP, control_client_sighandler);
1942 signal(SIGINT, control_client_sighandler);
1943 signal(SIGTERM, control_client_sighandler);
1944 signal(SIGWINCH, control_client_sigrelay);
1945
1946 /*
1947 * Stick around until the controlee closes the client_fd.
1948 */
1949 buffer_clear(&m);
1950 if (mux_client_read_packet(fd, &m) != 0) {
1951 if (errno == EPIPE ||
1952 (errno == EINTR && muxclient_terminate != 0))
1953 return 0;
1954 fatal("%s: mux_client_read_packet: %s",
1955 __func__, strerror(errno));
1956 }
1957 fatal("%s: master returned unexpected message %u", __func__, type);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001958}
1959
Damien Miller6c3eec72011-05-05 14:16:22 +10001960static void
1961mux_client_request_stop_listening(int fd)
1962{
1963 Buffer m;
1964 char *e;
1965 u_int type, rid;
1966
1967 debug3("%s: entering", __func__);
1968
1969 buffer_init(&m);
1970 buffer_put_int(&m, MUX_C_STOP_LISTENING);
1971 buffer_put_int(&m, muxclient_request_id);
1972
1973 if (mux_client_write_packet(fd, &m) != 0)
1974 fatal("%s: write packet: %s", __func__, strerror(errno));
1975
1976 buffer_clear(&m);
1977
1978 /* Read their reply */
1979 if (mux_client_read_packet(fd, &m) != 0)
1980 fatal("%s: read from master failed: %s",
1981 __func__, strerror(errno));
1982
1983 type = buffer_get_int(&m);
1984 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1985 fatal("%s: out of sequence reply: my id %u theirs %u",
1986 __func__, muxclient_request_id, rid);
1987 switch (type) {
1988 case MUX_S_OK:
1989 break;
1990 case MUX_S_PERMISSION_DENIED:
1991 e = buffer_get_string(&m, NULL);
1992 fatal("Master refused stop listening request: %s", e);
1993 case MUX_S_FAILURE:
1994 e = buffer_get_string(&m, NULL);
1995 fatal("%s: stop listening request failed: %s", __func__, e);
1996 default:
1997 fatal("%s: unexpected response from master 0x%08x",
1998 __func__, type);
1999 }
2000 buffer_free(&m);
2001 muxclient_request_id++;
2002}
2003
Damien Millerb1cbfa22008-05-19 16:00:08 +10002004/* Multiplex client main loop. */
2005void
2006muxclient(const char *path)
2007{
2008 struct sockaddr_un addr;
Damien Millere1537f92010-01-26 13:26:22 +11002009 socklen_t sun_len;
2010 int sock;
2011 u_int pid;
Damien Millerb1cbfa22008-05-19 16:00:08 +10002012
Damien Millere1537f92010-01-26 13:26:22 +11002013 if (muxclient_command == 0) {
2014 if (stdio_forward_host != NULL)
2015 muxclient_command = SSHMUX_COMMAND_STDIO_FWD;
2016 else
2017 muxclient_command = SSHMUX_COMMAND_OPEN;
2018 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10002019
2020 switch (options.control_master) {
2021 case SSHCTL_MASTER_AUTO:
2022 case SSHCTL_MASTER_AUTO_ASK:
2023 debug("auto-mux: Trying existing master");
2024 /* FALLTHROUGH */
2025 case SSHCTL_MASTER_NO:
2026 break;
2027 default:
2028 return;
2029 }
2030
2031 memset(&addr, '\0', sizeof(addr));
2032 addr.sun_family = AF_UNIX;
Damien Millere1537f92010-01-26 13:26:22 +11002033 sun_len = offsetof(struct sockaddr_un, sun_path) +
Damien Millerb1cbfa22008-05-19 16:00:08 +10002034 strlen(path) + 1;
2035
2036 if (strlcpy(addr.sun_path, path,
2037 sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
2038 fatal("ControlPath too long");
2039
2040 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
2041 fatal("%s socket(): %s", __func__, strerror(errno));
2042
Damien Millere1537f92010-01-26 13:26:22 +11002043 if (connect(sock, (struct sockaddr *)&addr, sun_len) == -1) {
2044 switch (muxclient_command) {
2045 case SSHMUX_COMMAND_OPEN:
2046 case SSHMUX_COMMAND_STDIO_FWD:
2047 break;
2048 default:
Damien Millerb1cbfa22008-05-19 16:00:08 +10002049 fatal("Control socket connect(%.100s): %s", path,
2050 strerror(errno));
2051 }
Damien Miller603134e2010-09-24 22:07:55 +10002052 if (errno == ECONNREFUSED &&
2053 options.control_master != SSHCTL_MASTER_NO) {
2054 debug("Stale control socket %.100s, unlinking", path);
2055 unlink(path);
2056 } else if (errno == ENOENT) {
Damien Millerb1cbfa22008-05-19 16:00:08 +10002057 debug("Control socket \"%.100s\" does not exist", path);
Damien Miller603134e2010-09-24 22:07:55 +10002058 } else {
Damien Millerb1cbfa22008-05-19 16:00:08 +10002059 error("Control socket connect(%.100s): %s", path,
2060 strerror(errno));
2061 }
2062 close(sock);
2063 return;
2064 }
Damien Millere1537f92010-01-26 13:26:22 +11002065 set_nonblock(sock);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002066
Damien Millere1537f92010-01-26 13:26:22 +11002067 if (mux_client_hello_exchange(sock) != 0) {
2068 error("%s: master hello exchange failed", __func__);
Darren Tuckerca19bfe2008-06-13 10:24:03 +10002069 close(sock);
Darren Tuckerca19bfe2008-06-13 10:24:03 +10002070 return;
2071 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10002072
2073 switch (muxclient_command) {
2074 case SSHMUX_COMMAND_ALIVE_CHECK:
Damien Millere1537f92010-01-26 13:26:22 +11002075 if ((pid = mux_client_request_alive(sock)) == 0)
2076 fatal("%s: master alive check failed", __func__);
2077 fprintf(stderr, "Master running (pid=%d)\r\n", pid);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002078 exit(0);
2079 case SSHMUX_COMMAND_TERMINATE:
Damien Millere1537f92010-01-26 13:26:22 +11002080 mux_client_request_terminate(sock);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002081 fprintf(stderr, "Exit request sent.\r\n");
2082 exit(0);
Damien Miller388f6fc2010-05-21 14:57:35 +10002083 case SSHMUX_COMMAND_FORWARD:
Damien Millerf6dff7c2011-09-22 21:38:52 +10002084 if (mux_client_forwards(sock, 0) != 0)
Damien Miller388f6fc2010-05-21 14:57:35 +10002085 fatal("%s: master forward request failed", __func__);
2086 exit(0);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002087 case SSHMUX_COMMAND_OPEN:
Damien Millerf6dff7c2011-09-22 21:38:52 +10002088 if (mux_client_forwards(sock, 0) != 0) {
Damien Millere1537f92010-01-26 13:26:22 +11002089 error("%s: master forward request failed", __func__);
2090 return;
Darren Tucker2fb66ca2008-06-13 04:49:33 +10002091 }
Damien Millere1537f92010-01-26 13:26:22 +11002092 mux_client_request_session(sock);
2093 return;
2094 case SSHMUX_COMMAND_STDIO_FWD:
2095 mux_client_request_stdio_fwd(sock);
2096 exit(0);
Damien Miller6c3eec72011-05-05 14:16:22 +10002097 case SSHMUX_COMMAND_STOP:
2098 mux_client_request_stop_listening(sock);
2099 fprintf(stderr, "Stop listening request sent.\r\n");
2100 exit(0);
Damien Millerf6dff7c2011-09-22 21:38:52 +10002101 case SSHMUX_COMMAND_CANCEL_FWD:
2102 if (mux_client_forwards(sock, 1) != 0)
2103 error("%s: master cancel forward request failed",
2104 __func__);
2105 exit(0);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002106 default:
Darren Tucker2fb66ca2008-06-13 04:49:33 +10002107 fatal("unrecognised muxclient_command %d", muxclient_command);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002108 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10002109}