blob: d90605eb4d05d40a9344a39be1514e5efa4c27da [file] [log] [blame]
Damien Miller2ec03422012-02-11 08:16:28 +11001/* $OpenBSD: mux.c,v 1.34 2012/01/07 21:11:36 djm Exp $ */
Damien Millerb1cbfa22008-05-19 16:00:08 +10002/*
3 * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* ssh session multiplexing support */
19
Darren Tucker2fb66ca2008-06-13 04:49:33 +100020/*
21 * TODO:
Damien Millere1537f92010-01-26 13:26:22 +110022 * - Better signalling from master to slave, especially passing of
Darren Tucker2fb66ca2008-06-13 04:49:33 +100023 * error messages
Damien Millere1537f92010-01-26 13:26:22 +110024 * - Better fall-back from mux slave error to new connection.
25 * - ExitOnForwardingFailure
26 * - Maybe extension mechanisms for multi-X11/multi-agent forwarding
27 * - Support ~^Z in mux slaves.
28 * - Inspect or control sessions in master.
29 * - If we ever support the "signal" channel request, send signals on
30 * sessions in master.
Darren Tucker2fb66ca2008-06-13 04:49:33 +100031 */
32
Damien Millere1537f92010-01-26 13:26:22 +110033#include "includes.h"
34
Damien Millerb1cbfa22008-05-19 16:00:08 +100035#include <sys/types.h>
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
66#ifdef HAVE_LIBUTIL_H
67# include <libutil.h>
68#endif
69
Damien Millerb1cbfa22008-05-19 16:00:08 +100070#include "openbsd-compat/sys-queue.h"
71#include "xmalloc.h"
72#include "log.h"
73#include "ssh.h"
Damien Miller388f6fc2010-05-21 14:57:35 +100074#include "ssh2.h"
Damien Millerb1cbfa22008-05-19 16:00:08 +100075#include "pathnames.h"
76#include "misc.h"
77#include "match.h"
78#include "buffer.h"
79#include "channels.h"
80#include "msg.h"
81#include "packet.h"
82#include "monitor_fdpass.h"
83#include "sshpty.h"
84#include "key.h"
85#include "readconf.h"
86#include "clientloop.h"
87
88/* from ssh.c */
89extern int tty_flag;
90extern Options options;
91extern int stdin_null_flag;
92extern char *host;
Darren Tucker8ec4fd82009-10-07 08:39:57 +110093extern int subsystem_flag;
Damien Millerb1cbfa22008-05-19 16:00:08 +100094extern Buffer command;
Damien Millere1537f92010-01-26 13:26:22 +110095extern volatile sig_atomic_t quit_pending;
96extern char *stdio_forward_host;
97extern int stdio_forward_port;
Damien Millerb1cbfa22008-05-19 16:00:08 +100098
Darren Tucker2fb66ca2008-06-13 04:49:33 +100099/* Context for session open confirmation callback */
100struct mux_session_confirm_ctx {
Damien Millere1537f92010-01-26 13:26:22 +1100101 u_int want_tty;
102 u_int want_subsys;
103 u_int want_x_fwd;
104 u_int want_agent_fwd;
Darren Tucker2fb66ca2008-06-13 04:49:33 +1000105 Buffer cmd;
106 char *term;
107 struct termios tio;
108 char **env;
Damien Millerd530f5f2010-05-21 14:57:10 +1000109 u_int rid;
Darren Tucker2fb66ca2008-06-13 04:49:33 +1000110};
111
Damien Miller388f6fc2010-05-21 14:57:35 +1000112/* Context for global channel callback */
113struct mux_channel_confirm_ctx {
114 u_int cid; /* channel id */
115 u_int rid; /* request id */
116 int fid; /* forward id */
117};
118
Damien Millerb1cbfa22008-05-19 16:00:08 +1000119/* fd to control socket */
120int muxserver_sock = -1;
121
Damien Millere1537f92010-01-26 13:26:22 +1100122/* client request id */
123u_int muxclient_request_id = 0;
124
Damien Millerb1cbfa22008-05-19 16:00:08 +1000125/* Multiplexing control command */
126u_int muxclient_command = 0;
127
128/* Set when signalled. */
129static volatile sig_atomic_t muxclient_terminate = 0;
130
131/* PID of multiplex server */
132static u_int muxserver_pid = 0;
133
Damien Millere1537f92010-01-26 13:26:22 +1100134static Channel *mux_listener_channel = NULL;
Damien Millerb1cbfa22008-05-19 16:00:08 +1000135
Damien Millere1537f92010-01-26 13:26:22 +1100136struct mux_master_state {
137 int hello_rcvd;
138};
139
140/* mux protocol messages */
141#define MUX_MSG_HELLO 0x00000001
142#define MUX_C_NEW_SESSION 0x10000002
143#define MUX_C_ALIVE_CHECK 0x10000004
144#define MUX_C_TERMINATE 0x10000005
145#define MUX_C_OPEN_FWD 0x10000006
146#define MUX_C_CLOSE_FWD 0x10000007
147#define MUX_C_NEW_STDIO_FWD 0x10000008
Damien Miller6c3eec72011-05-05 14:16:22 +1000148#define MUX_C_STOP_LISTENING 0x10000009
Damien Millere1537f92010-01-26 13:26:22 +1100149#define MUX_S_OK 0x80000001
150#define MUX_S_PERMISSION_DENIED 0x80000002
151#define MUX_S_FAILURE 0x80000003
152#define MUX_S_EXIT_MESSAGE 0x80000004
153#define MUX_S_ALIVE 0x80000005
154#define MUX_S_SESSION_OPENED 0x80000006
Damien Miller388f6fc2010-05-21 14:57:35 +1000155#define MUX_S_REMOTE_PORT 0x80000007
Damien Miller555f3b82011-05-15 08:48:05 +1000156#define MUX_S_TTY_ALLOC_FAIL 0x80000008
Damien Millere1537f92010-01-26 13:26:22 +1100157
158/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */
159#define MUX_FWD_LOCAL 1
160#define MUX_FWD_REMOTE 2
161#define MUX_FWD_DYNAMIC 3
162
Damien Millerd530f5f2010-05-21 14:57:10 +1000163static void mux_session_confirm(int, int, void *);
Damien Millere1537f92010-01-26 13:26:22 +1100164
165static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *);
166static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *);
167static int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *);
168static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *);
169static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *);
170static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *);
171static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *);
Damien Miller6c3eec72011-05-05 14:16:22 +1000172static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *);
Damien Millere1537f92010-01-26 13:26:22 +1100173
174static const struct {
175 u_int type;
176 int (*handler)(u_int, Channel *, Buffer *, Buffer *);
177} mux_master_handlers[] = {
178 { MUX_MSG_HELLO, process_mux_master_hello },
179 { MUX_C_NEW_SESSION, process_mux_new_session },
180 { MUX_C_ALIVE_CHECK, process_mux_alive_check },
181 { MUX_C_TERMINATE, process_mux_terminate },
182 { MUX_C_OPEN_FWD, process_mux_open_fwd },
183 { MUX_C_CLOSE_FWD, process_mux_close_fwd },
184 { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd },
Damien Miller6c3eec72011-05-05 14:16:22 +1000185 { MUX_C_STOP_LISTENING, process_mux_stop_listening },
Damien Millere1537f92010-01-26 13:26:22 +1100186 { 0, NULL }
187};
188
189/* Cleanup callback fired on closure of mux slave _session_ channel */
190/* ARGSUSED */
191static void
192mux_master_session_cleanup_cb(int cid, void *unused)
193{
194 Channel *cc, *c = channel_by_id(cid);
195
196 debug3("%s: entering for channel %d", __func__, cid);
197 if (c == NULL)
198 fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
199 if (c->ctl_chan != -1) {
200 if ((cc = channel_by_id(c->ctl_chan)) == NULL)
201 fatal("%s: channel %d missing control channel %d",
202 __func__, c->self, c->ctl_chan);
203 c->ctl_chan = -1;
204 cc->remote_id = -1;
205 chan_rcvd_oclose(cc);
206 }
207 channel_cancel_cleanup(c->self);
208}
209
210/* Cleanup callback fired on closure of mux slave _control_ channel */
211/* ARGSUSED */
212static void
213mux_master_control_cleanup_cb(int cid, void *unused)
214{
215 Channel *sc, *c = channel_by_id(cid);
216
217 debug3("%s: entering for channel %d", __func__, cid);
218 if (c == NULL)
219 fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
220 if (c->remote_id != -1) {
221 if ((sc = channel_by_id(c->remote_id)) == NULL)
Damien Miller601a23c2010-04-16 15:54:01 +1000222 fatal("%s: channel %d missing session channel %d",
Damien Millere1537f92010-01-26 13:26:22 +1100223 __func__, c->self, c->remote_id);
224 c->remote_id = -1;
225 sc->ctl_chan = -1;
Damien Millera21cdfa2010-01-28 06:26:59 +1100226 if (sc->type != SSH_CHANNEL_OPEN) {
227 debug2("%s: channel %d: not open", __func__, sc->self);
Damien Miller133d9d32010-01-30 17:30:04 +1100228 chan_mark_dead(sc);
Damien Millera21cdfa2010-01-28 06:26:59 +1100229 } else {
Damien Miller0dac03f2010-01-30 17:36:33 +1100230 if (sc->istate == CHAN_INPUT_OPEN)
231 chan_read_failed(sc);
232 if (sc->ostate == CHAN_OUTPUT_OPEN)
233 chan_write_failed(sc);
Damien Millera21cdfa2010-01-28 06:26:59 +1100234 }
Damien Millere1537f92010-01-26 13:26:22 +1100235 }
236 channel_cancel_cleanup(c->self);
237}
238
239/* Check mux client environment variables before passing them to mux master. */
240static int
241env_permitted(char *env)
242{
243 int i, ret;
244 char name[1024], *cp;
245
246 if ((cp = strchr(env, '=')) == NULL || cp == env)
247 return 0;
248 ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
249 if (ret <= 0 || (size_t)ret >= sizeof(name)) {
250 error("env_permitted: name '%.100s...' too long", env);
251 return 0;
252 }
253
254 for (i = 0; i < options.num_send_env; i++)
255 if (match_pattern(name, options.send_env[i]))
256 return 1;
257
258 return 0;
259}
260
261/* Mux master protocol message handlers */
262
263static int
264process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r)
265{
266 u_int ver;
267 struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
268
269 if (state == NULL)
270 fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self);
271 if (state->hello_rcvd) {
272 error("%s: HELLO received twice", __func__);
273 return -1;
274 }
275 if (buffer_get_int_ret(&ver, m) != 0) {
276 malf:
277 error("%s: malformed message", __func__);
278 return -1;
279 }
280 if (ver != SSHMUX_VER) {
281 error("Unsupported multiplexing protocol version %d "
282 "(expected %d)", ver, SSHMUX_VER);
283 return -1;
284 }
285 debug2("%s: channel %d slave version %u", __func__, c->self, ver);
286
287 /* No extensions are presently defined */
288 while (buffer_len(m) > 0) {
289 char *name = buffer_get_string_ret(m, NULL);
290 char *value = buffer_get_string_ret(m, NULL);
291
292 if (name == NULL || value == NULL) {
293 if (name != NULL)
294 xfree(name);
295 goto malf;
296 }
297 debug2("Unrecognised slave extension \"%s\"", name);
298 xfree(name);
299 xfree(value);
300 }
301 state->hello_rcvd = 1;
302 return 0;
303}
304
305static int
306process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
307{
308 Channel *nc;
309 struct mux_session_confirm_ctx *cctx;
310 char *reserved, *cmd, *cp;
311 u_int i, j, len, env_len, escape_char, window, packetmax;
312 int new_fd[3];
313
314 /* Reply for SSHMUX_COMMAND_OPEN */
315 cctx = xcalloc(1, sizeof(*cctx));
316 cctx->term = NULL;
Damien Millerd530f5f2010-05-21 14:57:10 +1000317 cctx->rid = rid;
Damien Millere1537f92010-01-26 13:26:22 +1100318 cmd = reserved = NULL;
319 if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
320 buffer_get_int_ret(&cctx->want_tty, m) != 0 ||
321 buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 ||
322 buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 ||
323 buffer_get_int_ret(&cctx->want_subsys, m) != 0 ||
324 buffer_get_int_ret(&escape_char, m) != 0 ||
325 (cctx->term = buffer_get_string_ret(m, &len)) == NULL ||
326 (cmd = buffer_get_string_ret(m, &len)) == NULL) {
327 malf:
328 if (cmd != NULL)
329 xfree(cmd);
330 if (reserved != NULL)
331 xfree(reserved);
332 if (cctx->term != NULL)
333 xfree(cctx->term);
334 error("%s: malformed message", __func__);
335 return -1;
336 }
337 xfree(reserved);
338 reserved = NULL;
339
340 cctx->env = NULL;
341 env_len = 0;
342 while (buffer_len(m) > 0) {
343#define MUX_MAX_ENV_VARS 4096
Damien Miller2ec03422012-02-11 08:16:28 +1100344 if ((cp = buffer_get_string_ret(m, &len)) == NULL)
Damien Millere1537f92010-01-26 13:26:22 +1100345 goto malf;
Damien Millere1537f92010-01-26 13:26:22 +1100346 if (!env_permitted(cp)) {
347 xfree(cp);
348 continue;
349 }
350 cctx->env = xrealloc(cctx->env, env_len + 2,
351 sizeof(*cctx->env));
352 cctx->env[env_len++] = cp;
353 cctx->env[env_len] = NULL;
354 if (env_len > MUX_MAX_ENV_VARS) {
355 error(">%d environment variables received, ignoring "
356 "additional", MUX_MAX_ENV_VARS);
357 break;
358 }
359 }
360
361 debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, "
362 "term \"%s\", cmd \"%s\", env %u", __func__, c->self,
363 cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd,
364 cctx->want_subsys, cctx->term, cmd, env_len);
365
366 buffer_init(&cctx->cmd);
367 buffer_append(&cctx->cmd, cmd, strlen(cmd));
368 xfree(cmd);
369 cmd = NULL;
370
371 /* Gather fds from client */
372 for(i = 0; i < 3; i++) {
373 if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
374 error("%s: failed to receive fd %d from slave",
375 __func__, i);
376 for (j = 0; j < i; j++)
377 close(new_fd[j]);
378 for (j = 0; j < env_len; j++)
379 xfree(cctx->env[j]);
380 if (env_len > 0)
381 xfree(cctx->env);
382 xfree(cctx->term);
383 buffer_free(&cctx->cmd);
384 xfree(cctx);
385
386 /* prepare reply */
387 buffer_put_int(r, MUX_S_FAILURE);
388 buffer_put_int(r, rid);
389 buffer_put_cstring(r,
390 "did not receive file descriptors");
391 return -1;
392 }
393 }
394
395 debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
396 new_fd[0], new_fd[1], new_fd[2]);
397
398 /* XXX support multiple child sessions in future */
399 if (c->remote_id != -1) {
400 debug2("%s: session already open", __func__);
401 /* prepare reply */
402 buffer_put_int(r, MUX_S_FAILURE);
403 buffer_put_int(r, rid);
404 buffer_put_cstring(r, "Multiple sessions not supported");
405 cleanup:
406 close(new_fd[0]);
407 close(new_fd[1]);
408 close(new_fd[2]);
409 xfree(cctx->term);
410 if (env_len != 0) {
411 for (i = 0; i < env_len; i++)
412 xfree(cctx->env[i]);
413 xfree(cctx->env);
414 }
415 buffer_free(&cctx->cmd);
416 return 0;
417 }
418
419 if (options.control_master == SSHCTL_MASTER_ASK ||
420 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
421 if (!ask_permission("Allow shared connection to %s? ", host)) {
422 debug2("%s: session refused by user", __func__);
423 /* prepare reply */
424 buffer_put_int(r, MUX_S_PERMISSION_DENIED);
425 buffer_put_int(r, rid);
426 buffer_put_cstring(r, "Permission denied");
427 goto cleanup;
428 }
429 }
430
431 /* Try to pick up ttymodes from client before it goes raw */
432 if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
433 error("%s: tcgetattr: %s", __func__, strerror(errno));
434
435 /* enable nonblocking unless tty */
436 if (!isatty(new_fd[0]))
437 set_nonblock(new_fd[0]);
438 if (!isatty(new_fd[1]))
439 set_nonblock(new_fd[1]);
440 if (!isatty(new_fd[2]))
441 set_nonblock(new_fd[2]);
442
443 window = CHAN_SES_WINDOW_DEFAULT;
444 packetmax = CHAN_SES_PACKET_DEFAULT;
445 if (cctx->want_tty) {
446 window >>= 1;
447 packetmax >>= 1;
448 }
449
450 nc = channel_new("session", SSH_CHANNEL_OPENING,
451 new_fd[0], new_fd[1], new_fd[2], window, packetmax,
452 CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
453
454 nc->ctl_chan = c->self; /* link session -> control channel */
455 c->remote_id = nc->self; /* link control -> session channel */
456
457 if (cctx->want_tty && escape_char != 0xffffffff) {
458 channel_register_filter(nc->self,
459 client_simple_escape_filter, NULL,
460 client_filter_cleanup,
461 client_new_escape_filter_ctx((int)escape_char));
462 }
463
464 debug2("%s: channel_new: %d linked to control channel %d",
465 __func__, nc->self, nc->ctl_chan);
466
467 channel_send_open(nc->self);
468 channel_register_open_confirm(nc->self, mux_session_confirm, cctx);
Damien Millerd530f5f2010-05-21 14:57:10 +1000469 c->mux_pause = 1; /* stop handling messages until open_confirm done */
Damien Miller85c50d72010-05-10 11:53:02 +1000470 channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
Damien Millere1537f92010-01-26 13:26:22 +1100471
Damien Millerd530f5f2010-05-21 14:57:10 +1000472 /* reply is deferred, sent by mux_session_confirm */
Damien Millere1537f92010-01-26 13:26:22 +1100473 return 0;
474}
475
476static int
477process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r)
478{
479 debug2("%s: channel %d: alive check", __func__, c->self);
480
481 /* prepare reply */
482 buffer_put_int(r, MUX_S_ALIVE);
483 buffer_put_int(r, rid);
484 buffer_put_int(r, (u_int)getpid());
485
486 return 0;
487}
488
489static int
490process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r)
491{
492 debug2("%s: channel %d: terminate request", __func__, c->self);
493
494 if (options.control_master == SSHCTL_MASTER_ASK ||
495 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
496 if (!ask_permission("Terminate shared connection to %s? ",
497 host)) {
498 debug2("%s: termination refused by user", __func__);
499 buffer_put_int(r, MUX_S_PERMISSION_DENIED);
500 buffer_put_int(r, rid);
501 buffer_put_cstring(r, "Permission denied");
502 return 0;
503 }
504 }
505
506 quit_pending = 1;
507 buffer_put_int(r, MUX_S_OK);
508 buffer_put_int(r, rid);
509 /* XXX exit happens too soon - message never makes it to client */
510 return 0;
511}
512
513static char *
514format_forward(u_int ftype, Forward *fwd)
515{
516 char *ret;
517
518 switch (ftype) {
519 case MUX_FWD_LOCAL:
520 xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d",
521 (fwd->listen_host == NULL) ?
522 (options.gateway_ports ? "*" : "LOCALHOST") :
523 fwd->listen_host, fwd->listen_port,
524 fwd->connect_host, fwd->connect_port);
525 break;
526 case MUX_FWD_DYNAMIC:
527 xasprintf(&ret, "dynamic forward %.200s:%d -> *",
528 (fwd->listen_host == NULL) ?
529 (options.gateway_ports ? "*" : "LOCALHOST") :
530 fwd->listen_host, fwd->listen_port);
531 break;
532 case MUX_FWD_REMOTE:
533 xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d",
534 (fwd->listen_host == NULL) ?
535 "LOCALHOST" : fwd->listen_host,
536 fwd->listen_port,
537 fwd->connect_host, fwd->connect_port);
538 break;
539 default:
540 fatal("%s: unknown forward type %u", __func__, ftype);
541 }
542 return ret;
543}
544
545static int
546compare_host(const char *a, const char *b)
547{
548 if (a == NULL && b == NULL)
549 return 1;
550 if (a == NULL || b == NULL)
551 return 0;
552 return strcmp(a, b) == 0;
553}
554
555static int
556compare_forward(Forward *a, Forward *b)
557{
558 if (!compare_host(a->listen_host, b->listen_host))
559 return 0;
560 if (a->listen_port != b->listen_port)
561 return 0;
562 if (!compare_host(a->connect_host, b->connect_host))
563 return 0;
564 if (a->connect_port != b->connect_port)
565 return 0;
566
567 return 1;
568}
569
Damien Miller388f6fc2010-05-21 14:57:35 +1000570static void
571mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
572{
573 struct mux_channel_confirm_ctx *fctx = ctxt;
574 char *failmsg = NULL;
575 Forward *rfwd;
576 Channel *c;
577 Buffer out;
578
579 if ((c = channel_by_id(fctx->cid)) == NULL) {
580 /* no channel for reply */
581 error("%s: unknown channel", __func__);
582 return;
583 }
584 buffer_init(&out);
585 if (fctx->fid >= options.num_remote_forwards) {
586 xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid);
587 goto fail;
588 }
589 rfwd = &options.remote_forwards[fctx->fid];
590 debug("%s: %s for: listen %d, connect %s:%d", __func__,
591 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
592 rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
593 if (type == SSH2_MSG_REQUEST_SUCCESS) {
594 if (rfwd->listen_port == 0) {
595 rfwd->allocated_port = packet_get_int();
596 logit("Allocated port %u for mux remote forward"
597 " to %s:%d", rfwd->allocated_port,
598 rfwd->connect_host, rfwd->connect_port);
599 buffer_put_int(&out, MUX_S_REMOTE_PORT);
600 buffer_put_int(&out, fctx->rid);
601 buffer_put_int(&out, rfwd->allocated_port);
Darren Tucker68afb8c2011-10-02 18:59:03 +1100602 channel_update_permitted_opens(rfwd->handle,
603 rfwd->allocated_port);
Damien Miller388f6fc2010-05-21 14:57:35 +1000604 } else {
605 buffer_put_int(&out, MUX_S_OK);
606 buffer_put_int(&out, fctx->rid);
607 }
608 goto out;
609 } else {
Darren Tucker68afb8c2011-10-02 18:59:03 +1100610 if (rfwd->listen_port == 0)
611 channel_update_permitted_opens(rfwd->handle, -1);
Damien Miller388f6fc2010-05-21 14:57:35 +1000612 xasprintf(&failmsg, "remote port forwarding failed for "
613 "listen port %d", rfwd->listen_port);
614 }
615 fail:
616 error("%s: %s", __func__, failmsg);
617 buffer_put_int(&out, MUX_S_FAILURE);
618 buffer_put_int(&out, fctx->rid);
619 buffer_put_cstring(&out, failmsg);
620 xfree(failmsg);
621 out:
622 buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out));
623 buffer_free(&out);
624 if (c->mux_pause <= 0)
625 fatal("%s: mux_pause %d", __func__, c->mux_pause);
626 c->mux_pause = 0; /* start processing messages again */
627}
628
Damien Millere1537f92010-01-26 13:26:22 +1100629static int
630process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
631{
632 Forward fwd;
633 char *fwd_desc = NULL;
634 u_int ftype;
635 int i, ret = 0, freefwd = 1;
636
637 fwd.listen_host = fwd.connect_host = NULL;
638 if (buffer_get_int_ret(&ftype, m) != 0 ||
639 (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
640 buffer_get_int_ret(&fwd.listen_port, m) != 0 ||
641 (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
642 buffer_get_int_ret(&fwd.connect_port, m) != 0) {
643 error("%s: malformed message", __func__);
644 ret = -1;
645 goto out;
646 }
647
648 if (*fwd.listen_host == '\0') {
649 xfree(fwd.listen_host);
650 fwd.listen_host = NULL;
651 }
652 if (*fwd.connect_host == '\0') {
653 xfree(fwd.connect_host);
654 fwd.connect_host = NULL;
655 }
656
657 debug2("%s: channel %d: request %s", __func__, c->self,
658 (fwd_desc = format_forward(ftype, &fwd)));
659
660 if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE &&
661 ftype != MUX_FWD_DYNAMIC) {
662 logit("%s: invalid forwarding type %u", __func__, ftype);
663 invalid:
Damien Miller388f6fc2010-05-21 14:57:35 +1000664 if (fwd.listen_host)
665 xfree(fwd.listen_host);
666 if (fwd.connect_host)
667 xfree(fwd.connect_host);
Damien Millere1537f92010-01-26 13:26:22 +1100668 buffer_put_int(r, MUX_S_FAILURE);
669 buffer_put_int(r, rid);
670 buffer_put_cstring(r, "Invalid forwarding request");
671 return 0;
672 }
Damien Miller388f6fc2010-05-21 14:57:35 +1000673 if (fwd.listen_port >= 65536) {
Damien Millere1537f92010-01-26 13:26:22 +1100674 logit("%s: invalid listen port %u", __func__,
675 fwd.listen_port);
676 goto invalid;
677 }
678 if (fwd.connect_port >= 65536 || (ftype != MUX_FWD_DYNAMIC &&
679 ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) {
680 logit("%s: invalid connect port %u", __func__,
681 fwd.connect_port);
682 goto invalid;
683 }
684 if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL) {
685 logit("%s: missing connect host", __func__);
686 goto invalid;
687 }
688
689 /* Skip forwards that have already been requested */
690 switch (ftype) {
691 case MUX_FWD_LOCAL:
692 case MUX_FWD_DYNAMIC:
693 for (i = 0; i < options.num_local_forwards; i++) {
694 if (compare_forward(&fwd,
695 options.local_forwards + i)) {
696 exists:
697 debug2("%s: found existing forwarding",
698 __func__);
699 buffer_put_int(r, MUX_S_OK);
700 buffer_put_int(r, rid);
701 goto out;
702 }
703 }
704 break;
705 case MUX_FWD_REMOTE:
706 for (i = 0; i < options.num_remote_forwards; i++) {
707 if (compare_forward(&fwd,
Damien Miller388f6fc2010-05-21 14:57:35 +1000708 options.remote_forwards + i)) {
709 if (fwd.listen_port != 0)
710 goto exists;
711 debug2("%s: found allocated port",
712 __func__);
713 buffer_put_int(r, MUX_S_REMOTE_PORT);
714 buffer_put_int(r, rid);
715 buffer_put_int(r,
716 options.remote_forwards[i].allocated_port);
717 goto out;
718 }
Damien Millere1537f92010-01-26 13:26:22 +1100719 }
720 break;
721 }
722
723 if (options.control_master == SSHCTL_MASTER_ASK ||
724 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
725 if (!ask_permission("Open %s on %s?", fwd_desc, host)) {
726 debug2("%s: forwarding refused by user", __func__);
727 buffer_put_int(r, MUX_S_PERMISSION_DENIED);
728 buffer_put_int(r, rid);
729 buffer_put_cstring(r, "Permission denied");
730 goto out;
731 }
732 }
733
734 if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) {
Damien Miller232cfb12010-06-26 09:50:30 +1000735 if (channel_setup_local_fwd_listener(fwd.listen_host,
Damien Millere1537f92010-01-26 13:26:22 +1100736 fwd.listen_port, fwd.connect_host, fwd.connect_port,
737 options.gateway_ports) < 0) {
738 fail:
739 logit("slave-requested %s failed", fwd_desc);
740 buffer_put_int(r, MUX_S_FAILURE);
741 buffer_put_int(r, rid);
742 buffer_put_cstring(r, "Port forwarding failed");
743 goto out;
744 }
745 add_local_forward(&options, &fwd);
746 freefwd = 0;
747 } else {
Damien Miller388f6fc2010-05-21 14:57:35 +1000748 struct mux_channel_confirm_ctx *fctx;
749
Darren Tucker68afb8c2011-10-02 18:59:03 +1100750 fwd.handle = channel_request_remote_forwarding(fwd.listen_host,
751 fwd.listen_port, fwd.connect_host, fwd.connect_port);
752 if (fwd.handle < 0)
Damien Millere1537f92010-01-26 13:26:22 +1100753 goto fail;
754 add_remote_forward(&options, &fwd);
Damien Miller388f6fc2010-05-21 14:57:35 +1000755 fctx = xcalloc(1, sizeof(*fctx));
756 fctx->cid = c->self;
757 fctx->rid = rid;
Damien Miller232cfb12010-06-26 09:50:30 +1000758 fctx->fid = options.num_remote_forwards - 1;
Damien Miller388f6fc2010-05-21 14:57:35 +1000759 client_register_global_confirm(mux_confirm_remote_forward,
760 fctx);
Damien Millere1537f92010-01-26 13:26:22 +1100761 freefwd = 0;
Damien Miller388f6fc2010-05-21 14:57:35 +1000762 c->mux_pause = 1; /* wait for mux_confirm_remote_forward */
763 /* delayed reply in mux_confirm_remote_forward */
764 goto out;
Damien Millere1537f92010-01-26 13:26:22 +1100765 }
766 buffer_put_int(r, MUX_S_OK);
767 buffer_put_int(r, rid);
768 out:
769 if (fwd_desc != NULL)
770 xfree(fwd_desc);
771 if (freefwd) {
772 if (fwd.listen_host != NULL)
773 xfree(fwd.listen_host);
774 if (fwd.connect_host != NULL)
775 xfree(fwd.connect_host);
776 }
777 return ret;
778}
779
780static int
781process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
782{
Damien Millerf6dff7c2011-09-22 21:38:52 +1000783 Forward fwd, *found_fwd;
Damien Millere1537f92010-01-26 13:26:22 +1100784 char *fwd_desc = NULL;
Damien Millerf6dff7c2011-09-22 21:38:52 +1000785 const char *error_reason = NULL;
Damien Millere1537f92010-01-26 13:26:22 +1100786 u_int ftype;
Darren Tucker68afb8c2011-10-02 18:59:03 +1100787 int i, listen_port, ret = 0;
Damien Millere1537f92010-01-26 13:26:22 +1100788
789 fwd.listen_host = fwd.connect_host = NULL;
790 if (buffer_get_int_ret(&ftype, m) != 0 ||
791 (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
792 buffer_get_int_ret(&fwd.listen_port, m) != 0 ||
793 (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
794 buffer_get_int_ret(&fwd.connect_port, m) != 0) {
795 error("%s: malformed message", __func__);
796 ret = -1;
797 goto out;
798 }
799
800 if (*fwd.listen_host == '\0') {
801 xfree(fwd.listen_host);
802 fwd.listen_host = NULL;
803 }
804 if (*fwd.connect_host == '\0') {
805 xfree(fwd.connect_host);
806 fwd.connect_host = NULL;
807 }
808
Damien Millerf6dff7c2011-09-22 21:38:52 +1000809 debug2("%s: channel %d: request cancel %s", __func__, c->self,
Damien Millere1537f92010-01-26 13:26:22 +1100810 (fwd_desc = format_forward(ftype, &fwd)));
811
Damien Millerf6dff7c2011-09-22 21:38:52 +1000812 /* make sure this has been requested */
813 found_fwd = NULL;
814 switch (ftype) {
815 case MUX_FWD_LOCAL:
816 case MUX_FWD_DYNAMIC:
817 for (i = 0; i < options.num_local_forwards; i++) {
818 if (compare_forward(&fwd,
819 options.local_forwards + i)) {
820 found_fwd = options.local_forwards + i;
821 break;
822 }
823 }
824 break;
825 case MUX_FWD_REMOTE:
826 for (i = 0; i < options.num_remote_forwards; i++) {
827 if (compare_forward(&fwd,
828 options.remote_forwards + i)) {
829 found_fwd = options.remote_forwards + i;
830 break;
831 }
832 }
833 break;
834 }
Damien Millere1537f92010-01-26 13:26:22 +1100835
Damien Millerf6dff7c2011-09-22 21:38:52 +1000836 if (found_fwd == NULL)
837 error_reason = "port not forwarded";
838 else if (ftype == MUX_FWD_REMOTE) {
839 /*
840 * This shouldn't fail unless we confused the host/port
841 * between options.remote_forwards and permitted_opens.
Darren Tucker68afb8c2011-10-02 18:59:03 +1100842 * However, for dynamic allocated listen ports we need
843 * to lookup the actual listen port.
Damien Millerf6dff7c2011-09-22 21:38:52 +1000844 */
Darren Tucker68afb8c2011-10-02 18:59:03 +1100845 listen_port = (fwd.listen_port == 0) ?
846 found_fwd->allocated_port : fwd.listen_port;
Damien Millerf6dff7c2011-09-22 21:38:52 +1000847 if (channel_request_rforward_cancel(fwd.listen_host,
Darren Tucker68afb8c2011-10-02 18:59:03 +1100848 listen_port) == -1)
Damien Millerf6dff7c2011-09-22 21:38:52 +1000849 error_reason = "port not in permitted opens";
850 } else { /* local and dynamic forwards */
851 /* Ditto */
852 if (channel_cancel_lport_listener(fwd.listen_host,
853 fwd.listen_port, fwd.connect_port,
854 options.gateway_ports) == -1)
855 error_reason = "port not found";
856 }
857
858 if (error_reason == NULL) {
859 buffer_put_int(r, MUX_S_OK);
860 buffer_put_int(r, rid);
861
862 if (found_fwd->listen_host != NULL)
863 xfree(found_fwd->listen_host);
864 if (found_fwd->connect_host != NULL)
865 xfree(found_fwd->connect_host);
866 found_fwd->listen_host = found_fwd->connect_host = NULL;
867 found_fwd->listen_port = found_fwd->connect_port = 0;
868 } else {
869 buffer_put_int(r, MUX_S_FAILURE);
870 buffer_put_int(r, rid);
871 buffer_put_cstring(r, error_reason);
872 }
Damien Millere1537f92010-01-26 13:26:22 +1100873 out:
874 if (fwd_desc != NULL)
875 xfree(fwd_desc);
876 if (fwd.listen_host != NULL)
877 xfree(fwd.listen_host);
878 if (fwd.connect_host != NULL)
879 xfree(fwd.connect_host);
880
881 return ret;
882}
883
884static int
885process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
886{
887 Channel *nc;
888 char *reserved, *chost;
889 u_int cport, i, j;
890 int new_fd[2];
891
892 chost = reserved = NULL;
893 if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
894 (chost = buffer_get_string_ret(m, NULL)) == NULL ||
895 buffer_get_int_ret(&cport, m) != 0) {
896 if (reserved != NULL)
897 xfree(reserved);
898 if (chost != NULL)
899 xfree(chost);
900 error("%s: malformed message", __func__);
901 return -1;
902 }
903 xfree(reserved);
904
905 debug2("%s: channel %d: request stdio fwd to %s:%u",
906 __func__, c->self, chost, cport);
907
908 /* Gather fds from client */
909 for(i = 0; i < 2; i++) {
910 if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
911 error("%s: failed to receive fd %d from slave",
912 __func__, i);
913 for (j = 0; j < i; j++)
914 close(new_fd[j]);
915 xfree(chost);
916
917 /* prepare reply */
918 buffer_put_int(r, MUX_S_FAILURE);
919 buffer_put_int(r, rid);
920 buffer_put_cstring(r,
921 "did not receive file descriptors");
922 return -1;
923 }
924 }
925
926 debug3("%s: got fds stdin %d, stdout %d", __func__,
927 new_fd[0], new_fd[1]);
928
929 /* XXX support multiple child sessions in future */
930 if (c->remote_id != -1) {
931 debug2("%s: session already open", __func__);
932 /* prepare reply */
933 buffer_put_int(r, MUX_S_FAILURE);
934 buffer_put_int(r, rid);
935 buffer_put_cstring(r, "Multiple sessions not supported");
936 cleanup:
937 close(new_fd[0]);
938 close(new_fd[1]);
939 xfree(chost);
940 return 0;
941 }
942
943 if (options.control_master == SSHCTL_MASTER_ASK ||
944 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
Damien Miller68512c02010-10-21 15:21:11 +1100945 if (!ask_permission("Allow forward to %s:%u? ",
Damien Millere1537f92010-01-26 13:26:22 +1100946 chost, cport)) {
947 debug2("%s: stdio fwd refused by user", __func__);
948 /* prepare reply */
949 buffer_put_int(r, MUX_S_PERMISSION_DENIED);
950 buffer_put_int(r, rid);
951 buffer_put_cstring(r, "Permission denied");
952 goto cleanup;
953 }
954 }
955
956 /* enable nonblocking unless tty */
957 if (!isatty(new_fd[0]))
958 set_nonblock(new_fd[0]);
959 if (!isatty(new_fd[1]))
960 set_nonblock(new_fd[1]);
961
962 nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]);
963
964 nc->ctl_chan = c->self; /* link session -> control channel */
965 c->remote_id = nc->self; /* link control -> session channel */
966
967 debug2("%s: channel_new: %d linked to control channel %d",
968 __func__, nc->self, nc->ctl_chan);
969
Damien Miller85c50d72010-05-10 11:53:02 +1000970 channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
Damien Millere1537f92010-01-26 13:26:22 +1100971
972 /* prepare reply */
973 /* XXX defer until channel confirmed */
974 buffer_put_int(r, MUX_S_SESSION_OPENED);
975 buffer_put_int(r, rid);
976 buffer_put_int(r, nc->self);
977
978 return 0;
979}
980
Damien Miller6c3eec72011-05-05 14:16:22 +1000981static int
982process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
983{
984 debug("%s: channel %d: stop listening", __func__, c->self);
985
986 if (options.control_master == SSHCTL_MASTER_ASK ||
987 options.control_master == SSHCTL_MASTER_AUTO_ASK) {
988 if (!ask_permission("Disable further multiplexing on shared "
989 "connection to %s? ", host)) {
990 debug2("%s: stop listen refused by user", __func__);
991 buffer_put_int(r, MUX_S_PERMISSION_DENIED);
992 buffer_put_int(r, rid);
993 buffer_put_cstring(r, "Permission denied");
994 return 0;
995 }
996 }
997
998 if (mux_listener_channel != NULL) {
999 channel_free(mux_listener_channel);
1000 client_stop_mux();
1001 xfree(options.control_path);
1002 options.control_path = NULL;
1003 mux_listener_channel = NULL;
1004 muxserver_sock = -1;
1005 }
1006
1007 /* prepare reply */
1008 buffer_put_int(r, MUX_S_OK);
1009 buffer_put_int(r, rid);
1010
1011 return 0;
1012}
1013
Damien Millere1537f92010-01-26 13:26:22 +11001014/* Channel callbacks fired on read/write from mux slave fd */
1015static int
1016mux_master_read_cb(Channel *c)
1017{
1018 struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
1019 Buffer in, out;
1020 void *ptr;
1021 u_int type, rid, have, i;
1022 int ret = -1;
1023
1024 /* Setup ctx and */
1025 if (c->mux_ctx == NULL) {
Damien Millerc094d1e2010-06-26 09:36:34 +10001026 state = xcalloc(1, sizeof(*state));
Damien Millere1537f92010-01-26 13:26:22 +11001027 c->mux_ctx = state;
1028 channel_register_cleanup(c->self,
1029 mux_master_control_cleanup_cb, 0);
1030
1031 /* Send hello */
1032 buffer_init(&out);
1033 buffer_put_int(&out, MUX_MSG_HELLO);
1034 buffer_put_int(&out, SSHMUX_VER);
1035 /* no extensions */
1036 buffer_put_string(&c->output, buffer_ptr(&out),
1037 buffer_len(&out));
1038 buffer_free(&out);
1039 debug3("%s: channel %d: hello sent", __func__, c->self);
1040 return 0;
1041 }
1042
1043 buffer_init(&in);
1044 buffer_init(&out);
1045
1046 /* Channel code ensures that we receive whole packets */
1047 if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) {
1048 malf:
1049 error("%s: malformed message", __func__);
1050 goto out;
1051 }
1052 buffer_append(&in, ptr, have);
1053
1054 if (buffer_get_int_ret(&type, &in) != 0)
1055 goto malf;
1056 debug3("%s: channel %d packet type 0x%08x len %u",
1057 __func__, c->self, type, buffer_len(&in));
1058
1059 if (type == MUX_MSG_HELLO)
1060 rid = 0;
1061 else {
1062 if (!state->hello_rcvd) {
1063 error("%s: expected MUX_MSG_HELLO(0x%08x), "
1064 "received 0x%08x", __func__, MUX_MSG_HELLO, type);
1065 goto out;
1066 }
1067 if (buffer_get_int_ret(&rid, &in) != 0)
1068 goto malf;
1069 }
1070
1071 for (i = 0; mux_master_handlers[i].handler != NULL; i++) {
1072 if (type == mux_master_handlers[i].type) {
1073 ret = mux_master_handlers[i].handler(rid, c, &in, &out);
1074 break;
1075 }
1076 }
1077 if (mux_master_handlers[i].handler == NULL) {
1078 error("%s: unsupported mux message 0x%08x", __func__, type);
1079 buffer_put_int(&out, MUX_S_FAILURE);
1080 buffer_put_int(&out, rid);
1081 buffer_put_cstring(&out, "unsupported request");
1082 ret = 0;
1083 }
1084 /* Enqueue reply packet */
1085 if (buffer_len(&out) != 0) {
1086 buffer_put_string(&c->output, buffer_ptr(&out),
1087 buffer_len(&out));
1088 }
1089 out:
1090 buffer_free(&in);
1091 buffer_free(&out);
1092 return ret;
1093}
1094
1095void
1096mux_exit_message(Channel *c, int exitval)
1097{
1098 Buffer m;
1099 Channel *mux_chan;
1100
1101 debug3("%s: channel %d: exit message, evitval %d", __func__, c->self,
1102 exitval);
1103
1104 if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
1105 fatal("%s: channel %d missing mux channel %d",
1106 __func__, c->self, c->ctl_chan);
1107
1108 /* Append exit message packet to control socket output queue */
1109 buffer_init(&m);
1110 buffer_put_int(&m, MUX_S_EXIT_MESSAGE);
1111 buffer_put_int(&m, c->self);
1112 buffer_put_int(&m, exitval);
1113
1114 buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
1115 buffer_free(&m);
1116}
Damien Millerb1cbfa22008-05-19 16:00:08 +10001117
Damien Miller555f3b82011-05-15 08:48:05 +10001118void
1119mux_tty_alloc_failed(Channel *c)
1120{
1121 Buffer m;
1122 Channel *mux_chan;
1123
1124 debug3("%s: channel %d: TTY alloc failed", __func__, c->self);
1125
1126 if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
1127 fatal("%s: channel %d missing mux channel %d",
1128 __func__, c->self, c->ctl_chan);
1129
1130 /* Append exit message packet to control socket output queue */
1131 buffer_init(&m);
1132 buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL);
1133 buffer_put_int(&m, c->self);
1134
1135 buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
1136 buffer_free(&m);
1137}
1138
Damien Millerb1cbfa22008-05-19 16:00:08 +10001139/* Prepare a mux master to listen on a Unix domain socket. */
1140void
1141muxserver_listen(void)
1142{
1143 struct sockaddr_un addr;
Damien Millere1537f92010-01-26 13:26:22 +11001144 socklen_t sun_len;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001145 mode_t old_umask;
Damien Miller603134e2010-09-24 22:07:55 +10001146 char *orig_control_path = options.control_path;
1147 char rbuf[16+1];
1148 u_int i, r;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001149
1150 if (options.control_path == NULL ||
1151 options.control_master == SSHCTL_MASTER_NO)
1152 return;
1153
1154 debug("setting up multiplex master socket");
1155
Damien Miller603134e2010-09-24 22:07:55 +10001156 /*
1157 * Use a temporary path before listen so we can pseudo-atomically
1158 * establish the listening socket in its final location to avoid
1159 * other processes racing in between bind() and listen() and hitting
1160 * an unready socket.
1161 */
1162 for (i = 0; i < sizeof(rbuf) - 1; i++) {
1163 r = arc4random_uniform(26+26+10);
1164 rbuf[i] = (r < 26) ? 'a' + r :
1165 (r < 26*2) ? 'A' + r - 26 :
1166 '0' + r - 26 - 26;
1167 }
1168 rbuf[sizeof(rbuf) - 1] = '\0';
1169 options.control_path = NULL;
1170 xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf);
1171 debug3("%s: temporary control path %s", __func__, options.control_path);
1172
Damien Millerb1cbfa22008-05-19 16:00:08 +10001173 memset(&addr, '\0', sizeof(addr));
1174 addr.sun_family = AF_UNIX;
Damien Millere1537f92010-01-26 13:26:22 +11001175 sun_len = offsetof(struct sockaddr_un, sun_path) +
Damien Millerb1cbfa22008-05-19 16:00:08 +10001176 strlen(options.control_path) + 1;
1177
1178 if (strlcpy(addr.sun_path, options.control_path,
Damien Miller60432d82011-05-15 08:34:46 +10001179 sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) {
1180 error("ControlPath \"%s\" too long for Unix domain socket",
1181 options.control_path);
1182 goto disable_mux_master;
1183 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10001184
1185 if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1186 fatal("%s socket(): %s", __func__, strerror(errno));
1187
1188 old_umask = umask(0177);
Damien Millere1537f92010-01-26 13:26:22 +11001189 if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) {
Darren Tuckerca19bfe2008-06-13 10:24:03 +10001190 if (errno == EINVAL || errno == EADDRINUSE) {
1191 error("ControlSocket %s already exists, "
1192 "disabling multiplexing", options.control_path);
Damien Miller603134e2010-09-24 22:07:55 +10001193 disable_mux_master:
Damien Miller60432d82011-05-15 08:34:46 +10001194 if (muxserver_sock != -1) {
1195 close(muxserver_sock);
1196 muxserver_sock = -1;
1197 }
Darren Tuckerca19bfe2008-06-13 10:24:03 +10001198 xfree(options.control_path);
1199 options.control_path = NULL;
1200 options.control_master = SSHCTL_MASTER_NO;
1201 return;
1202 } else
Damien Millerb1cbfa22008-05-19 16:00:08 +10001203 fatal("%s bind(): %s", __func__, strerror(errno));
1204 }
1205 umask(old_umask);
1206
1207 if (listen(muxserver_sock, 64) == -1)
1208 fatal("%s listen(): %s", __func__, strerror(errno));
1209
Damien Miller603134e2010-09-24 22:07:55 +10001210 /* Now atomically "move" the mux socket into position */
1211 if (link(options.control_path, orig_control_path) != 0) {
1212 if (errno != EEXIST) {
1213 fatal("%s: link mux listener %s => %s: %s", __func__,
1214 options.control_path, orig_control_path,
1215 strerror(errno));
1216 }
1217 error("ControlSocket %s already exists, disabling multiplexing",
1218 orig_control_path);
1219 xfree(orig_control_path);
1220 unlink(options.control_path);
1221 goto disable_mux_master;
1222 }
1223 unlink(options.control_path);
1224 xfree(options.control_path);
1225 options.control_path = orig_control_path;
1226
Damien Millerb1cbfa22008-05-19 16:00:08 +10001227 set_nonblock(muxserver_sock);
Damien Millere1537f92010-01-26 13:26:22 +11001228
1229 mux_listener_channel = channel_new("mux listener",
1230 SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1,
1231 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
Damien Miller603134e2010-09-24 22:07:55 +10001232 0, options.control_path, 1);
Damien Millere1537f92010-01-26 13:26:22 +11001233 mux_listener_channel->mux_rcb = mux_master_read_cb;
1234 debug3("%s: mux listener channel %d fd %d", __func__,
1235 mux_listener_channel->self, mux_listener_channel->sock);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001236}
1237
1238/* Callback on open confirmation in mux master for a mux client session. */
1239static void
Damien Millerd530f5f2010-05-21 14:57:10 +10001240mux_session_confirm(int id, int success, void *arg)
Damien Millerb1cbfa22008-05-19 16:00:08 +10001241{
1242 struct mux_session_confirm_ctx *cctx = arg;
1243 const char *display;
Damien Millerd530f5f2010-05-21 14:57:10 +10001244 Channel *c, *cc;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001245 int i;
Damien Millerd530f5f2010-05-21 14:57:10 +10001246 Buffer reply;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001247
1248 if (cctx == NULL)
1249 fatal("%s: cctx == NULL", __func__);
Damien Millere1537f92010-01-26 13:26:22 +11001250 if ((c = channel_by_id(id)) == NULL)
Damien Millerb1cbfa22008-05-19 16:00:08 +10001251 fatal("%s: no channel for id %d", __func__, id);
Damien Millerd530f5f2010-05-21 14:57:10 +10001252 if ((cc = channel_by_id(c->ctl_chan)) == NULL)
1253 fatal("%s: channel %d lacks control channel %d", __func__,
1254 id, c->ctl_chan);
1255
1256 if (!success) {
1257 debug3("%s: sending failure reply", __func__);
1258 /* prepare reply */
1259 buffer_init(&reply);
1260 buffer_put_int(&reply, MUX_S_FAILURE);
1261 buffer_put_int(&reply, cctx->rid);
1262 buffer_put_cstring(&reply, "Session open refused by peer");
1263 goto done;
1264 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10001265
1266 display = getenv("DISPLAY");
1267 if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
1268 char *proto, *data;
Damien Miller1ab6a512010-06-26 10:02:24 +10001269
Damien Millerb1cbfa22008-05-19 16:00:08 +10001270 /* Get reasonable local authentication information. */
1271 client_x11_get_proto(display, options.xauth_location,
Damien Miller1ab6a512010-06-26 10:02:24 +10001272 options.forward_x11_trusted, options.forward_x11_timeout,
1273 &proto, &data);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001274 /* Request forwarding with authentication spoofing. */
Damien Miller1ab6a512010-06-26 10:02:24 +10001275 debug("Requesting X11 forwarding with authentication "
1276 "spoofing.");
Damien Miller6d7b4372011-06-23 08:31:57 +10001277 x11_request_forwarding_with_spoofing(id, display, proto,
1278 data, 1);
1279 client_expect_confirm(id, "X11 forwarding", CONFIRM_WARN);
1280 /* XXX exit_on_forward_failure */
Damien Millerb1cbfa22008-05-19 16:00:08 +10001281 }
1282
1283 if (cctx->want_agent_fwd && options.forward_agent) {
1284 debug("Requesting authentication agent forwarding.");
1285 channel_request_start(id, "auth-agent-req@openssh.com", 0);
1286 packet_send();
1287 }
1288
1289 client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
1290 cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);
1291
Damien Millerd530f5f2010-05-21 14:57:10 +10001292 debug3("%s: sending success reply", __func__);
1293 /* prepare reply */
1294 buffer_init(&reply);
1295 buffer_put_int(&reply, MUX_S_SESSION_OPENED);
1296 buffer_put_int(&reply, cctx->rid);
1297 buffer_put_int(&reply, c->self);
1298
1299 done:
1300 /* Send reply */
1301 buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
1302 buffer_free(&reply);
1303
1304 if (cc->mux_pause <= 0)
1305 fatal("%s: mux_pause %d", __func__, cc->mux_pause);
1306 cc->mux_pause = 0; /* start processing messages again */
Damien Millerb1cbfa22008-05-19 16:00:08 +10001307 c->open_confirm_ctx = NULL;
1308 buffer_free(&cctx->cmd);
1309 xfree(cctx->term);
1310 if (cctx->env != NULL) {
1311 for (i = 0; cctx->env[i] != NULL; i++)
1312 xfree(cctx->env[i]);
1313 xfree(cctx->env);
1314 }
1315 xfree(cctx);
1316}
1317
Damien Millerb1cbfa22008-05-19 16:00:08 +10001318/* ** Multiplexing client support */
1319
1320/* Exit signal handler */
1321static void
1322control_client_sighandler(int signo)
1323{
1324 muxclient_terminate = signo;
1325}
1326
1327/*
1328 * Relay signal handler - used to pass some signals from mux client to
1329 * mux master.
1330 */
1331static void
1332control_client_sigrelay(int signo)
1333{
1334 int save_errno = errno;
1335
1336 if (muxserver_pid > 1)
1337 kill(muxserver_pid, signo);
1338
1339 errno = save_errno;
1340}
1341
Damien Millerb1cbfa22008-05-19 16:00:08 +10001342static int
Damien Millere1537f92010-01-26 13:26:22 +11001343mux_client_read(int fd, Buffer *b, u_int need)
Damien Millerb1cbfa22008-05-19 16:00:08 +10001344{
Damien Millere1537f92010-01-26 13:26:22 +11001345 u_int have;
1346 ssize_t len;
1347 u_char *p;
1348 struct pollfd pfd;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001349
Damien Millere1537f92010-01-26 13:26:22 +11001350 pfd.fd = fd;
1351 pfd.events = POLLIN;
1352 p = buffer_append_space(b, need);
1353 for (have = 0; have < need; ) {
1354 if (muxclient_terminate) {
1355 errno = EINTR;
1356 return -1;
1357 }
1358 len = read(fd, p + have, need - have);
1359 if (len < 0) {
1360 switch (errno) {
1361#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1362 case EWOULDBLOCK:
1363#endif
1364 case EAGAIN:
1365 (void)poll(&pfd, 1, -1);
1366 /* FALLTHROUGH */
1367 case EINTR:
1368 continue;
1369 default:
1370 return -1;
1371 }
1372 }
1373 if (len == 0) {
1374 errno = EPIPE;
1375 return -1;
1376 }
1377 have += (u_int)len;
1378 }
1379 return 0;
1380}
Damien Millerb1cbfa22008-05-19 16:00:08 +10001381
Damien Millere1537f92010-01-26 13:26:22 +11001382static int
1383mux_client_write_packet(int fd, Buffer *m)
1384{
1385 Buffer queue;
1386 u_int have, need;
1387 int oerrno, len;
1388 u_char *ptr;
1389 struct pollfd pfd;
Damien Millerb1cbfa22008-05-19 16:00:08 +10001390
Damien Millere1537f92010-01-26 13:26:22 +11001391 pfd.fd = fd;
1392 pfd.events = POLLOUT;
1393 buffer_init(&queue);
1394 buffer_put_string(&queue, buffer_ptr(m), buffer_len(m));
1395
1396 need = buffer_len(&queue);
1397 ptr = buffer_ptr(&queue);
1398
1399 for (have = 0; have < need; ) {
1400 if (muxclient_terminate) {
1401 buffer_free(&queue);
1402 errno = EINTR;
1403 return -1;
1404 }
1405 len = write(fd, ptr + have, need - have);
1406 if (len < 0) {
1407 switch (errno) {
1408#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1409 case EWOULDBLOCK:
1410#endif
1411 case EAGAIN:
1412 (void)poll(&pfd, 1, -1);
1413 /* FALLTHROUGH */
1414 case EINTR:
1415 continue;
1416 default:
1417 oerrno = errno;
1418 buffer_free(&queue);
1419 errno = oerrno;
1420 return -1;
1421 }
1422 }
1423 if (len == 0) {
1424 buffer_free(&queue);
1425 errno = EPIPE;
1426 return -1;
1427 }
1428 have += (u_int)len;
1429 }
1430 buffer_free(&queue);
1431 return 0;
1432}
1433
1434static int
1435mux_client_read_packet(int fd, Buffer *m)
1436{
1437 Buffer queue;
1438 u_int need, have;
1439 void *ptr;
1440 int oerrno;
1441
1442 buffer_init(&queue);
1443 if (mux_client_read(fd, &queue, 4) != 0) {
1444 if ((oerrno = errno) == EPIPE)
1445 debug3("%s: read header failed: %s", __func__, strerror(errno));
1446 errno = oerrno;
1447 return -1;
1448 }
1449 need = get_u32(buffer_ptr(&queue));
1450 if (mux_client_read(fd, &queue, need) != 0) {
1451 oerrno = errno;
1452 debug3("%s: read body failed: %s", __func__, strerror(errno));
1453 errno = oerrno;
1454 return -1;
1455 }
1456 ptr = buffer_get_string_ptr(&queue, &have);
1457 buffer_append(m, ptr, have);
1458 buffer_free(&queue);
1459 return 0;
1460}
1461
1462static int
1463mux_client_hello_exchange(int fd)
1464{
1465 Buffer m;
1466 u_int type, ver;
1467
1468 buffer_init(&m);
1469 buffer_put_int(&m, MUX_MSG_HELLO);
1470 buffer_put_int(&m, SSHMUX_VER);
1471 /* no extensions */
1472
1473 if (mux_client_write_packet(fd, &m) != 0)
1474 fatal("%s: write packet: %s", __func__, strerror(errno));
1475
1476 buffer_clear(&m);
1477
1478 /* Read their HELLO */
1479 if (mux_client_read_packet(fd, &m) != 0) {
1480 buffer_free(&m);
1481 return -1;
1482 }
1483
1484 type = buffer_get_int(&m);
1485 if (type != MUX_MSG_HELLO)
1486 fatal("%s: expected HELLO (%u) received %u",
1487 __func__, MUX_MSG_HELLO, type);
1488 ver = buffer_get_int(&m);
1489 if (ver != SSHMUX_VER)
1490 fatal("Unsupported multiplexing protocol version %d "
1491 "(expected %d)", ver, SSHMUX_VER);
1492 debug2("%s: master version %u", __func__, ver);
1493 /* No extensions are presently defined */
1494 while (buffer_len(&m) > 0) {
1495 char *name = buffer_get_string(&m, NULL);
1496 char *value = buffer_get_string(&m, NULL);
1497
1498 debug2("Unrecognised master extension \"%s\"", name);
1499 xfree(name);
1500 xfree(value);
1501 }
1502 buffer_free(&m);
1503 return 0;
1504}
1505
1506static u_int
1507mux_client_request_alive(int fd)
1508{
1509 Buffer m;
1510 char *e;
1511 u_int pid, type, rid;
1512
1513 debug3("%s: entering", __func__);
1514
1515 buffer_init(&m);
1516 buffer_put_int(&m, MUX_C_ALIVE_CHECK);
1517 buffer_put_int(&m, muxclient_request_id);
1518
1519 if (mux_client_write_packet(fd, &m) != 0)
1520 fatal("%s: write packet: %s", __func__, strerror(errno));
1521
1522 buffer_clear(&m);
1523
1524 /* Read their reply */
1525 if (mux_client_read_packet(fd, &m) != 0) {
1526 buffer_free(&m);
1527 return 0;
1528 }
1529
1530 type = buffer_get_int(&m);
1531 if (type != MUX_S_ALIVE) {
1532 e = buffer_get_string(&m, NULL);
1533 fatal("%s: master returned error: %s", __func__, e);
1534 }
1535
1536 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1537 fatal("%s: out of sequence reply: my id %u theirs %u",
1538 __func__, muxclient_request_id, rid);
1539 pid = buffer_get_int(&m);
1540 buffer_free(&m);
1541
1542 debug3("%s: done pid = %u", __func__, pid);
1543
1544 muxclient_request_id++;
1545
1546 return pid;
1547}
1548
1549static void
1550mux_client_request_terminate(int fd)
1551{
1552 Buffer m;
1553 char *e;
1554 u_int type, rid;
1555
1556 debug3("%s: entering", __func__);
1557
1558 buffer_init(&m);
1559 buffer_put_int(&m, MUX_C_TERMINATE);
1560 buffer_put_int(&m, muxclient_request_id);
1561
1562 if (mux_client_write_packet(fd, &m) != 0)
1563 fatal("%s: write packet: %s", __func__, strerror(errno));
1564
1565 buffer_clear(&m);
1566
1567 /* Read their reply */
1568 if (mux_client_read_packet(fd, &m) != 0) {
1569 /* Remote end exited already */
1570 if (errno == EPIPE) {
1571 buffer_free(&m);
1572 return;
1573 }
1574 fatal("%s: read from master failed: %s",
1575 __func__, strerror(errno));
1576 }
1577
1578 type = buffer_get_int(&m);
1579 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1580 fatal("%s: out of sequence reply: my id %u theirs %u",
1581 __func__, muxclient_request_id, rid);
1582 switch (type) {
1583 case MUX_S_OK:
1584 break;
1585 case MUX_S_PERMISSION_DENIED:
1586 e = buffer_get_string(&m, NULL);
1587 fatal("Master refused termination request: %s", e);
1588 case MUX_S_FAILURE:
1589 e = buffer_get_string(&m, NULL);
1590 fatal("%s: termination request failed: %s", __func__, e);
1591 default:
1592 fatal("%s: unexpected response from master 0x%08x",
1593 __func__, type);
1594 }
1595 buffer_free(&m);
1596 muxclient_request_id++;
1597}
1598
1599static int
Damien Millerf6dff7c2011-09-22 21:38:52 +10001600mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd)
Damien Millere1537f92010-01-26 13:26:22 +11001601{
1602 Buffer m;
1603 char *e, *fwd_desc;
1604 u_int type, rid;
1605
1606 fwd_desc = format_forward(ftype, fwd);
Damien Millerf6dff7c2011-09-22 21:38:52 +10001607 debug("Requesting %s %s",
1608 cancel_flag ? "cancellation of" : "forwarding of", fwd_desc);
Damien Millere1537f92010-01-26 13:26:22 +11001609 xfree(fwd_desc);
1610
1611 buffer_init(&m);
Damien Millerf6dff7c2011-09-22 21:38:52 +10001612 buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD);
Damien Millere1537f92010-01-26 13:26:22 +11001613 buffer_put_int(&m, muxclient_request_id);
1614 buffer_put_int(&m, ftype);
1615 buffer_put_cstring(&m,
1616 fwd->listen_host == NULL ? "" : fwd->listen_host);
1617 buffer_put_int(&m, fwd->listen_port);
1618 buffer_put_cstring(&m,
1619 fwd->connect_host == NULL ? "" : fwd->connect_host);
1620 buffer_put_int(&m, fwd->connect_port);
1621
1622 if (mux_client_write_packet(fd, &m) != 0)
1623 fatal("%s: write packet: %s", __func__, strerror(errno));
1624
1625 buffer_clear(&m);
1626
1627 /* Read their reply */
1628 if (mux_client_read_packet(fd, &m) != 0) {
1629 buffer_free(&m);
1630 return -1;
1631 }
1632
1633 type = buffer_get_int(&m);
1634 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1635 fatal("%s: out of sequence reply: my id %u theirs %u",
1636 __func__, muxclient_request_id, rid);
1637 switch (type) {
1638 case MUX_S_OK:
1639 break;
Damien Miller388f6fc2010-05-21 14:57:35 +10001640 case MUX_S_REMOTE_PORT:
Damien Millerf6dff7c2011-09-22 21:38:52 +10001641 if (cancel_flag)
1642 fatal("%s: got MUX_S_REMOTE_PORT for cancel", __func__);
Damien Miller388f6fc2010-05-21 14:57:35 +10001643 fwd->allocated_port = buffer_get_int(&m);
1644 logit("Allocated port %u for remote forward to %s:%d",
1645 fwd->allocated_port,
1646 fwd->connect_host ? fwd->connect_host : "",
1647 fwd->connect_port);
1648 if (muxclient_command == SSHMUX_COMMAND_FORWARD)
1649 fprintf(stdout, "%u\n", fwd->allocated_port);
1650 break;
Damien Millere1537f92010-01-26 13:26:22 +11001651 case MUX_S_PERMISSION_DENIED:
1652 e = buffer_get_string(&m, NULL);
1653 buffer_free(&m);
1654 error("Master refused forwarding request: %s", e);
1655 return -1;
1656 case MUX_S_FAILURE:
1657 e = buffer_get_string(&m, NULL);
1658 buffer_free(&m);
Damien Miller445c9a52011-01-14 12:01:29 +11001659 error("%s: forwarding request failed: %s", __func__, e);
Damien Millere1537f92010-01-26 13:26:22 +11001660 return -1;
1661 default:
1662 fatal("%s: unexpected response from master 0x%08x",
1663 __func__, type);
1664 }
1665 buffer_free(&m);
1666
1667 muxclient_request_id++;
1668 return 0;
1669}
1670
1671static int
Damien Millerf6dff7c2011-09-22 21:38:52 +10001672mux_client_forwards(int fd, int cancel_flag)
Damien Millere1537f92010-01-26 13:26:22 +11001673{
Damien Millerf6dff7c2011-09-22 21:38:52 +10001674 int i, ret = 0;
Damien Millere1537f92010-01-26 13:26:22 +11001675
Damien Millerf6dff7c2011-09-22 21:38:52 +10001676 debug3("%s: %s forwardings: %d local, %d remote", __func__,
1677 cancel_flag ? "cancel" : "request",
Damien Millere1537f92010-01-26 13:26:22 +11001678 options.num_local_forwards, options.num_remote_forwards);
1679
1680 /* XXX ExitOnForwardingFailure */
1681 for (i = 0; i < options.num_local_forwards; i++) {
Damien Millerf6dff7c2011-09-22 21:38:52 +10001682 if (mux_client_forward(fd, cancel_flag,
Damien Millere1537f92010-01-26 13:26:22 +11001683 options.local_forwards[i].connect_port == 0 ?
1684 MUX_FWD_DYNAMIC : MUX_FWD_LOCAL,
1685 options.local_forwards + i) != 0)
Damien Millerf6dff7c2011-09-22 21:38:52 +10001686 ret = -1;
Damien Millere1537f92010-01-26 13:26:22 +11001687 }
1688 for (i = 0; i < options.num_remote_forwards; i++) {
Damien Millerf6dff7c2011-09-22 21:38:52 +10001689 if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE,
Damien Millere1537f92010-01-26 13:26:22 +11001690 options.remote_forwards + i) != 0)
Damien Millerf6dff7c2011-09-22 21:38:52 +10001691 ret = -1;
Damien Millere1537f92010-01-26 13:26:22 +11001692 }
Damien Millerf6dff7c2011-09-22 21:38:52 +10001693 return ret;
Damien Millere1537f92010-01-26 13:26:22 +11001694}
1695
1696static int
1697mux_client_request_session(int fd)
1698{
1699 Buffer m;
1700 char *e, *term;
1701 u_int i, rid, sid, esid, exitval, type, exitval_seen;
1702 extern char **environ;
Damien Miller555f3b82011-05-15 08:48:05 +10001703 int devnull, rawmode;
Damien Millere1537f92010-01-26 13:26:22 +11001704
1705 debug3("%s: entering", __func__);
1706
1707 if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
1708 error("%s: master alive request failed", __func__);
1709 return -1;
1710 }
1711
1712 signal(SIGPIPE, SIG_IGN);
1713
1714 if (stdin_null_flag) {
1715 if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
1716 fatal("open(/dev/null): %s", strerror(errno));
1717 if (dup2(devnull, STDIN_FILENO) == -1)
1718 fatal("dup2: %s", strerror(errno));
1719 if (devnull > STDERR_FILENO)
1720 close(devnull);
1721 }
1722
1723 term = getenv("TERM");
1724
1725 buffer_init(&m);
1726 buffer_put_int(&m, MUX_C_NEW_SESSION);
1727 buffer_put_int(&m, muxclient_request_id);
1728 buffer_put_cstring(&m, ""); /* reserved */
1729 buffer_put_int(&m, tty_flag);
1730 buffer_put_int(&m, options.forward_x11);
1731 buffer_put_int(&m, options.forward_agent);
1732 buffer_put_int(&m, subsystem_flag);
1733 buffer_put_int(&m, options.escape_char == SSH_ESCAPECHAR_NONE ?
1734 0xffffffff : (u_int)options.escape_char);
1735 buffer_put_cstring(&m, term == NULL ? "" : term);
1736 buffer_put_string(&m, buffer_ptr(&command), buffer_len(&command));
1737
1738 if (options.num_send_env > 0 && environ != NULL) {
1739 /* Pass environment */
1740 for (i = 0; environ[i] != NULL; i++) {
1741 if (env_permitted(environ[i])) {
1742 buffer_put_cstring(&m, environ[i]);
1743 }
1744 }
1745 }
1746
1747 if (mux_client_write_packet(fd, &m) != 0)
1748 fatal("%s: write packet: %s", __func__, strerror(errno));
1749
1750 /* Send the stdio file descriptors */
1751 if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
1752 mm_send_fd(fd, STDOUT_FILENO) == -1 ||
1753 mm_send_fd(fd, STDERR_FILENO) == -1)
1754 fatal("%s: send fds failed", __func__);
1755
1756 debug3("%s: session request sent", __func__);
1757
1758 /* Read their reply */
1759 buffer_clear(&m);
1760 if (mux_client_read_packet(fd, &m) != 0) {
1761 error("%s: read from master failed: %s",
1762 __func__, strerror(errno));
1763 buffer_free(&m);
1764 return -1;
1765 }
1766
1767 type = buffer_get_int(&m);
1768 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1769 fatal("%s: out of sequence reply: my id %u theirs %u",
1770 __func__, muxclient_request_id, rid);
1771 switch (type) {
1772 case MUX_S_SESSION_OPENED:
1773 sid = buffer_get_int(&m);
1774 debug("%s: master session id: %u", __func__, sid);
1775 break;
1776 case MUX_S_PERMISSION_DENIED:
1777 e = buffer_get_string(&m, NULL);
1778 buffer_free(&m);
Damien Miller445c9a52011-01-14 12:01:29 +11001779 error("Master refused session request: %s", e);
Damien Millere1537f92010-01-26 13:26:22 +11001780 return -1;
1781 case MUX_S_FAILURE:
1782 e = buffer_get_string(&m, NULL);
1783 buffer_free(&m);
Damien Miller445c9a52011-01-14 12:01:29 +11001784 error("%s: session request failed: %s", __func__, e);
Damien Millere1537f92010-01-26 13:26:22 +11001785 return -1;
1786 default:
1787 buffer_free(&m);
1788 error("%s: unexpected response from master 0x%08x",
1789 __func__, type);
1790 return -1;
1791 }
1792 muxclient_request_id++;
1793
1794 signal(SIGHUP, control_client_sighandler);
1795 signal(SIGINT, control_client_sighandler);
1796 signal(SIGTERM, control_client_sighandler);
1797 signal(SIGWINCH, control_client_sigrelay);
1798
Damien Miller555f3b82011-05-15 08:48:05 +10001799 rawmode = tty_flag;
Damien Millere1537f92010-01-26 13:26:22 +11001800 if (tty_flag)
Damien Miller21771e22011-05-15 08:45:50 +10001801 enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
Damien Millere1537f92010-01-26 13:26:22 +11001802
1803 /*
1804 * Stick around until the controlee closes the client_fd.
1805 * Before it does, it is expected to write an exit message.
1806 * This process must read the value and wait for the closure of
1807 * the client_fd; if this one closes early, the multiplex master will
1808 * terminate early too (possibly losing data).
1809 */
1810 for (exitval = 255, exitval_seen = 0;;) {
1811 buffer_clear(&m);
1812 if (mux_client_read_packet(fd, &m) != 0)
1813 break;
1814 type = buffer_get_int(&m);
Damien Miller555f3b82011-05-15 08:48:05 +10001815 switch (type) {
1816 case MUX_S_TTY_ALLOC_FAIL:
1817 if ((esid = buffer_get_int(&m)) != sid)
1818 fatal("%s: tty alloc fail on unknown session: "
1819 "my id %u theirs %u",
1820 __func__, sid, esid);
1821 leave_raw_mode(options.request_tty ==
1822 REQUEST_TTY_FORCE);
1823 rawmode = 0;
1824 continue;
1825 case MUX_S_EXIT_MESSAGE:
1826 if ((esid = buffer_get_int(&m)) != sid)
1827 fatal("%s: exit on unknown session: "
1828 "my id %u theirs %u",
1829 __func__, sid, esid);
1830 if (exitval_seen)
1831 fatal("%s: exitval sent twice", __func__);
1832 exitval = buffer_get_int(&m);
1833 exitval_seen = 1;
1834 continue;
1835 default:
Damien Millere1537f92010-01-26 13:26:22 +11001836 e = buffer_get_string(&m, NULL);
1837 fatal("%s: master returned error: %s", __func__, e);
1838 }
Damien Millere1537f92010-01-26 13:26:22 +11001839 }
1840
1841 close(fd);
Damien Miller555f3b82011-05-15 08:48:05 +10001842 if (rawmode)
1843 leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
Damien Millere1537f92010-01-26 13:26:22 +11001844
1845 if (muxclient_terminate) {
1846 debug2("Exiting on signal %d", muxclient_terminate);
1847 exitval = 255;
1848 } else if (!exitval_seen) {
1849 debug2("Control master terminated unexpectedly");
1850 exitval = 255;
1851 } else
1852 debug2("Received exit status from master %d", exitval);
1853
1854 if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
1855 fprintf(stderr, "Shared connection to %s closed.\r\n", host);
1856
1857 exit(exitval);
1858}
1859
1860static int
1861mux_client_request_stdio_fwd(int fd)
1862{
1863 Buffer m;
1864 char *e;
1865 u_int type, rid, sid;
1866 int devnull;
1867
1868 debug3("%s: entering", __func__);
1869
1870 if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
1871 error("%s: master alive request failed", __func__);
1872 return -1;
1873 }
1874
1875 signal(SIGPIPE, SIG_IGN);
1876
1877 if (stdin_null_flag) {
1878 if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
1879 fatal("open(/dev/null): %s", strerror(errno));
1880 if (dup2(devnull, STDIN_FILENO) == -1)
1881 fatal("dup2: %s", strerror(errno));
1882 if (devnull > STDERR_FILENO)
1883 close(devnull);
1884 }
1885
1886 buffer_init(&m);
1887 buffer_put_int(&m, MUX_C_NEW_STDIO_FWD);
1888 buffer_put_int(&m, muxclient_request_id);
1889 buffer_put_cstring(&m, ""); /* reserved */
1890 buffer_put_cstring(&m, stdio_forward_host);
1891 buffer_put_int(&m, stdio_forward_port);
1892
1893 if (mux_client_write_packet(fd, &m) != 0)
1894 fatal("%s: write packet: %s", __func__, strerror(errno));
1895
1896 /* Send the stdio file descriptors */
1897 if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
1898 mm_send_fd(fd, STDOUT_FILENO) == -1)
1899 fatal("%s: send fds failed", __func__);
1900
1901 debug3("%s: stdio forward request sent", __func__);
1902
1903 /* Read their reply */
1904 buffer_clear(&m);
1905
1906 if (mux_client_read_packet(fd, &m) != 0) {
1907 error("%s: read from master failed: %s",
1908 __func__, strerror(errno));
1909 buffer_free(&m);
1910 return -1;
1911 }
1912
1913 type = buffer_get_int(&m);
1914 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1915 fatal("%s: out of sequence reply: my id %u theirs %u",
1916 __func__, muxclient_request_id, rid);
1917 switch (type) {
1918 case MUX_S_SESSION_OPENED:
1919 sid = buffer_get_int(&m);
1920 debug("%s: master session id: %u", __func__, sid);
1921 break;
1922 case MUX_S_PERMISSION_DENIED:
1923 e = buffer_get_string(&m, NULL);
1924 buffer_free(&m);
Damien Miller445c9a52011-01-14 12:01:29 +11001925 fatal("Master refused stdio forwarding request: %s", e);
Damien Millere1537f92010-01-26 13:26:22 +11001926 case MUX_S_FAILURE:
1927 e = buffer_get_string(&m, NULL);
1928 buffer_free(&m);
1929 fatal("%s: stdio forwarding request failed: %s", __func__, e);
1930 default:
1931 buffer_free(&m);
1932 error("%s: unexpected response from master 0x%08x",
1933 __func__, type);
1934 return -1;
1935 }
1936 muxclient_request_id++;
1937
1938 signal(SIGHUP, control_client_sighandler);
1939 signal(SIGINT, control_client_sighandler);
1940 signal(SIGTERM, control_client_sighandler);
1941 signal(SIGWINCH, control_client_sigrelay);
1942
1943 /*
1944 * Stick around until the controlee closes the client_fd.
1945 */
1946 buffer_clear(&m);
1947 if (mux_client_read_packet(fd, &m) != 0) {
1948 if (errno == EPIPE ||
1949 (errno == EINTR && muxclient_terminate != 0))
1950 return 0;
1951 fatal("%s: mux_client_read_packet: %s",
1952 __func__, strerror(errno));
1953 }
1954 fatal("%s: master returned unexpected message %u", __func__, type);
Damien Millerb1cbfa22008-05-19 16:00:08 +10001955}
1956
Damien Miller6c3eec72011-05-05 14:16:22 +10001957static void
1958mux_client_request_stop_listening(int fd)
1959{
1960 Buffer m;
1961 char *e;
1962 u_int type, rid;
1963
1964 debug3("%s: entering", __func__);
1965
1966 buffer_init(&m);
1967 buffer_put_int(&m, MUX_C_STOP_LISTENING);
1968 buffer_put_int(&m, muxclient_request_id);
1969
1970 if (mux_client_write_packet(fd, &m) != 0)
1971 fatal("%s: write packet: %s", __func__, strerror(errno));
1972
1973 buffer_clear(&m);
1974
1975 /* Read their reply */
1976 if (mux_client_read_packet(fd, &m) != 0)
1977 fatal("%s: read from master failed: %s",
1978 __func__, strerror(errno));
1979
1980 type = buffer_get_int(&m);
1981 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
1982 fatal("%s: out of sequence reply: my id %u theirs %u",
1983 __func__, muxclient_request_id, rid);
1984 switch (type) {
1985 case MUX_S_OK:
1986 break;
1987 case MUX_S_PERMISSION_DENIED:
1988 e = buffer_get_string(&m, NULL);
1989 fatal("Master refused stop listening request: %s", e);
1990 case MUX_S_FAILURE:
1991 e = buffer_get_string(&m, NULL);
1992 fatal("%s: stop listening request failed: %s", __func__, e);
1993 default:
1994 fatal("%s: unexpected response from master 0x%08x",
1995 __func__, type);
1996 }
1997 buffer_free(&m);
1998 muxclient_request_id++;
1999}
2000
Damien Millerb1cbfa22008-05-19 16:00:08 +10002001/* Multiplex client main loop. */
2002void
2003muxclient(const char *path)
2004{
2005 struct sockaddr_un addr;
Damien Millere1537f92010-01-26 13:26:22 +11002006 socklen_t sun_len;
2007 int sock;
2008 u_int pid;
Damien Millerb1cbfa22008-05-19 16:00:08 +10002009
Damien Millere1537f92010-01-26 13:26:22 +11002010 if (muxclient_command == 0) {
2011 if (stdio_forward_host != NULL)
2012 muxclient_command = SSHMUX_COMMAND_STDIO_FWD;
2013 else
2014 muxclient_command = SSHMUX_COMMAND_OPEN;
2015 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10002016
2017 switch (options.control_master) {
2018 case SSHCTL_MASTER_AUTO:
2019 case SSHCTL_MASTER_AUTO_ASK:
2020 debug("auto-mux: Trying existing master");
2021 /* FALLTHROUGH */
2022 case SSHCTL_MASTER_NO:
2023 break;
2024 default:
2025 return;
2026 }
2027
2028 memset(&addr, '\0', sizeof(addr));
2029 addr.sun_family = AF_UNIX;
Damien Millere1537f92010-01-26 13:26:22 +11002030 sun_len = offsetof(struct sockaddr_un, sun_path) +
Damien Millerb1cbfa22008-05-19 16:00:08 +10002031 strlen(path) + 1;
2032
2033 if (strlcpy(addr.sun_path, path,
2034 sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
2035 fatal("ControlPath too long");
2036
2037 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
2038 fatal("%s socket(): %s", __func__, strerror(errno));
2039
Damien Millere1537f92010-01-26 13:26:22 +11002040 if (connect(sock, (struct sockaddr *)&addr, sun_len) == -1) {
2041 switch (muxclient_command) {
2042 case SSHMUX_COMMAND_OPEN:
2043 case SSHMUX_COMMAND_STDIO_FWD:
2044 break;
2045 default:
Damien Millerb1cbfa22008-05-19 16:00:08 +10002046 fatal("Control socket connect(%.100s): %s", path,
2047 strerror(errno));
2048 }
Damien Miller603134e2010-09-24 22:07:55 +10002049 if (errno == ECONNREFUSED &&
2050 options.control_master != SSHCTL_MASTER_NO) {
2051 debug("Stale control socket %.100s, unlinking", path);
2052 unlink(path);
2053 } else if (errno == ENOENT) {
Damien Millerb1cbfa22008-05-19 16:00:08 +10002054 debug("Control socket \"%.100s\" does not exist", path);
Damien Miller603134e2010-09-24 22:07:55 +10002055 } else {
Damien Millerb1cbfa22008-05-19 16:00:08 +10002056 error("Control socket connect(%.100s): %s", path,
2057 strerror(errno));
2058 }
2059 close(sock);
2060 return;
2061 }
Damien Millere1537f92010-01-26 13:26:22 +11002062 set_nonblock(sock);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002063
Damien Millere1537f92010-01-26 13:26:22 +11002064 if (mux_client_hello_exchange(sock) != 0) {
2065 error("%s: master hello exchange failed", __func__);
Darren Tuckerca19bfe2008-06-13 10:24:03 +10002066 close(sock);
Darren Tuckerca19bfe2008-06-13 10:24:03 +10002067 return;
2068 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10002069
2070 switch (muxclient_command) {
2071 case SSHMUX_COMMAND_ALIVE_CHECK:
Damien Millere1537f92010-01-26 13:26:22 +11002072 if ((pid = mux_client_request_alive(sock)) == 0)
2073 fatal("%s: master alive check failed", __func__);
2074 fprintf(stderr, "Master running (pid=%d)\r\n", pid);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002075 exit(0);
2076 case SSHMUX_COMMAND_TERMINATE:
Damien Millere1537f92010-01-26 13:26:22 +11002077 mux_client_request_terminate(sock);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002078 fprintf(stderr, "Exit request sent.\r\n");
2079 exit(0);
Damien Miller388f6fc2010-05-21 14:57:35 +10002080 case SSHMUX_COMMAND_FORWARD:
Damien Millerf6dff7c2011-09-22 21:38:52 +10002081 if (mux_client_forwards(sock, 0) != 0)
Damien Miller388f6fc2010-05-21 14:57:35 +10002082 fatal("%s: master forward request failed", __func__);
2083 exit(0);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002084 case SSHMUX_COMMAND_OPEN:
Damien Millerf6dff7c2011-09-22 21:38:52 +10002085 if (mux_client_forwards(sock, 0) != 0) {
Damien Millere1537f92010-01-26 13:26:22 +11002086 error("%s: master forward request failed", __func__);
2087 return;
Darren Tucker2fb66ca2008-06-13 04:49:33 +10002088 }
Damien Millere1537f92010-01-26 13:26:22 +11002089 mux_client_request_session(sock);
2090 return;
2091 case SSHMUX_COMMAND_STDIO_FWD:
2092 mux_client_request_stdio_fwd(sock);
2093 exit(0);
Damien Miller6c3eec72011-05-05 14:16:22 +10002094 case SSHMUX_COMMAND_STOP:
2095 mux_client_request_stop_listening(sock);
2096 fprintf(stderr, "Stop listening request sent.\r\n");
2097 exit(0);
Damien Millerf6dff7c2011-09-22 21:38:52 +10002098 case SSHMUX_COMMAND_CANCEL_FWD:
2099 if (mux_client_forwards(sock, 1) != 0)
2100 error("%s: master cancel forward request failed",
2101 __func__);
2102 exit(0);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002103 default:
Darren Tucker2fb66ca2008-06-13 04:49:33 +10002104 fatal("unrecognised muxclient_command %d", muxclient_command);
Damien Millerb1cbfa22008-05-19 16:00:08 +10002105 }
Damien Millerb1cbfa22008-05-19 16:00:08 +10002106}