diff options
author | Damien Miller <djm@cvs.openbsd.org> | 2017-10-23 05:08:01 +0000 |
---|---|---|
committer | Damien Miller <djm@cvs.openbsd.org> | 2017-10-23 05:08:01 +0000 |
commit | d101021c91e6723d093b279fa2979e22fa704f32 (patch) | |
tree | 39eb2aacd7bc4b20a0f1cb6bb2bd7b548cd8064c /usr.bin | |
parent | f0376769f6cc51d6e56898684c676dac4807ce18 (diff) |
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
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/ssh/clientloop.c | 12 | ||||
-rw-r--r-- | usr.bin/ssh/clientloop.h | 4 | ||||
-rw-r--r-- | usr.bin/ssh/misc.c | 10 | ||||
-rw-r--r-- | usr.bin/ssh/misc.h | 4 | ||||
-rw-r--r-- | usr.bin/ssh/serverloop.c | 23 | ||||
-rw-r--r-- | usr.bin/ssh/session.c | 5 | ||||
-rw-r--r-- | usr.bin/ssh/ssh.1 | 9 | ||||
-rw-r--r-- | usr.bin/ssh/ssh.c | 108 | ||||
-rw-r--r-- | usr.bin/ssh/ssh_config.5 | 16 |
9 files changed, 118 insertions, 73 deletions
diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c index c439b03cd7d..21c976b4257 100644 --- a/usr.bin/ssh/clientloop.c +++ b/usr.bin/ssh/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.305 2017/09/19 04:24:22 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.306 2017/10/23 05:08:00 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -1592,12 +1592,13 @@ client_request_agent(struct ssh *ssh, const char *request_type, int rchan) return c; } -int +char * client_request_tun_fwd(struct ssh *ssh, int tun_mode, int local_tun, int remote_tun) { Channel *c; int fd; + char *ifname = NULL; if (tun_mode == SSH_TUNMODE_NO) return 0; @@ -1605,10 +1606,11 @@ client_request_tun_fwd(struct ssh *ssh, int tun_mode, debug("Requesting tun unit %d in mode %d", local_tun, tun_mode); /* Open local tunnel device */ - if ((fd = tun_open(local_tun, tun_mode)) == -1) { + if ((fd = tun_open(local_tun, tun_mode, &ifname)) == -1) { error("Tunnel device open failed."); - return -1; + return NULL; } + debug("Tunnel forwarding using interface %s", ifname); c = channel_new(ssh, "tun", SSH_CHANNEL_OPENING, fd, fd, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); @@ -1623,7 +1625,7 @@ client_request_tun_fwd(struct ssh *ssh, int tun_mode, packet_put_int(remote_tun); packet_send(); - return 0; + return ifname; } /* XXXX move to generic input handler */ diff --git a/usr.bin/ssh/clientloop.h b/usr.bin/ssh/clientloop.h index a1975ccc8a1..8d1f0bff695 100644 --- a/usr.bin/ssh/clientloop.h +++ b/usr.bin/ssh/clientloop.h @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.h,v 1.34 2017/09/12 06:32:07 djm Exp $ */ +/* $OpenBSD: clientloop.h,v 1.35 2017/10/23 05:08:00 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -46,7 +46,7 @@ int client_x11_get_proto(struct ssh *, const char *, const char *, void client_global_request_reply_fwd(int, u_int32_t, void *); void client_session2_setup(struct ssh *, int, int, int, const char *, struct termios *, int, Buffer *, char **); -int client_request_tun_fwd(struct ssh *, int, int, int); +char *client_request_tun_fwd(struct ssh *, int, int, int); void client_stop_mux(void); /* Escape filter for protocol 2 sessions */ diff --git a/usr.bin/ssh/misc.c b/usr.bin/ssh/misc.c index 33e0c3a5972..54efcfd5cd0 100644 --- a/usr.bin/ssh/misc.c +++ b/usr.bin/ssh/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.114 2017/10/21 23:06:24 millert Exp $ */ +/* $OpenBSD: misc.c,v 1.115 2017/10/23 05:08:00 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005,2006 Damien Miller. All rights reserved. @@ -944,13 +944,16 @@ read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz, } int -tun_open(int tun, int mode) +tun_open(int tun, int mode, char **ifname) { struct ifreq ifr; char name[100]; int fd = -1, sock; const char *tunbase = "tun"; + if (ifname != NULL) + *ifname = NULL; + if (mode == SSH_TUNMODE_ETHERNET) tunbase = "tap"; @@ -997,6 +1000,9 @@ tun_open(int tun, int mode) } } + if (ifname != NULL) + *ifname = xstrdup(ifr.ifr_name); + close(sock); return fd; diff --git a/usr.bin/ssh/misc.h b/usr.bin/ssh/misc.h index b5ee75e235c..e4bd39b37c2 100644 --- a/usr.bin/ssh/misc.h +++ b/usr.bin/ssh/misc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.h,v 1.64 2017/10/21 23:06:24 millert Exp $ */ +/* $OpenBSD: misc.h,v 1.65 2017/10/23 05:08:00 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -85,7 +85,7 @@ void replacearg(arglist *, u_int, char *, ...) __attribute__((format(printf, 3, 4))); void freeargs(arglist *); -int tun_open(int, int); +int tun_open(int, int, char **); /* Common definitions for ssh tunnel device forwarding */ #define SSH_TUNMODE_NO 0x00 diff --git a/usr.bin/ssh/serverloop.c b/usr.bin/ssh/serverloop.c index aeb39328c4d..955656ec81e 100644 --- a/usr.bin/ssh/serverloop.c +++ b/usr.bin/ssh/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.198 2017/09/12 06:35:32 djm Exp $ */ +/* $OpenBSD: serverloop.c,v 1.199 2017/10/23 05:08:00 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -95,6 +95,9 @@ static volatile sig_atomic_t received_sigterm = 0; /* prototypes */ static void server_init_dispatch(void); +/* requested tunnel forwarding interface(s), shared with session.c */ +char *tun_fwd_ifnames = NULL; + /* * we write to this pipe if a SIGCHLD is caught in order to avoid * the race between select() and child_terminated @@ -512,6 +515,7 @@ server_request_tun(struct ssh *ssh) Channel *c = NULL; int mode, tun; int sock; + char *tmp, *ifname = NULL; mode = packet_get_int(); switch (mode) { @@ -534,13 +538,28 @@ server_request_tun(struct ssh *ssh) goto done; tun = forced_tun_device; } - sock = tun_open(tun, mode); + sock = tun_open(tun, mode, &ifname); if (sock < 0) goto done; + debug("Tunnel forwarding using interface %s", ifname); + c = channel_new(ssh, "tun", SSH_CHANNEL_OPEN, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); c->datagram = 1; + /* + * Update the list of names exposed to the session + * XXX remove these if the tunnels are closed (won't matter + * much if they are already in the environment though) + */ + tmp = tun_fwd_ifnames; + xasprintf(&tun_fwd_ifnames, "%s%s%s", + tun_fwd_ifnames == NULL ? "" : tun_fwd_ifnames, + tun_fwd_ifnames == NULL ? "" : ",", + ifname); + free(tmp); + free(ifname); + done: if (c == NULL) packet_send_debug("Failed to open the tunnel device."); diff --git a/usr.bin/ssh/session.c b/usr.bin/ssh/session.c index 7fbc3048274..6ab23a84dd1 100644 --- a/usr.bin/ssh/session.c +++ b/usr.bin/ssh/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.292 2017/09/12 06:32:07 djm Exp $ */ +/* $OpenBSD: session.c,v 1.293 2017/10/23 05:08:00 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved @@ -124,6 +124,7 @@ extern u_int utmp_len; extern int startup_pipe; extern void destroy_sensitive_data(void); extern Buffer loginmsg; +char *tun_fwd_ifnames; /* serverloop.c */ /* original command from peer. */ const char *original_command = NULL; @@ -834,6 +835,8 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) free(laddr); child_set_env(&env, &envsize, "SSH_CONNECTION", buf); + if (tun_fwd_ifnames != NULL) + child_set_env(&env, &envsize, "SSH_TUNNEL", tun_fwd_ifnames); if (auth_info_file != NULL) child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file); if (s->ttyfd != -1) diff --git a/usr.bin/ssh/ssh.1 b/usr.bin/ssh/ssh.1 index 310f34cc952..093f17707c7 100644 --- a/usr.bin/ssh/ssh.1 +++ b/usr.bin/ssh/ssh.1 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.386 2017/10/21 23:06:24 millert Exp $ -.Dd $Mdocdate: October 21 2017 $ +.\" $OpenBSD: ssh.1,v 1.387 2017/10/23 05:08:00 djm Exp $ +.Dd $Mdocdate: October 23 2017 $ .Dt SSH 1 .Os .Sh NAME @@ -1395,6 +1395,11 @@ This is set to the name of the tty (path to the device) associated with the current shell or command. If the current session has no tty, this variable is not set. +.It Ev SSH_TUNNEL +Optionally set by +.Xr sshd 8 +to contain the interface names assigned if tunnel forwarding was +requested by the client. .It Ev SSH_USER_AUTH Optionally set by .Xr sshd 8 , diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c index b411635279e..9053a8f056d 100644 --- a/usr.bin/ssh/ssh.c +++ b/usr.bin/ssh/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.465 2017/10/21 23:06:24 millert Exp $ */ +/* $OpenBSD: ssh.c,v 1.466 2017/10/23 05:08:00 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -152,6 +152,10 @@ char *config = NULL; */ char *host; +/* Various strings used to to percent_expand() arguments */ +static char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; +static char uidstr[32], *host_arg, *conn_hash_hex; + /* socket address the host resolves to */ struct sockaddr_storage hostaddr; @@ -192,8 +196,8 @@ usage(void) exit(255); } -static int ssh_session2(struct ssh *); -static void load_public_identity_files(void); +static int ssh_session2(struct ssh *, struct passwd *); +static void load_public_identity_files(struct passwd *); static void main_sigchld_handler(int); /* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ @@ -440,14 +444,14 @@ resolve_canonicalize(char **hostp, int port) * file if the user specifies a config file on the command line. */ static void -process_config_files(const char *host_arg, struct passwd *pw, int post_canon) +process_config_files(const char *host_name, struct passwd *pw, int post_canon) { char buf[PATH_MAX]; int r; if (config != NULL) { if (strcasecmp(config, "none") != 0 && - !read_config_file(config, pw, host, host_arg, &options, + !read_config_file(config, pw, host, host_name, &options, SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0))) fatal("Can't open user config file %.100s: " "%.100s", config, strerror(errno)); @@ -455,13 +459,13 @@ process_config_files(const char *host_arg, struct passwd *pw, int post_canon) r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_USER_CONFFILE); if (r > 0 && (size_t)r < sizeof(buf)) - (void)read_config_file(buf, pw, host, host_arg, + (void)read_config_file(buf, pw, host, host_name, &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0)); /* Read systemwide configuration file after user config. */ (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, - host, host_arg, &options, + host, host_name, &options, post_canon ? SSHCONF_POSTCANON : 0); } } @@ -495,9 +499,8 @@ main(int ac, char **av) struct ssh *ssh = NULL; int i, r, opt, exit_status, use_syslog, direct, timeout_ms; int config_test = 0, opt_terminated = 0; - char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile; - char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; - char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex; + char *p, *cp, *line, *argv0, buf[PATH_MAX], *logfile; + char cname[NI_MAXHOST]; struct stat st; struct passwd *pw; extern int optind, optreset; @@ -1169,6 +1172,7 @@ main(int ac, char **av) if (options.user == NULL) options.user = xstrdup(pw->pw_name); + /* Set up strings used to percent_expand() arguments */ if (gethostname(thishost, sizeof(thishost)) == -1) fatal("gethostname: %s", strerror(errno)); strlcpy(shorthost, thishost, sizeof(shorthost)); @@ -1186,24 +1190,11 @@ main(int ac, char **av) ssh_digest_free(md); conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); - if (options.local_command != NULL) { - debug3("expanding LocalCommand: %s", options.local_command); - cp = options.local_command; - options.local_command = percent_expand(cp, - "C", conn_hash_hex, - "L", shorthost, - "d", pw->pw_dir, - "h", host, - "l", thishost, - "n", host_arg, - "p", portstr, - "r", options.user, - "u", pw->pw_name, - (char *)NULL); - debug3("expanded LocalCommand: %s", options.local_command); - free(cp); - } - + /* + * Expand tokens in arguments. NB. LocalCommand is expanded later, + * after port-forwarding is set up, so it may pick up any local + * tunnel interface name allocated. + */ if (options.remote_command != NULL) { debug3("expanding RemoteCommand: %s", options.remote_command); cp = options.remote_command; @@ -1222,7 +1213,6 @@ main(int ac, char **av) free(cp); buffer_append(&command, options.remote_command, strlen(options.remote_command)); - } if (options.control_path != NULL) { @@ -1377,7 +1367,7 @@ main(int ac, char **av) } /* load options.identity_files */ - load_public_identity_files(); + load_public_identity_files(pw); /* optionally set the SSH_AUTHSOCKET_ENV_NAME varibale */ if (options.identity_agent && @@ -1441,7 +1431,7 @@ main(int ac, char **av) } skip_connect: - exit_status = ssh_session2(ssh); + exit_status = ssh_session2(ssh, pw); packet_close(); if (options.control_path != NULL && muxserver_sock != -1) @@ -1600,7 +1590,7 @@ ssh_init_stdio_forwarding(struct ssh *ssh) } static void -ssh_init_forwarding(struct ssh *ssh) +ssh_init_forwarding(struct ssh *ssh, char **ifname) { int success = 0; int i; @@ -1658,8 +1648,9 @@ ssh_init_forwarding(struct ssh *ssh) /* Initiate tunnel forwarding. */ if (options.tun_open != SSH_TUNMODE_NO) { - if (client_request_tun_fwd(ssh, options.tun_open, - options.tun_local, options.tun_remote) == -1) { + if ((*ifname = client_request_tun_fwd(ssh, + options.tun_open, options.tun_local, + options.tun_remote)) == NULL) { if (options.exit_on_forward_failure) fatal("Could not request tunnel forwarding."); else @@ -1774,14 +1765,35 @@ ssh_session2_open(struct ssh *ssh) } static int -ssh_session2(struct ssh *ssh) +ssh_session2(struct ssh *ssh, struct passwd *pw) { int id = -1; + char *cp, *tun_fwd_ifname = NULL; /* XXX should be pre-session */ if (!options.control_persist) ssh_init_stdio_forwarding(ssh); - ssh_init_forwarding(ssh); + + ssh_init_forwarding(ssh, &tun_fwd_ifname); + + if (options.local_command != NULL) { + debug3("expanding LocalCommand: %s", options.local_command); + cp = options.local_command; + options.local_command = percent_expand(cp, + "C", conn_hash_hex, + "L", shorthost, + "d", pw->pw_dir, + "h", host, + "l", thishost, + "n", host_arg, + "p", portstr, + "r", options.user, + "u", pw->pw_name, + "T", tun_fwd_ifname == NULL ? "NONE" : tun_fwd_ifname, + (char *)NULL); + debug3("expanded LocalCommand: %s", options.local_command); + free(cp); + } /* Start listening for multiplex clients */ if (!packet_get_mux()) @@ -1857,12 +1869,10 @@ ssh_session2(struct ssh *ssh) /* Loads all IdentityFile and CertificateFile keys */ static void -load_public_identity_files(void) +load_public_identity_files(struct passwd *pw) { - char *filename, *cp, thishost[NI_MAXHOST]; - char *pwdir = NULL, *pwname = NULL; + char *filename, *cp; struct sshkey *public; - struct passwd *pw; int i; u_int n_ids, n_certs; char *identity_files[SSH_MAX_IDENTITY_FILES]; @@ -1901,11 +1911,6 @@ load_public_identity_files(void) #endif /* ENABLE_PKCS11 */ if ((pw = getpwuid(original_real_uid)) == NULL) fatal("load_public_identity_files: getpwuid failed"); - pwname = xstrdup(pw->pw_name); - pwdir = xstrdup(pw->pw_dir); - if (gethostname(thishost, sizeof(thishost)) == -1) - fatal("load_public_identity_files: gethostname: %s", - strerror(errno)); for (i = 0; i < options.num_identity_files; i++) { if (n_ids >= SSH_MAX_IDENTITY_FILES || strcasecmp(options.identity_files[i], "none") == 0) { @@ -1915,8 +1920,8 @@ load_public_identity_files(void) } cp = tilde_expand_filename(options.identity_files[i], original_real_uid); - filename = percent_expand(cp, "d", pwdir, - "u", pwname, "l", thishost, "h", host, + filename = percent_expand(cp, "d", pw->pw_dir, + "u", pw->pw_name, "l", thishost, "h", host, "r", options.user, (char *)NULL); free(cp); public = key_load_public(filename, NULL); @@ -1961,8 +1966,8 @@ load_public_identity_files(void) for (i = 0; i < options.num_certificate_files; i++) { cp = tilde_expand_filename(options.certificate_files[i], original_real_uid); - filename = percent_expand(cp, "d", pwdir, - "u", pwname, "l", thishost, "h", host, + filename = percent_expand(cp, "d", pw->pw_dir, + "u", pw->pw_name, "l", thishost, "h", host, "r", options.user, (char *)NULL); free(cp); @@ -1995,11 +2000,6 @@ load_public_identity_files(void) memcpy(options.certificate_files, certificate_files, sizeof(certificate_files)); memcpy(options.certificates, certificates, sizeof(certificates)); - - explicit_bzero(pwname, strlen(pwname)); - free(pwname); - explicit_bzero(pwdir, strlen(pwdir)); - free(pwdir); } static void diff --git a/usr.bin/ssh/ssh_config.5 b/usr.bin/ssh/ssh_config.5 index c04701044a0..4d3fc3425a2 100644 --- a/usr.bin/ssh/ssh_config.5 +++ b/usr.bin/ssh/ssh_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.260 2017/10/21 23:06:24 millert Exp $ -.Dd $Mdocdate: October 21 2017 $ +.\" $OpenBSD: ssh_config.5,v 1.261 2017/10/23 05:08:00 djm Exp $ +.Dd $Mdocdate: October 23 2017 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -1713,6 +1713,16 @@ The original remote hostname, as given on the command line. The remote port. .It %r The remote username. +.It \&%T +The local +.Xr tun 4 +or +.Xr tap 4 +network interface assigned if +.Cm Tunnel +forwarding was requested, or +.Cm NONE +otherwise. .It %u The local username. .El @@ -1735,7 +1745,7 @@ and accept the tokens %%, %d, %h, %l, %r, and %u. .Pp .Cm LocalCommand -accepts the tokens %%, %C, %d, %h, %l, %n, %p, %r, and %u. +accepts the tokens %%, %C, %d, %h, %l, %n, %p, %r, %T, and %u. .Pp .Cm ProxyCommand accepts the tokens %%, %h, %p, and %r. |