summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2017-10-23 05:08:00 +0000
committerDamien Miller <djm@mindrot.org>2017-10-23 16:14:30 +1100
commitb7548b12a6b2b4abf4d057192c353147e0abba08 (patch)
treedc76477cd371b6197ba840c3a178bfbcf6d7baba
parent887669ef032d63cf07f53cada216fa8a0c9a7d72 (diff)
upstream commit
Expose devices allocated for tun/tap forwarding. At the client, the device may be obtained from a new %T expansion for LocalCommand. At the server, the allocated devices will be listed in a SSH_TUNNEL variable exposed to the environment of any user sessions started after the tunnel forwarding was established. ok markus Upstream-ID: e61e53f8ae80566e9ddc0d67a5df5bdf2f3c9f9e
-rw-r--r--clientloop.c12
-rw-r--r--clientloop.h4
-rw-r--r--misc.c12
-rw-r--r--misc.h4
-rw-r--r--openbsd-compat/port-tun.c16
-rw-r--r--openbsd-compat/port-tun.h2
-rw-r--r--serverloop.c22
-rw-r--r--session.c5
-rw-r--r--ssh.19
-rw-r--r--ssh.c108
-rw-r--r--ssh_config.516
11 files changed, 133 insertions, 77 deletions
diff --git a/clientloop.c b/clientloop.c
index 791d336e3..46ede4f0e 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.c,v 1.305 2017/09/19 04:24:22 djm Exp $ */ 1/* $OpenBSD: clientloop.c,v 1.306 2017/10/23 05:08:00 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1601,12 +1601,13 @@ client_request_agent(struct ssh *ssh, const char *request_type, int rchan)
1601 return c; 1601 return c;
1602} 1602}
1603 1603
1604int 1604char *
1605client_request_tun_fwd(struct ssh *ssh, int tun_mode, 1605client_request_tun_fwd(struct ssh *ssh, int tun_mode,
1606 int local_tun, int remote_tun) 1606 int local_tun, int remote_tun)
1607{ 1607{
1608 Channel *c; 1608 Channel *c;
1609 int fd; 1609 int fd;
1610 char *ifname = NULL;
1610 1611
1611 if (tun_mode == SSH_TUNMODE_NO) 1612 if (tun_mode == SSH_TUNMODE_NO)
1612 return 0; 1613 return 0;
@@ -1614,10 +1615,11 @@ client_request_tun_fwd(struct ssh *ssh, int tun_mode,
1614 debug("Requesting tun unit %d in mode %d", local_tun, tun_mode); 1615 debug("Requesting tun unit %d in mode %d", local_tun, tun_mode);
1615 1616
1616 /* Open local tunnel device */ 1617 /* Open local tunnel device */
1617 if ((fd = tun_open(local_tun, tun_mode)) == -1) { 1618 if ((fd = tun_open(local_tun, tun_mode, &ifname)) == -1) {
1618 error("Tunnel device open failed."); 1619 error("Tunnel device open failed.");
1619 return -1; 1620 return NULL;
1620 } 1621 }
1622 debug("Tunnel forwarding using interface %s", ifname);
1621 1623
1622 c = channel_new(ssh, "tun", SSH_CHANNEL_OPENING, fd, fd, -1, 1624 c = channel_new(ssh, "tun", SSH_CHANNEL_OPENING, fd, fd, -1,
1623 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); 1625 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
@@ -1638,7 +1640,7 @@ client_request_tun_fwd(struct ssh *ssh, int tun_mode,
1638 packet_put_int(remote_tun); 1640 packet_put_int(remote_tun);
1639 packet_send(); 1641 packet_send();
1640 1642
1641 return 0; 1643 return ifname;
1642} 1644}
1643 1645
1644/* XXXX move to generic input handler */ 1646/* XXXX move to generic input handler */
diff --git a/clientloop.h b/clientloop.h
index a1975ccc8..8d1f0bff6 100644
--- a/clientloop.h
+++ b/clientloop.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.h,v 1.34 2017/09/12 06:32:07 djm Exp $ */ 1/* $OpenBSD: clientloop.h,v 1.35 2017/10/23 05:08:00 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -46,7 +46,7 @@ int client_x11_get_proto(struct ssh *, const char *, const char *,
46void client_global_request_reply_fwd(int, u_int32_t, void *); 46void client_global_request_reply_fwd(int, u_int32_t, void *);
47void client_session2_setup(struct ssh *, int, int, int, 47void client_session2_setup(struct ssh *, int, int, int,
48 const char *, struct termios *, int, Buffer *, char **); 48 const char *, struct termios *, int, Buffer *, char **);
49int client_request_tun_fwd(struct ssh *, int, int, int); 49char *client_request_tun_fwd(struct ssh *, int, int, int);
50void client_stop_mux(void); 50void client_stop_mux(void);
51 51
52/* Escape filter for protocol 2 sessions */ 52/* Escape filter for protocol 2 sessions */
diff --git a/misc.c b/misc.c
index d4d0e44a5..7f1d42567 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: misc.c,v 1.114 2017/10/21 23:06:24 millert Exp $ */ 1/* $OpenBSD: misc.c,v 1.115 2017/10/23 05:08:00 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Copyright (c) 2005,2006 Damien Miller. All rights reserved. 4 * Copyright (c) 2005,2006 Damien Miller. All rights reserved.
@@ -964,16 +964,19 @@ read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
964} 964}
965 965
966int 966int
967tun_open(int tun, int mode) 967tun_open(int tun, int mode, char **ifname)
968{ 968{
969#if defined(CUSTOM_SYS_TUN_OPEN) 969#if defined(CUSTOM_SYS_TUN_OPEN)
970 return (sys_tun_open(tun, mode)); 970 return (sys_tun_open(tun, mode, ifname));
971#elif defined(SSH_TUN_OPENBSD) 971#elif defined(SSH_TUN_OPENBSD)
972 struct ifreq ifr; 972 struct ifreq ifr;
973 char name[100]; 973 char name[100];
974 int fd = -1, sock; 974 int fd = -1, sock;
975 const char *tunbase = "tun"; 975 const char *tunbase = "tun";
976 976
977 if (ifname != NULL)
978 *ifname = NULL;
979
977 if (mode == SSH_TUNMODE_ETHERNET) 980 if (mode == SSH_TUNMODE_ETHERNET)
978 tunbase = "tap"; 981 tunbase = "tap";
979 982
@@ -1020,6 +1023,9 @@ tun_open(int tun, int mode)
1020 } 1023 }
1021 } 1024 }
1022 1025
1026 if (ifname != NULL)
1027 *ifname = xstrdup(ifr.ifr_name);
1028
1023 close(sock); 1029 close(sock);
1024 return fd; 1030 return fd;
1025 1031
diff --git a/misc.h b/misc.h
index b6f502b3e..19fdf5c84 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: misc.h,v 1.64 2017/10/21 23:06:24 millert Exp $ */ 1/* $OpenBSD: misc.h,v 1.65 2017/10/23 05:08:00 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -87,7 +87,7 @@ void replacearg(arglist *, u_int, char *, ...)
87 __attribute__((format(printf, 3, 4))); 87 __attribute__((format(printf, 3, 4)));
88void freeargs(arglist *); 88void freeargs(arglist *);
89 89
90int tun_open(int, int); 90int tun_open(int, int, char **);
91 91
92/* Common definitions for ssh tunnel device forwarding */ 92/* Common definitions for ssh tunnel device forwarding */
93#define SSH_TUNMODE_NO 0x00 93#define SSH_TUNMODE_NO 0x00
diff --git a/openbsd-compat/port-tun.c b/openbsd-compat/port-tun.c
index 7579c6084..0e75c911d 100644
--- a/openbsd-compat/port-tun.c
+++ b/openbsd-compat/port-tun.c
@@ -56,12 +56,15 @@
56#include <linux/if_tun.h> 56#include <linux/if_tun.h>
57 57
58int 58int
59sys_tun_open(int tun, int mode) 59sys_tun_open(int tun, int mode, char **ifname)
60{ 60{
61 struct ifreq ifr; 61 struct ifreq ifr;
62 int fd = -1; 62 int fd = -1;
63 const char *name = NULL; 63 const char *name = NULL;
64 64
65 if (ifname != NULL)
66 *ifname = NULL;
67
65 if ((fd = open("/dev/net/tun", O_RDWR)) == -1) { 68 if ((fd = open("/dev/net/tun", O_RDWR)) == -1) {
66 debug("%s: failed to open tunnel control interface: %s", 69 debug("%s: failed to open tunnel control interface: %s",
67 __func__, strerror(errno)); 70 __func__, strerror(errno));
@@ -99,6 +102,9 @@ sys_tun_open(int tun, int mode)
99 else 102 else
100 debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd); 103 debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd);
101 104
105 if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)))
106 goto failed;
107
102 return (fd); 108 return (fd);
103 109
104 failed: 110 failed:
@@ -116,13 +122,16 @@ sys_tun_open(int tun, int mode)
116#endif 122#endif
117 123
118int 124int
119sys_tun_open(int tun, int mode) 125sys_tun_open(int tun, int mode, char **ifname)
120{ 126{
121 struct ifreq ifr; 127 struct ifreq ifr;
122 char name[100]; 128 char name[100];
123 int fd = -1, sock, flag; 129 int fd = -1, sock, flag;
124 const char *tunbase = "tun"; 130 const char *tunbase = "tun";
125 131
132 if (ifname != NULL)
133 *ifname = NULL;
134
126 if (mode == SSH_TUNMODE_ETHERNET) { 135 if (mode == SSH_TUNMODE_ETHERNET) {
127#ifdef SSH_TUN_NO_L2 136#ifdef SSH_TUN_NO_L2
128 debug("%s: no layer 2 tunnelling support", __func__); 137 debug("%s: no layer 2 tunnelling support", __func__);
@@ -180,6 +189,9 @@ sys_tun_open(int tun, int mode)
180 goto failed; 189 goto failed;
181 } 190 }
182 191
192 if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)))
193 goto failed;
194
183 close(sock); 195 close(sock);
184 return (fd); 196 return (fd);
185 197
diff --git a/openbsd-compat/port-tun.h b/openbsd-compat/port-tun.h
index 103514370..926bc93e1 100644
--- a/openbsd-compat/port-tun.h
+++ b/openbsd-compat/port-tun.h
@@ -22,7 +22,7 @@ struct ssh;
22 22
23#if defined(SSH_TUN_LINUX) || defined(SSH_TUN_FREEBSD) 23#if defined(SSH_TUN_LINUX) || defined(SSH_TUN_FREEBSD)
24# define CUSTOM_SYS_TUN_OPEN 24# define CUSTOM_SYS_TUN_OPEN
25int sys_tun_open(int, int); 25int sys_tun_open(int, int, char **);
26#endif 26#endif
27 27
28#if defined(SSH_TUN_COMPAT_AF) || defined(SSH_TUN_PREPEND_AF) 28#if defined(SSH_TUN_COMPAT_AF) || defined(SSH_TUN_PREPEND_AF)
diff --git a/serverloop.c b/serverloop.c
index 24bbae322..a3cb8e782 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: serverloop.c,v 1.198 2017/09/12 06:35:32 djm Exp $ */ 1/* $OpenBSD: serverloop.c,v 1.199 2017/10/23 05:08:00 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -99,6 +99,9 @@ static volatile sig_atomic_t received_sigterm = 0;
99/* prototypes */ 99/* prototypes */
100static void server_init_dispatch(void); 100static void server_init_dispatch(void);
101 101
102/* requested tunnel forwarding interface(s), shared with session.c */
103char *tun_fwd_ifnames = NULL;
104
102/* 105/*
103 * we write to this pipe if a SIGCHLD is caught in order to avoid 106 * we write to this pipe if a SIGCHLD is caught in order to avoid
104 * the race between select() and child_terminated 107 * the race between select() and child_terminated
@@ -519,6 +522,7 @@ server_request_tun(struct ssh *ssh)
519 Channel *c = NULL; 522 Channel *c = NULL;
520 int mode, tun; 523 int mode, tun;
521 int sock; 524 int sock;
525 char *tmp, *ifname = NULL;
522 526
523 mode = packet_get_int(); 527 mode = packet_get_int();
524 switch (mode) { 528 switch (mode) {
@@ -541,9 +545,10 @@ server_request_tun(struct ssh *ssh)
541 goto done; 545 goto done;
542 tun = forced_tun_device; 546 tun = forced_tun_device;
543 } 547 }
544 sock = tun_open(tun, mode); 548 sock = tun_open(tun, mode, &ifname);
545 if (sock < 0) 549 if (sock < 0)
546 goto done; 550 goto done;
551 debug("Tunnel forwarding using interface %s", ifname);
547 c = channel_new(ssh, "tun", SSH_CHANNEL_OPEN, sock, sock, -1, 552 c = channel_new(ssh, "tun", SSH_CHANNEL_OPEN, sock, sock, -1,
548 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); 553 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
549 c->datagram = 1; 554 c->datagram = 1;
@@ -553,6 +558,19 @@ server_request_tun(struct ssh *ssh)
553 sys_tun_outfilter, NULL, NULL); 558 sys_tun_outfilter, NULL, NULL);
554#endif 559#endif
555 560
561 /*
562 * Update the list of names exposed to the session
563 * XXX remove these if the tunnels are closed (won't matter
564 * much if they are already in the environment though)
565 */
566 tmp = tun_fwd_ifnames;
567 xasprintf(&tun_fwd_ifnames, "%s%s%s",
568 tun_fwd_ifnames == NULL ? "" : tun_fwd_ifnames,
569 tun_fwd_ifnames == NULL ? "" : ",",
570 ifname);
571 free(tmp);
572 free(ifname);
573
556 done: 574 done:
557 if (c == NULL) 575 if (c == NULL)
558 packet_send_debug("Failed to open the tunnel device."); 576 packet_send_debug("Failed to open the tunnel device.");
diff --git a/session.c b/session.c
index 4bccb62d1..a701fa0cd 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: session.c,v 1.292 2017/09/12 06:32:07 djm Exp $ */ 1/* $OpenBSD: session.c,v 1.293 2017/10/23 05:08:00 djm Exp $ */
2/* 2/*
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved 4 * All rights reserved
@@ -140,6 +140,7 @@ extern u_int utmp_len;
140extern int startup_pipe; 140extern int startup_pipe;
141extern void destroy_sensitive_data(void); 141extern void destroy_sensitive_data(void);
142extern Buffer loginmsg; 142extern Buffer loginmsg;
143char *tun_fwd_ifnames; /* serverloop.c */
143 144
144/* original command from peer. */ 145/* original command from peer. */
145const char *original_command = NULL; 146const char *original_command = NULL;
@@ -1066,6 +1067,8 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
1066 free(laddr); 1067 free(laddr);
1067 child_set_env(&env, &envsize, "SSH_CONNECTION", buf); 1068 child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
1068 1069
1070 if (tun_fwd_ifnames != NULL)
1071 child_set_env(&env, &envsize, "SSH_TUNNEL", tun_fwd_ifnames);
1069 if (auth_info_file != NULL) 1072 if (auth_info_file != NULL)
1070 child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file); 1073 child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file);
1071 if (s->ttyfd != -1) 1074 if (s->ttyfd != -1)
diff --git a/ssh.1 b/ssh.1
index 310f34cc9..093f17707 100644
--- a/ssh.1
+++ b/ssh.1
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: ssh.1,v 1.386 2017/10/21 23:06:24 millert Exp $ 36.\" $OpenBSD: ssh.1,v 1.387 2017/10/23 05:08:00 djm Exp $
37.Dd $Mdocdate: October 21 2017 $ 37.Dd $Mdocdate: October 23 2017 $
38.Dt SSH 1 38.Dt SSH 1
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -1395,6 +1395,11 @@ This is set to the name of the tty (path to the device) associated
1395with the current shell or command. 1395with the current shell or command.
1396If the current session has no tty, 1396If the current session has no tty,
1397this variable is not set. 1397this variable is not set.
1398.It Ev SSH_TUNNEL
1399Optionally set by
1400.Xr sshd 8
1401to contain the interface names assigned if tunnel forwarding was
1402requested by the client.
1398.It Ev SSH_USER_AUTH 1403.It Ev SSH_USER_AUTH
1399Optionally set by 1404Optionally set by
1400.Xr sshd 8 , 1405.Xr sshd 8 ,
diff --git a/ssh.c b/ssh.c
index 213c35e77..74056985b 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.465 2017/10/21 23:06:24 millert Exp $ */ 1/* $OpenBSD: ssh.c,v 1.466 2017/10/23 05:08:00 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -168,6 +168,10 @@ char *config = NULL;
168 */ 168 */
169char *host; 169char *host;
170 170
171/* Various strings used to to percent_expand() arguments */
172static char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
173static char uidstr[32], *host_arg, *conn_hash_hex;
174
171/* socket address the host resolves to */ 175/* socket address the host resolves to */
172struct sockaddr_storage hostaddr; 176struct sockaddr_storage hostaddr;
173 177
@@ -208,8 +212,8 @@ usage(void)
208 exit(255); 212 exit(255);
209} 213}
210 214
211static int ssh_session2(struct ssh *); 215static int ssh_session2(struct ssh *, struct passwd *);
212static void load_public_identity_files(void); 216static void load_public_identity_files(struct passwd *);
213static void main_sigchld_handler(int); 217static void main_sigchld_handler(int);
214 218
215/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ 219/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */
@@ -456,14 +460,14 @@ resolve_canonicalize(char **hostp, int port)
456 * file if the user specifies a config file on the command line. 460 * file if the user specifies a config file on the command line.
457 */ 461 */
458static void 462static void
459process_config_files(const char *host_arg, struct passwd *pw, int post_canon) 463process_config_files(const char *host_name, struct passwd *pw, int post_canon)
460{ 464{
461 char buf[PATH_MAX]; 465 char buf[PATH_MAX];
462 int r; 466 int r;
463 467
464 if (config != NULL) { 468 if (config != NULL) {
465 if (strcasecmp(config, "none") != 0 && 469 if (strcasecmp(config, "none") != 0 &&
466 !read_config_file(config, pw, host, host_arg, &options, 470 !read_config_file(config, pw, host, host_name, &options,
467 SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0))) 471 SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0)))
468 fatal("Can't open user config file %.100s: " 472 fatal("Can't open user config file %.100s: "
469 "%.100s", config, strerror(errno)); 473 "%.100s", config, strerror(errno));
@@ -471,13 +475,13 @@ process_config_files(const char *host_arg, struct passwd *pw, int post_canon)
471 r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, 475 r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
472 _PATH_SSH_USER_CONFFILE); 476 _PATH_SSH_USER_CONFFILE);
473 if (r > 0 && (size_t)r < sizeof(buf)) 477 if (r > 0 && (size_t)r < sizeof(buf))
474 (void)read_config_file(buf, pw, host, host_arg, 478 (void)read_config_file(buf, pw, host, host_name,
475 &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | 479 &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF |
476 (post_canon ? SSHCONF_POSTCANON : 0)); 480 (post_canon ? SSHCONF_POSTCANON : 0));
477 481
478 /* Read systemwide configuration file after user config. */ 482 /* Read systemwide configuration file after user config. */
479 (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, 483 (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw,
480 host, host_arg, &options, 484 host, host_name, &options,
481 post_canon ? SSHCONF_POSTCANON : 0); 485 post_canon ? SSHCONF_POSTCANON : 0);
482 } 486 }
483} 487}
@@ -511,9 +515,8 @@ main(int ac, char **av)
511 struct ssh *ssh = NULL; 515 struct ssh *ssh = NULL;
512 int i, r, opt, exit_status, use_syslog, direct, timeout_ms; 516 int i, r, opt, exit_status, use_syslog, direct, timeout_ms;
513 int config_test = 0, opt_terminated = 0; 517 int config_test = 0, opt_terminated = 0;
514 char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile; 518 char *p, *cp, *line, *argv0, buf[PATH_MAX], *logfile;
515 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; 519 char cname[NI_MAXHOST];
516 char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex;
517 struct stat st; 520 struct stat st;
518 struct passwd *pw; 521 struct passwd *pw;
519 extern int optind, optreset; 522 extern int optind, optreset;
@@ -1203,6 +1206,7 @@ main(int ac, char **av)
1203 if (options.user == NULL) 1206 if (options.user == NULL)
1204 options.user = xstrdup(pw->pw_name); 1207 options.user = xstrdup(pw->pw_name);
1205 1208
1209 /* Set up strings used to percent_expand() arguments */
1206 if (gethostname(thishost, sizeof(thishost)) == -1) 1210 if (gethostname(thishost, sizeof(thishost)) == -1)
1207 fatal("gethostname: %s", strerror(errno)); 1211 fatal("gethostname: %s", strerror(errno));
1208 strlcpy(shorthost, thishost, sizeof(shorthost)); 1212 strlcpy(shorthost, thishost, sizeof(shorthost));
@@ -1220,24 +1224,11 @@ main(int ac, char **av)
1220 ssh_digest_free(md); 1224 ssh_digest_free(md);
1221 conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); 1225 conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
1222 1226
1223 if (options.local_command != NULL) { 1227 /*
1224 debug3("expanding LocalCommand: %s", options.local_command); 1228 * Expand tokens in arguments. NB. LocalCommand is expanded later,
1225 cp = options.local_command; 1229 * after port-forwarding is set up, so it may pick up any local
1226 options.local_command = percent_expand(cp, 1230 * tunnel interface name allocated.
1227 "C", conn_hash_hex, 1231 */
1228 "L", shorthost,
1229 "d", pw->pw_dir,
1230 "h", host,
1231 "l", thishost,
1232 "n", host_arg,
1233 "p", portstr,
1234 "r", options.user,
1235 "u", pw->pw_name,
1236 (char *)NULL);
1237 debug3("expanded LocalCommand: %s", options.local_command);
1238 free(cp);
1239 }
1240
1241 if (options.remote_command != NULL) { 1232 if (options.remote_command != NULL) {
1242 debug3("expanding RemoteCommand: %s", options.remote_command); 1233 debug3("expanding RemoteCommand: %s", options.remote_command);
1243 cp = options.remote_command; 1234 cp = options.remote_command;
@@ -1256,7 +1247,6 @@ main(int ac, char **av)
1256 free(cp); 1247 free(cp);
1257 buffer_append(&command, options.remote_command, 1248 buffer_append(&command, options.remote_command,
1258 strlen(options.remote_command)); 1249 strlen(options.remote_command));
1259
1260 } 1250 }
1261 1251
1262 if (options.control_path != NULL) { 1252 if (options.control_path != NULL) {
@@ -1427,7 +1417,7 @@ main(int ac, char **av)
1427 } 1417 }
1428 } 1418 }
1429 /* load options.identity_files */ 1419 /* load options.identity_files */
1430 load_public_identity_files(); 1420 load_public_identity_files(pw);
1431 1421
1432 /* optionally set the SSH_AUTHSOCKET_ENV_NAME varibale */ 1422 /* optionally set the SSH_AUTHSOCKET_ENV_NAME varibale */
1433 if (options.identity_agent && 1423 if (options.identity_agent &&
@@ -1491,7 +1481,7 @@ main(int ac, char **av)
1491 } 1481 }
1492 1482
1493 skip_connect: 1483 skip_connect:
1494 exit_status = ssh_session2(ssh); 1484 exit_status = ssh_session2(ssh, pw);
1495 packet_close(); 1485 packet_close();
1496 1486
1497 if (options.control_path != NULL && muxserver_sock != -1) 1487 if (options.control_path != NULL && muxserver_sock != -1)
@@ -1650,7 +1640,7 @@ ssh_init_stdio_forwarding(struct ssh *ssh)
1650} 1640}
1651 1641
1652static void 1642static void
1653ssh_init_forwarding(struct ssh *ssh) 1643ssh_init_forwarding(struct ssh *ssh, char **ifname)
1654{ 1644{
1655 int success = 0; 1645 int success = 0;
1656 int i; 1646 int i;
@@ -1708,8 +1698,9 @@ ssh_init_forwarding(struct ssh *ssh)
1708 1698
1709 /* Initiate tunnel forwarding. */ 1699 /* Initiate tunnel forwarding. */
1710 if (options.tun_open != SSH_TUNMODE_NO) { 1700 if (options.tun_open != SSH_TUNMODE_NO) {
1711 if (client_request_tun_fwd(ssh, options.tun_open, 1701 if ((*ifname = client_request_tun_fwd(ssh,
1712 options.tun_local, options.tun_remote) == -1) { 1702 options.tun_open, options.tun_local,
1703 options.tun_remote)) == NULL) {
1713 if (options.exit_on_forward_failure) 1704 if (options.exit_on_forward_failure)
1714 fatal("Could not request tunnel forwarding."); 1705 fatal("Could not request tunnel forwarding.");
1715 else 1706 else
@@ -1824,14 +1815,35 @@ ssh_session2_open(struct ssh *ssh)
1824} 1815}
1825 1816
1826static int 1817static int
1827ssh_session2(struct ssh *ssh) 1818ssh_session2(struct ssh *ssh, struct passwd *pw)
1828{ 1819{
1829 int id = -1; 1820 int id = -1;
1821 char *cp, *tun_fwd_ifname = NULL;
1830 1822
1831 /* XXX should be pre-session */ 1823 /* XXX should be pre-session */
1832 if (!options.control_persist) 1824 if (!options.control_persist)
1833 ssh_init_stdio_forwarding(ssh); 1825 ssh_init_stdio_forwarding(ssh);
1834 ssh_init_forwarding(ssh); 1826
1827 ssh_init_forwarding(ssh, &tun_fwd_ifname);
1828
1829 if (options.local_command != NULL) {
1830 debug3("expanding LocalCommand: %s", options.local_command);
1831 cp = options.local_command;
1832 options.local_command = percent_expand(cp,
1833 "C", conn_hash_hex,
1834 "L", shorthost,
1835 "d", pw->pw_dir,
1836 "h", host,
1837 "l", thishost,
1838 "n", host_arg,
1839 "p", portstr,
1840 "r", options.user,
1841 "u", pw->pw_name,
1842 "T", tun_fwd_ifname == NULL ? "NONE" : tun_fwd_ifname,
1843 (char *)NULL);
1844 debug3("expanded LocalCommand: %s", options.local_command);
1845 free(cp);
1846 }
1835 1847
1836 /* Start listening for multiplex clients */ 1848 /* Start listening for multiplex clients */
1837 if (!packet_get_mux()) 1849 if (!packet_get_mux())
@@ -1907,12 +1919,10 @@ ssh_session2(struct ssh *ssh)
1907 1919
1908/* Loads all IdentityFile and CertificateFile keys */ 1920/* Loads all IdentityFile and CertificateFile keys */
1909static void 1921static void
1910load_public_identity_files(void) 1922load_public_identity_files(struct passwd *pw)
1911{ 1923{
1912 char *filename, *cp, thishost[NI_MAXHOST]; 1924 char *filename, *cp;
1913 char *pwdir = NULL, *pwname = NULL;
1914 struct sshkey *public; 1925 struct sshkey *public;
1915 struct passwd *pw;
1916 int i; 1926 int i;
1917 u_int n_ids, n_certs; 1927 u_int n_ids, n_certs;
1918 char *identity_files[SSH_MAX_IDENTITY_FILES]; 1928 char *identity_files[SSH_MAX_IDENTITY_FILES];
@@ -1951,11 +1961,6 @@ load_public_identity_files(void)
1951#endif /* ENABLE_PKCS11 */ 1961#endif /* ENABLE_PKCS11 */
1952 if ((pw = getpwuid(original_real_uid)) == NULL) 1962 if ((pw = getpwuid(original_real_uid)) == NULL)
1953 fatal("load_public_identity_files: getpwuid failed"); 1963 fatal("load_public_identity_files: getpwuid failed");
1954 pwname = xstrdup(pw->pw_name);
1955 pwdir = xstrdup(pw->pw_dir);
1956 if (gethostname(thishost, sizeof(thishost)) == -1)
1957 fatal("load_public_identity_files: gethostname: %s",
1958 strerror(errno));
1959 for (i = 0; i < options.num_identity_files; i++) { 1964 for (i = 0; i < options.num_identity_files; i++) {
1960 if (n_ids >= SSH_MAX_IDENTITY_FILES || 1965 if (n_ids >= SSH_MAX_IDENTITY_FILES ||
1961 strcasecmp(options.identity_files[i], "none") == 0) { 1966 strcasecmp(options.identity_files[i], "none") == 0) {
@@ -1965,8 +1970,8 @@ load_public_identity_files(void)
1965 } 1970 }
1966 cp = tilde_expand_filename(options.identity_files[i], 1971 cp = tilde_expand_filename(options.identity_files[i],
1967 original_real_uid); 1972 original_real_uid);
1968 filename = percent_expand(cp, "d", pwdir, 1973 filename = percent_expand(cp, "d", pw->pw_dir,
1969 "u", pwname, "l", thishost, "h", host, 1974 "u", pw->pw_name, "l", thishost, "h", host,
1970 "r", options.user, (char *)NULL); 1975 "r", options.user, (char *)NULL);
1971 free(cp); 1976 free(cp);
1972 public = key_load_public(filename, NULL); 1977 public = key_load_public(filename, NULL);
@@ -2011,8 +2016,8 @@ load_public_identity_files(void)
2011 for (i = 0; i < options.num_certificate_files; i++) { 2016 for (i = 0; i < options.num_certificate_files; i++) {
2012 cp = tilde_expand_filename(options.certificate_files[i], 2017 cp = tilde_expand_filename(options.certificate_files[i],
2013 original_real_uid); 2018 original_real_uid);
2014 filename = percent_expand(cp, "d", pwdir, 2019 filename = percent_expand(cp, "d", pw->pw_dir,
2015 "u", pwname, "l", thishost, "h", host, 2020 "u", pw->pw_name, "l", thishost, "h", host,
2016 "r", options.user, (char *)NULL); 2021 "r", options.user, (char *)NULL);
2017 free(cp); 2022 free(cp);
2018 2023
@@ -2045,11 +2050,6 @@ load_public_identity_files(void)
2045 memcpy(options.certificate_files, 2050 memcpy(options.certificate_files,
2046 certificate_files, sizeof(certificate_files)); 2051 certificate_files, sizeof(certificate_files));
2047 memcpy(options.certificates, certificates, sizeof(certificates)); 2052 memcpy(options.certificates, certificates, sizeof(certificates));
2048
2049 explicit_bzero(pwname, strlen(pwname));
2050 free(pwname);
2051 explicit_bzero(pwdir, strlen(pwdir));
2052 free(pwdir);
2053} 2053}
2054 2054
2055static void 2055static void
diff --git a/ssh_config.5 b/ssh_config.5
index c04701044..4d3fc3425 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: ssh_config.5,v 1.260 2017/10/21 23:06:24 millert Exp $ 36.\" $OpenBSD: ssh_config.5,v 1.261 2017/10/23 05:08:00 djm Exp $
37.Dd $Mdocdate: October 21 2017 $ 37.Dd $Mdocdate: October 23 2017 $
38.Dt SSH_CONFIG 5 38.Dt SSH_CONFIG 5
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -1713,6 +1713,16 @@ The original remote hostname, as given on the command line.
1713The remote port. 1713The remote port.
1714.It %r 1714.It %r
1715The remote username. 1715The remote username.
1716.It \&%T
1717The local
1718.Xr tun 4
1719or
1720.Xr tap 4
1721network interface assigned if
1722.Cm Tunnel
1723forwarding was requested, or
1724.Cm NONE
1725otherwise.
1716.It %u 1726.It %u
1717The local username. 1727The local username.
1718.El 1728.El
@@ -1735,7 +1745,7 @@ and
1735accept the tokens %%, %d, %h, %l, %r, and %u. 1745accept the tokens %%, %d, %h, %l, %r, and %u.
1736.Pp 1746.Pp
1737.Cm LocalCommand 1747.Cm LocalCommand
1738accepts the tokens %%, %C, %d, %h, %l, %n, %p, %r, and %u. 1748accepts the tokens %%, %C, %d, %h, %l, %n, %p, %r, %T, and %u.
1739.Pp 1749.Pp
1740.Cm ProxyCommand 1750.Cm ProxyCommand
1741accepts the tokens %%, %h, %p, and %r. 1751accepts the tokens %%, %h, %p, and %r.