summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2005-07-06 09:44:19 +1000
committerDamien Miller <djm@mindrot.org>2005-07-06 09:44:19 +1000
commit1339002e8b05d89b10767849d9ee9be55e460f4c (patch)
tree58e307b74579313f31732dfdf21f756d6a051ce9
parenta7270309fc5e95b29c91d0190b13ef5a9b1df339 (diff)
- djm@cvs.openbsd.org 2005/07/04 00:58:43
[channels.c clientloop.c clientloop.h misc.c misc.h ssh.c ssh_config.5] implement support for X11 and agent forwarding over multiplex slave connections. Because of protocol limitations, the slave connections inherit the master's DISPLAY and SSH_AUTH_SOCK rather than distinctly forwarding their own. ok dtucker@ "put it in" deraadt@
-rw-r--r--ChangeLog9
-rw-r--r--channels.c61
-rw-r--r--clientloop.c35
-rw-r--r--clientloop.h7
-rw-r--r--misc.c19
-rw-r--r--misc.h3
-rw-r--r--ssh.c45
-rw-r--r--ssh_config.58
8 files changed, 128 insertions, 59 deletions
diff --git a/ChangeLog b/ChangeLog
index 85d4e91c9..58607022a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,13 @@
3 - markus@cvs.openbsd.org 2005/07/01 13:19:47 3 - markus@cvs.openbsd.org 2005/07/01 13:19:47
4 [channels.c] 4 [channels.c]
5 don't free() if getaddrinfo() fails; report mpech@ 5 don't free() if getaddrinfo() fails; report mpech@
6 - djm@cvs.openbsd.org 2005/07/04 00:58:43
7 [channels.c clientloop.c clientloop.h misc.c misc.h ssh.c ssh_config.5]
8 implement support for X11 and agent forwarding over multiplex slave
9 connections. Because of protocol limitations, the slave connections inherit
10 the master's DISPLAY and SSH_AUTH_SOCK rather than distinctly forwarding
11 their own.
12 ok dtucker@ "put it in" deraadt@
6 13
720050626 1420050626
8 - (djm) OpenBSD CVS Sync 15 - (djm) OpenBSD CVS Sync
@@ -2769,4 +2776,4 @@
2769 - (djm) Trim deprecated options from INSTALL. Mention UsePAM 2776 - (djm) Trim deprecated options from INSTALL. Mention UsePAM
2770 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu 2777 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
2771 2778
2772$Id: ChangeLog,v 1.3832 2005/07/05 23:36:05 djm Exp $ 2779$Id: ChangeLog,v 1.3833 2005/07/05 23:44:19 djm Exp $
diff --git a/channels.c b/channels.c
index b58902328..14ff166ae 100644
--- a/channels.c
+++ b/channels.c
@@ -39,7 +39,7 @@
39 */ 39 */
40 40
41#include "includes.h" 41#include "includes.h"
42RCSID("$OpenBSD: channels.c,v 1.218 2005/07/01 13:19:47 markus Exp $"); 42RCSID("$OpenBSD: channels.c,v 1.219 2005/07/04 00:58:42 djm Exp $");
43 43
44#include "ssh.h" 44#include "ssh.h"
45#include "ssh1.h" 45#include "ssh1.h"
@@ -111,6 +111,9 @@ static int all_opens_permitted = 0;
111/* Maximum number of fake X11 displays to try. */ 111/* Maximum number of fake X11 displays to try. */
112#define MAX_DISPLAYS 1000 112#define MAX_DISPLAYS 1000
113 113
114/* Saved X11 local (client) display. */
115static char *x11_saved_display = NULL;
116
114/* Saved X11 authentication protocol name. */ 117/* Saved X11 authentication protocol name. */
115static char *x11_saved_proto = NULL; 118static char *x11_saved_proto = NULL;
116 119
@@ -2955,12 +2958,18 @@ x11_request_forwarding_with_spoofing(int client_session_id, const char *disp,
2955 const char *proto, const char *data) 2958 const char *proto, const char *data)
2956{ 2959{
2957 u_int data_len = (u_int) strlen(data) / 2; 2960 u_int data_len = (u_int) strlen(data) / 2;
2958 u_int i, value, len; 2961 u_int i, value;
2959 char *new_data; 2962 char *new_data;
2960 int screen_number; 2963 int screen_number;
2961 const char *cp; 2964 const char *cp;
2962 u_int32_t rnd = 0; 2965 u_int32_t rnd = 0;
2963 2966
2967 if (x11_saved_display && strcmp(disp, x11_saved_display) != 0) {
2968 error("x11_request_forwarding_with_spoofing: different "
2969 "$DISPLAY already forwarded");
2970 return;
2971 }
2972
2964 cp = disp; 2973 cp = disp;
2965 if (disp) 2974 if (disp)
2966 cp = strchr(disp, ':'); 2975 cp = strchr(disp, ':');
@@ -2971,33 +2980,31 @@ x11_request_forwarding_with_spoofing(int client_session_id, const char *disp,
2971 else 2980 else
2972 screen_number = 0; 2981 screen_number = 0;
2973 2982
2974 /* Save protocol name. */ 2983 if (x11_saved_proto == NULL) {
2975 x11_saved_proto = xstrdup(proto); 2984 /* Save protocol name. */
2976 2985 x11_saved_proto = xstrdup(proto);
2977 /* 2986 /*
2978 * Extract real authentication data and generate fake data of the 2987 * Extract real authentication data and generate fake data
2979 * same length. 2988 * of the same length.
2980 */ 2989 */
2981 x11_saved_data = xmalloc(data_len); 2990 x11_saved_data = xmalloc(data_len);
2982 x11_fake_data = xmalloc(data_len); 2991 x11_fake_data = xmalloc(data_len);
2983 for (i = 0; i < data_len; i++) { 2992 for (i = 0; i < data_len; i++) {
2984 if (sscanf(data + 2 * i, "%2x", &value) != 1) 2993 if (sscanf(data + 2 * i, "%2x", &value) != 1)
2985 fatal("x11_request_forwarding: bad authentication data: %.100s", data); 2994 fatal("x11_request_forwarding: bad "
2986 if (i % 4 == 0) 2995 "authentication data: %.100s", data);
2987 rnd = arc4random(); 2996 if (i % 4 == 0)
2988 x11_saved_data[i] = value; 2997 rnd = arc4random();
2989 x11_fake_data[i] = rnd & 0xff; 2998 x11_saved_data[i] = value;
2990 rnd >>= 8; 2999 x11_fake_data[i] = rnd & 0xff;
2991 } 3000 rnd >>= 8;
2992 x11_saved_data_len = data_len; 3001 }
2993 x11_fake_data_len = data_len; 3002 x11_saved_data_len = data_len;
3003 x11_fake_data_len = data_len;
3004 }
2994 3005
2995 /* Convert the fake data into hex. */ 3006 /* Convert the fake data into hex. */
2996 len = 2 * data_len + 1; 3007 new_data = tohex(x11_fake_data, data_len);
2997 new_data = xmalloc(len);
2998 for (i = 0; i < data_len; i++)
2999 snprintf(new_data + 2 * i, len - 2 * i,
3000 "%02x", (u_char) x11_fake_data[i]);
3001 3008
3002 /* Send the request packet. */ 3009 /* Send the request packet. */
3003 if (compat20) { 3010 if (compat20) {
diff --git a/clientloop.c b/clientloop.c
index a030cf6e4..9611a5e3e 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -59,7 +59,7 @@
59 */ 59 */
60 60
61#include "includes.h" 61#include "includes.h"
62RCSID("$OpenBSD: clientloop.c,v 1.139 2005/06/17 02:44:32 djm Exp $"); 62RCSID("$OpenBSD: clientloop.c,v 1.140 2005/07/04 00:58:43 djm Exp $");
63 63
64#include "ssh.h" 64#include "ssh.h"
65#include "ssh1.h" 65#include "ssh1.h"
@@ -140,6 +140,8 @@ int session_ident = -1;
140struct confirm_ctx { 140struct confirm_ctx {
141 int want_tty; 141 int want_tty;
142 int want_subsys; 142 int want_subsys;
143 int want_x_fwd;
144 int want_agent_fwd;
143 Buffer cmd; 145 Buffer cmd;
144 char *term; 146 char *term;
145 struct termios tio; 147 struct termios tio;
@@ -631,6 +633,7 @@ static void
631client_extra_session2_setup(int id, void *arg) 633client_extra_session2_setup(int id, void *arg)
632{ 634{
633 struct confirm_ctx *cctx = arg; 635 struct confirm_ctx *cctx = arg;
636 const char *display;
634 Channel *c; 637 Channel *c;
635 int i; 638 int i;
636 639
@@ -639,6 +642,24 @@ client_extra_session2_setup(int id, void *arg)
639 if ((c = channel_lookup(id)) == NULL) 642 if ((c = channel_lookup(id)) == NULL)
640 fatal("%s: no channel for id %d", __func__, id); 643 fatal("%s: no channel for id %d", __func__, id);
641 644
645 display = getenv("DISPLAY");
646 if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
647 char *proto, *data;
648 /* Get reasonable local authentication information. */
649 client_x11_get_proto(display, options.xauth_location,
650 options.forward_x11_trusted, &proto, &data);
651 /* Request forwarding with authentication spoofing. */
652 debug("Requesting X11 forwarding with authentication spoofing.");
653 x11_request_forwarding_with_spoofing(id, display, proto, data);
654 /* XXX wait for reply */
655 }
656
657 if (cctx->want_agent_fwd && options.forward_agent) {
658 debug("Requesting authentication agent forwarding.");
659 channel_request_start(id, "auth-agent-req@openssh.com", 0);
660 packet_send();
661 }
662
642 client_session2_setup(id, cctx->want_tty, cctx->want_subsys, 663 client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
643 cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env, 664 cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env,
644 client_subsystem_reply); 665 client_subsystem_reply);
@@ -704,7 +725,7 @@ client_process_control(fd_set * readset)
704 buffer_free(&m); 725 buffer_free(&m);
705 return; 726 return;
706 } 727 }
707 if ((ver = buffer_get_char(&m)) != 1) { 728 if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
708 error("%s: wrong client version %d", __func__, ver); 729 error("%s: wrong client version %d", __func__, ver);
709 buffer_free(&m); 730 buffer_free(&m);
710 close(client_fd); 731 close(client_fd);
@@ -738,7 +759,7 @@ client_process_control(fd_set * readset)
738 buffer_clear(&m); 759 buffer_clear(&m);
739 buffer_put_int(&m, allowed); 760 buffer_put_int(&m, allowed);
740 buffer_put_int(&m, getpid()); 761 buffer_put_int(&m, getpid());
741 if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { 762 if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
742 error("%s: client msg_send failed", __func__); 763 error("%s: client msg_send failed", __func__);
743 close(client_fd); 764 close(client_fd);
744 buffer_free(&m); 765 buffer_free(&m);
@@ -758,7 +779,7 @@ client_process_control(fd_set * readset)
758 buffer_clear(&m); 779 buffer_clear(&m);
759 buffer_put_int(&m, allowed); 780 buffer_put_int(&m, allowed);
760 buffer_put_int(&m, getpid()); 781 buffer_put_int(&m, getpid());
761 if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { 782 if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
762 error("%s: client msg_send failed", __func__); 783 error("%s: client msg_send failed", __func__);
763 close(client_fd); 784 close(client_fd);
764 buffer_free(&m); 785 buffer_free(&m);
@@ -779,7 +800,7 @@ client_process_control(fd_set * readset)
779 buffer_free(&m); 800 buffer_free(&m);
780 return; 801 return;
781 } 802 }
782 if ((ver = buffer_get_char(&m)) != 1) { 803 if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
783 error("%s: wrong client version %d", __func__, ver); 804 error("%s: wrong client version %d", __func__, ver);
784 buffer_free(&m); 805 buffer_free(&m);
785 close(client_fd); 806 close(client_fd);
@@ -790,6 +811,8 @@ client_process_control(fd_set * readset)
790 memset(cctx, 0, sizeof(*cctx)); 811 memset(cctx, 0, sizeof(*cctx));
791 cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0; 812 cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0;
792 cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0; 813 cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0;
814 cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
815 cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
793 cctx->term = buffer_get_string(&m, &len); 816 cctx->term = buffer_get_string(&m, &len);
794 817
795 cmd = buffer_get_string(&m, &len); 818 cmd = buffer_get_string(&m, &len);
@@ -823,7 +846,7 @@ client_process_control(fd_set * readset)
823 846
824 /* This roundtrip is just for synchronisation of ttymodes */ 847 /* This roundtrip is just for synchronisation of ttymodes */
825 buffer_clear(&m); 848 buffer_clear(&m);
826 if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { 849 if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
827 error("%s: client msg_send failed", __func__); 850 error("%s: client msg_send failed", __func__);
828 close(client_fd); 851 close(client_fd);
829 close(new_fd[0]); 852 close(new_fd[0]);
diff --git a/clientloop.h b/clientloop.h
index 71c61b5d2..aed2d918b 100644
--- a/clientloop.h
+++ b/clientloop.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.h,v 1.13 2005/06/16 03:38:36 djm Exp $ */ 1/* $OpenBSD: clientloop.h,v 1.14 2005/07/04 00:58:43 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -43,6 +43,9 @@ void client_global_request_reply_fwd(int, u_int32_t, void *);
43void client_session2_setup(int, int, int, const char *, struct termios *, 43void client_session2_setup(int, int, int, const char *, struct termios *,
44 int, Buffer *, char **, dispatch_fn *); 44 int, Buffer *, char **, dispatch_fn *);
45 45
46/* Multiplexing protocol version */
47#define SSHMUX_VER 1
48
46/* Multiplexing control protocol flags */ 49/* Multiplexing control protocol flags */
47#define SSHMUX_COMMAND_OPEN 1 /* Open new connection */ 50#define SSHMUX_COMMAND_OPEN 1 /* Open new connection */
48#define SSHMUX_COMMAND_ALIVE_CHECK 2 /* Check master is alive */ 51#define SSHMUX_COMMAND_ALIVE_CHECK 2 /* Check master is alive */
@@ -50,3 +53,5 @@ void client_session2_setup(int, int, int, const char *, struct termios *,
50 53
51#define SSHMUX_FLAG_TTY (1) /* Request tty on open */ 54#define SSHMUX_FLAG_TTY (1) /* Request tty on open */
52#define SSHMUX_FLAG_SUBSYS (1<<1) /* Subsystem request on open */ 55#define SSHMUX_FLAG_SUBSYS (1<<1) /* Subsystem request on open */
56#define SSHMUX_FLAG_X11_FWD (1<<2) /* Request X11 forwarding */
57#define SSHMUX_FLAG_AGENT_FWD (1<<3) /* Request agent forwarding */
diff --git a/misc.c b/misc.c
index c5ca0ce38..808b7ba27 100644
--- a/misc.c
+++ b/misc.c
@@ -24,7 +24,7 @@
24 */ 24 */
25 25
26#include "includes.h" 26#include "includes.h"
27RCSID("$OpenBSD: misc.c,v 1.32 2005/06/17 02:44:32 djm Exp $"); 27RCSID("$OpenBSD: misc.c,v 1.33 2005/07/04 00:58:43 djm Exp $");
28 28
29#include "misc.h" 29#include "misc.h"
30#include "log.h" 30#include "log.h"
@@ -506,3 +506,20 @@ read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
506 } 506 }
507 return -1; 507 return -1;
508} 508}
509
510char *
511tohex(const u_char *d, u_int l)
512{
513 char b[3], *r;
514 u_int i, hl;
515
516 hl = l * 2 + 1;
517 r = xmalloc(hl);
518 *r = '\0';
519 for (i = 0; i < l; i++) {
520 snprintf(b, sizeof(b), "%02x", d[i]);
521 strlcat(r, b, hl);
522 }
523 return (r);
524}
525
diff --git a/misc.h b/misc.h
index a85fcd134..92848b28e 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: misc.h,v 1.23 2005/06/06 11:20:36 djm Exp $ */ 1/* $OpenBSD: misc.h,v 1.24 2005/07/04 00:58:43 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -26,6 +26,7 @@ char *colon(char *);
26long convtime(const char *); 26long convtime(const char *);
27char *tilde_expand_filename(const char *, uid_t); 27char *tilde_expand_filename(const char *, uid_t);
28char *percent_expand(const char *, ...) __attribute__((sentinel)); 28char *percent_expand(const char *, ...) __attribute__((sentinel));
29char *tohex(const u_char *, u_int);
29 30
30struct passwd *pwcopy(struct passwd *); 31struct passwd *pwcopy(struct passwd *);
31 32
diff --git a/ssh.c b/ssh.c
index 67af53e69..43d97abcc 100644
--- a/ssh.c
+++ b/ssh.c
@@ -40,7 +40,7 @@
40 */ 40 */
41 41
42#include "includes.h" 42#include "includes.h"
43RCSID("$OpenBSD: ssh.c,v 1.246 2005/06/25 22:47:49 djm Exp $"); 43RCSID("$OpenBSD: ssh.c,v 1.247 2005/07/04 00:58:43 djm Exp $");
44 44
45#include <openssl/evp.h> 45#include <openssl/evp.h>
46#include <openssl/err.h> 46#include <openssl/err.h>
@@ -1250,41 +1250,44 @@ control_client(const char *path)
1250 error("Control socket connect(%.100s): %s", path, 1250 error("Control socket connect(%.100s): %s", path,
1251 strerror(errno)); 1251 strerror(errno));
1252 } 1252 }
1253 close(sock); 1253 close(sock);
1254 return; 1254 return;
1255 } 1255 }
1256 1256
1257 if (stdin_null_flag) { 1257 if (stdin_null_flag) {
1258 if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) 1258 if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
1259 fatal("open(/dev/null): %s", strerror(errno)); 1259 fatal("open(/dev/null): %s", strerror(errno));
1260 if (dup2(fd, STDIN_FILENO) == -1) 1260 if (dup2(fd, STDIN_FILENO) == -1)
1261 fatal("dup2: %s", strerror(errno)); 1261 fatal("dup2: %s", strerror(errno));
1262 if (fd > STDERR_FILENO) 1262 if (fd > STDERR_FILENO)
1263 close(fd); 1263 close(fd);
1264 } 1264 }
1265 1265
1266 if ((term = getenv("TERM")) == NULL) 1266 term = getenv("TERM");
1267 term = "";
1268 1267
1269 flags = 0; 1268 flags = 0;
1270 if (tty_flag) 1269 if (tty_flag)
1271 flags |= SSHMUX_FLAG_TTY; 1270 flags |= SSHMUX_FLAG_TTY;
1272 if (subsystem_flag) 1271 if (subsystem_flag)
1273 flags |= SSHMUX_FLAG_SUBSYS; 1272 flags |= SSHMUX_FLAG_SUBSYS;
1273 if (options.forward_x11)
1274 flags |= SSHMUX_FLAG_X11_FWD;
1275 if (options.forward_agent)
1276 flags |= SSHMUX_FLAG_AGENT_FWD;
1274 1277
1275 buffer_init(&m); 1278 buffer_init(&m);
1276 1279
1277 /* Send our command to server */ 1280 /* Send our command to server */
1278 buffer_put_int(&m, mux_command); 1281 buffer_put_int(&m, mux_command);
1279 buffer_put_int(&m, flags); 1282 buffer_put_int(&m, flags);
1280 if (ssh_msg_send(sock, /* version */1, &m) == -1) 1283 if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
1281 fatal("%s: msg_send", __func__); 1284 fatal("%s: msg_send", __func__);
1282 buffer_clear(&m); 1285 buffer_clear(&m);
1283 1286
1284 /* Get authorisation status and PID of controlee */ 1287 /* Get authorisation status and PID of controlee */
1285 if (ssh_msg_recv(sock, &m) == -1) 1288 if (ssh_msg_recv(sock, &m) == -1)
1286 fatal("%s: msg_recv", __func__); 1289 fatal("%s: msg_recv", __func__);
1287 if (buffer_get_char(&m) != 1) 1290 if (buffer_get_char(&m) != SSHMUX_VER)
1288 fatal("%s: wrong version", __func__); 1291 fatal("%s: wrong version", __func__);
1289 if (buffer_get_int(&m) != 1) 1292 if (buffer_get_int(&m) != 1)
1290 fatal("Connection to master denied"); 1293 fatal("Connection to master denied");
@@ -1308,7 +1311,7 @@ control_client(const char *path)
1308 } 1311 }
1309 1312
1310 /* SSHMUX_COMMAND_OPEN */ 1313 /* SSHMUX_COMMAND_OPEN */
1311 buffer_put_cstring(&m, term); 1314 buffer_put_cstring(&m, term ? term : "");
1312 buffer_append(&command, "\0", 1); 1315 buffer_append(&command, "\0", 1);
1313 buffer_put_cstring(&m, buffer_ptr(&command)); 1316 buffer_put_cstring(&m, buffer_ptr(&command));
1314 1317
@@ -1330,7 +1333,7 @@ control_client(const char *path)
1330 } 1333 }
1331 } 1334 }
1332 1335
1333 if (ssh_msg_send(sock, /* version */1, &m) == -1) 1336 if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
1334 fatal("%s: msg_send", __func__); 1337 fatal("%s: msg_send", __func__);
1335 1338
1336 mm_send_fd(sock, STDIN_FILENO); 1339 mm_send_fd(sock, STDIN_FILENO);
@@ -1341,7 +1344,7 @@ control_client(const char *path)
1341 buffer_clear(&m); 1344 buffer_clear(&m);
1342 if (ssh_msg_recv(sock, &m) == -1) 1345 if (ssh_msg_recv(sock, &m) == -1)
1343 fatal("%s: msg_recv", __func__); 1346 fatal("%s: msg_recv", __func__);
1344 if (buffer_get_char(&m) != 1) 1347 if (buffer_get_char(&m) != SSHMUX_VER)
1345 fatal("%s: wrong version", __func__); 1348 fatal("%s: wrong version", __func__);
1346 buffer_free(&m); 1349 buffer_free(&m);
1347 1350
diff --git a/ssh_config.5 b/ssh_config.5
index 3e7ca8f28..40774297c 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -34,7 +34,7 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.\" $OpenBSD: ssh_config.5,v 1.57 2005/06/18 04:30:36 djm Exp $ 37.\" $OpenBSD: ssh_config.5,v 1.58 2005/07/04 00:58:43 djm Exp $
38.Dd September 25, 1999 38.Dd September 25, 1999
39.Dt SSH_CONFIG 5 39.Dt SSH_CONFIG 5
40.Os 40.Os
@@ -279,6 +279,12 @@ can not be opened,
279.Nm ssh 279.Nm ssh
280will continue without connecting to a master instance. 280will continue without connecting to a master instance.
281.Pp 281.Pp
282X11 and
283.Xr ssh-agent 4
284forwarding is supported over these multiplexed connections, however the
285display and agent fowarded will be the one belonging to the master
286connection. I.e. it is not possible to forward multiple displays or agents.
287.Pp
282Two additional options allow for opportunistic multiplexing: try to use a 288Two additional options allow for opportunistic multiplexing: try to use a
283master connection but fall back to creating a new one if one does not already 289master connection but fall back to creating a new one if one does not already
284exist. 290exist.