From 54fd7cf2db5327f304825e0f9aaf9af5a490a75f Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 17 Sep 2007 12:04:08 +1000 Subject: - djm@cvs.openbsd.org 2007/09/04 03:21:03 [clientloop.c monitor.c monitor_fdpass.c monitor_fdpass.h] [monitor_wrap.c ssh.c] make file descriptor passing code return an error rather than call fatal() when it encounters problems, and use this to make session multiplexing masters survive slaves failing to pass all stdio FDs; ok markus@ --- ssh.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'ssh.c') diff --git a/ssh.c b/ssh.c index d3a7ffc9b..7f8ea0d17 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.301 2007/08/07 07:32:53 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.302 2007/09/04 03:21:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1426,9 +1426,10 @@ control_client(const char *path) if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) fatal("%s: msg_send", __func__); - mm_send_fd(sock, STDIN_FILENO); - mm_send_fd(sock, STDOUT_FILENO); - mm_send_fd(sock, STDERR_FILENO); + if (mm_send_fd(sock, STDIN_FILENO) == -1 || + mm_send_fd(sock, STDOUT_FILENO) == -1 || + mm_send_fd(sock, STDERR_FILENO) == -1) + fatal("%s: send fds failed", __func__); /* Wait for reply, so master has a chance to gather ttymodes */ buffer_clear(&m); -- cgit v1.2.3 From 67bd062b27f87047ec48e9a0dd9a47eec2891973 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 17 Sep 2007 12:06:57 +1000 Subject: - djm@cvs.openbsd.org 2007/09/04 11:15:56 [ssh.c sshconnect.c sshconnect.h] make ssh(1)'s ConnectTimeout option apply to both the TCP connection and SSH banner exchange (previously it just covered the TCP connection). This allows callers of ssh(1) to better detect and deal with stuck servers that accept a TCP connection but don't progress the protocol, and also makes ConnectTimeout useful for connections via a ProxyCommand; feedback and "looks ok" markus@ --- ChangeLog | 10 +++++- ssh.c | 15 ++++++--- sshconnect.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++------------ sshconnect.h | 6 ++-- 4 files changed, 107 insertions(+), 29 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index c0a927051..29f77d870 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,6 +25,14 @@ make file descriptor passing code return an error rather than call fatal() when it encounters problems, and use this to make session multiplexing masters survive slaves failing to pass all stdio FDs; ok markus@ + - djm@cvs.openbsd.org 2007/09/04 11:15:56 + [ssh.c sshconnect.c sshconnect.h] + make ssh(1)'s ConnectTimeout option apply to both the TCP connection and + SSH banner exchange (previously it just covered the TCP connection). + This allows callers of ssh(1) to better detect and deal with stuck servers + that accept a TCP connection but don't progress the protocol, and also + makes ConnectTimeout useful for connections via a ProxyCommand; + feedback and "looks ok" markus@ 20070914 - (dtucker) [openbsd-compat/bsd-asprintf.c] Plug mem leak in error path. @@ -3222,4 +3230,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4748 2007/09/17 02:04:08 djm Exp $ +$Id: ChangeLog,v 1.4749 2007/09/17 02:06:57 djm Exp $ diff --git a/ssh.c b/ssh.c index 7f8ea0d17..df3fc51ef 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.302 2007/09/04 03:21:03 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.303 2007/09/04 11:15:55 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -210,7 +210,7 @@ main(int ac, char **av) char *p, *cp, *line, buf[256]; struct stat st; struct passwd *pw; - int dummy; + int dummy, timeout_ms; extern int optind, optreset; extern char *optarg; struct servent *sp; @@ -681,9 +681,12 @@ main(int ac, char **av) if (options.control_path != NULL) control_client(options.control_path); + timeout_ms = options.connection_timeout * 1000; + /* Open a connection to the remote host. */ if (ssh_connect(host, &hostaddr, options.port, - options.address_family, options.connection_attempts, + options.address_family, options.connection_attempts, &timeout_ms, + options.tcp_keep_alive, #ifdef HAVE_CYGWIN options.use_privileged_port, #else @@ -692,6 +695,9 @@ main(int ac, char **av) options.proxy_command) != 0) exit(255); + if (timeout_ms > 0) + debug3("timeout: %d ms remain after connect", timeout_ms); + /* * If we successfully made the connection, load the host private key * in case we will need it later for combined rsa-rhosts @@ -767,7 +773,8 @@ main(int ac, char **av) signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ /* Log into the remote system. This never returns if the login fails. */ - ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw); + ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, + pw, timeout_ms); /* We no longer need the private host keys. Clear them now. */ if (sensitive_data.nkeys != 0) { diff --git a/sshconnect.c b/sshconnect.c index 7e3c9fff4..933df39fa 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.201 2007/08/23 03:23:26 djm Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.202 2007/09/04 11:15:55 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -77,6 +77,23 @@ extern pid_t proxy_command_pid; static int show_other_keys(const char *, Key *); static void warn_changed_key(Key *); +static void +ms_subtract_diff(struct timeval *start, int *ms) +{ + struct timeval diff, finish; + + gettimeofday(&finish, NULL); + timersub(&finish, start, &diff); + *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000); +} + +static void +ms_to_timeval(struct timeval *tv, int ms) +{ + tv->tv_sec = ms / 1000; + tv->tv_usec = (ms % 1000) * 1000; +} + /* * Connect to the given ssh server using a proxy command. */ @@ -223,30 +240,36 @@ ssh_create_socket(int privileged, struct addrinfo *ai) static int timeout_connect(int sockfd, const struct sockaddr *serv_addr, - socklen_t addrlen, int timeout) + socklen_t addrlen, int *timeoutp) { fd_set *fdset; - struct timeval tv; + struct timeval tv, t_start; socklen_t optlen; int optval, rc, result = -1; - if (timeout <= 0) - return (connect(sockfd, serv_addr, addrlen)); + gettimeofday(&t_start, NULL); + + if (*timeoutp <= 0) { + result = connect(sockfd, serv_addr, addrlen); + goto done; + } set_nonblock(sockfd); rc = connect(sockfd, serv_addr, addrlen); if (rc == 0) { unset_nonblock(sockfd); - return (0); + result = 0; + goto done; + } + if (errno != EINPROGRESS) { + result = -1; + goto done; } - if (errno != EINPROGRESS) - return (-1); fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS), sizeof(fd_mask)); FD_SET(sockfd, fdset); - tv.tv_sec = timeout; - tv.tv_usec = 0; + ms_to_timeval(&tv, *timeoutp); for (;;) { rc = select(sockfd + 1, NULL, fdset, NULL, &tv); @@ -285,6 +308,16 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr, } xfree(fdset); + + done: + if (result == 0 && *timeoutp > 0) { + ms_subtract_diff(&t_start, timeoutp); + if (*timeoutp <= 0) { + errno = ETIMEDOUT; + result = -1; + } + } + return (result); } @@ -301,8 +334,8 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr, */ int ssh_connect(const char *host, struct sockaddr_storage * hostaddr, - u_short port, int family, int connection_attempts, - int needpriv, const char *proxy_command) + u_short port, int family, int connection_attempts, int *timeout_ms, + int want_keepalive, int needpriv, const char *proxy_command) { int gaierr; int on = 1; @@ -355,7 +388,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, continue; if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, - options.connection_timeout) >= 0) { + timeout_ms) >= 0) { /* Successful connection. */ memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); break; @@ -382,7 +415,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, debug("Connection established."); /* Set SO_KEEPALIVE if requested. */ - if (options.tcp_keep_alive && + if (want_keepalive && setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)) < 0) error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); @@ -398,7 +431,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, * identification string. */ static void -ssh_exchange_identification(void) +ssh_exchange_identification(int timeout_ms) { char buf[256], remote_version[256]; /* must be same size! */ int remote_major, remote_minor, mismatch; @@ -406,16 +439,44 @@ ssh_exchange_identification(void) int connection_out = packet_get_connection_out(); int minor1 = PROTOCOL_MINOR_1; u_int i, n; + size_t len; + int fdsetsz, remaining, rc; + struct timeval t_start, t_remaining; + fd_set *fdset; + + fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask); + fdset = xcalloc(1, fdsetsz); /* Read other side's version identification. */ + remaining = timeout_ms; for (n = 0;;) { for (i = 0; i < sizeof(buf) - 1; i++) { - size_t len = atomicio(read, connection_in, &buf[i], 1); + if (timeout_ms > 0) { + gettimeofday(&t_start, NULL); + ms_to_timeval(&t_remaining, remaining); + FD_SET(connection_in, fdset); + rc = select(connection_in + 1, fdset, NULL, + fdset, &t_remaining); + ms_subtract_diff(&t_start, &remaining); + if (rc == 0 || remaining <= 0) + fatal("Connection timed out during " + "banner exchange"); + if (rc == -1) { + if (errno == EINTR) + continue; + fatal("ssh_exchange_identification: " + "select: %s", strerror(errno)); + } + } + + len = atomicio(read, connection_in, &buf[i], 1); if (len != 1 && errno == EPIPE) - fatal("ssh_exchange_identification: Connection closed by remote host"); + fatal("ssh_exchange_identification: " + "Connection closed by remote host"); else if (len != 1) - fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); + fatal("ssh_exchange_identification: " + "read: %.100s", strerror(errno)); if (buf[i] == '\r') { buf[i] = '\n'; buf[i + 1] = 0; @@ -426,7 +487,8 @@ ssh_exchange_identification(void) break; } if (++n > 65536) - fatal("ssh_exchange_identification: No banner received"); + fatal("ssh_exchange_identification: " + "No banner received"); } buf[sizeof(buf) - 1] = 0; if (strncmp(buf, "SSH-", 4) == 0) @@ -434,6 +496,7 @@ ssh_exchange_identification(void) debug("ssh_exchange_identification: %s", buf); } server_version_string = xstrdup(buf); + xfree(fdset); /* * Check that the versions match. In future this might accept @@ -946,7 +1009,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) */ void ssh_login(Sensitive *sensitive, const char *orighost, - struct sockaddr *hostaddr, struct passwd *pw) + struct sockaddr *hostaddr, struct passwd *pw, int timeout_ms) { char *host, *cp; char *server_user, *local_user; @@ -961,7 +1024,7 @@ ssh_login(Sensitive *sensitive, const char *orighost, *cp = (char)tolower(*cp); /* Exchange protocol version identification strings with the server. */ - ssh_exchange_identification(); + ssh_exchange_identification(timeout_ms); /* Put the connection into non-blocking mode. */ packet_set_nonblocking(); diff --git a/sshconnect.h b/sshconnect.h index 4e66bbffc..75bde1a4d 100644 --- a/sshconnect.h +++ b/sshconnect.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.h,v 1.23 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: sshconnect.h,v 1.24 2007/09/04 11:15:56 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -33,10 +33,10 @@ struct Sensitive { int ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int, - int, const char *); + int *, int, int, const char *); void -ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *); +ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *, int); int verify_host_key(char *, struct sockaddr *, Key *); -- cgit v1.2.3 From 32e42c74a54ba10bf6859f83b52e5b5e7d3c796a Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 2 Dec 2007 23:01:03 +1100 Subject: - dtucker@cvs.openbsd.org 2007/10/29 01:55:04 [ssh.c] Plug tiny mem leaks in ControlPath and ProxyCommand option processing; ok djm@ --- ChangeLog | 6 +++++- ssh.c | 11 ++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index b6eb45309..aff32e50e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,10 @@ [auth2-gss.c] Allow build without -DGSSAPI; ok deraadt@ (Id sync only, Portable already has the ifdefs) + - dtucker@cvs.openbsd.org 2007/10/29 01:55:04 + [ssh.c] + Plug tiny mem leaks in ControlPath and ProxyCommand option processing; + ok djm@ 20071030 - (djm) OpenBSD CVS Sync @@ -3425,4 +3429,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4797 2007/12/02 11:59:45 dtucker Exp $ +$Id: ChangeLog,v 1.4798 2007/12/02 12:01:03 dtucker Exp $ diff --git a/ssh.c b/ssh.c index df3fc51ef..802ba6870 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.303 2007/09/04 11:15:55 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.304 2007/10/29 01:55:04 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -658,11 +658,15 @@ main(int ac, char **av) } if (options.proxy_command != NULL && - strcmp(options.proxy_command, "none") == 0) + strcmp(options.proxy_command, "none") == 0) { + xfree(options.proxy_command); options.proxy_command = NULL; + } if (options.control_path != NULL && - strcmp(options.control_path, "none") == 0) + strcmp(options.control_path, "none") == 0) { + xfree(options.control_path); options.control_path = NULL; + } if (options.control_path != NULL) { char thishost[NI_MAXHOST]; @@ -672,6 +676,7 @@ main(int ac, char **av) snprintf(buf, sizeof(buf), "%d", options.port); cp = tilde_expand_filename(options.control_path, original_real_uid); + xfree(options.control_path); options.control_path = percent_expand(cp, "p", buf, "h", host, "r", options.user, "l", thishost, (char *)NULL); xfree(cp); -- cgit v1.2.3 From b776c856aa086b0e136b858d9484c155cb00a99b Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 2 Dec 2007 23:06:35 +1100 Subject: - dtucker@cvs.openbsd.org 2007/10/29 06:54:50 [ssh.c] Make LocalCommand work for Protocol 1 too; ok djm@ --- ChangeLog | 5 ++++- ssh.c | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index 2f7b5d0b5..818d71834 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,9 @@ - dtucker@cvs.openbsd.org 2007/10/29 06:51:59 [ssh_config.5] ProxyCommand and LocalCommand use the user's shell, not /bin/sh; ok djm@ + - dtucker@cvs.openbsd.org 2007/10/29 06:54:50 + [ssh.c] + Make LocalCommand work for Protocol 1 too; ok djm@ 20071030 - (djm) OpenBSD CVS Sync @@ -3437,4 +3440,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4800 2007/12/02 12:05:09 dtucker Exp $ +$Id: ChangeLog,v 1.4801 2007/12/02 12:06:35 dtucker Exp $ diff --git a/ssh.c b/ssh.c index 802ba6870..365321829 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.304 2007/10/29 01:55:04 dtucker Exp $ */ +/* $OpenBSD: ssh.c,v 1.305 2007/10/29 06:54:50 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1002,6 +1002,11 @@ ssh_session(void) /* Initiate port forwardings. */ ssh_init_forwarding(); + /* Execute a local command */ + if (options.local_command != NULL && + options.permit_local_command) + ssh_local_cmd(options.local_command); + /* If requested, let ssh continue in the background. */ if (fork_after_authentication_flag) if (daemon(1, 1) < 0) -- cgit v1.2.3 From b4fbbc6850fdcee5a96d799efbe74393969577fc Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 2 Dec 2007 23:16:32 +1100 Subject: - deraadt@cvs.openbsd.org 2007/11/03 01:24:06 [ssh.c] bz #1377: getpwuid results were being clobbered by another getpw* call inside tilde_expand_filename(); save the data we need carefully ok djm --- ChangeLog | 7 ++++++- ssh.c | 13 ++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index d7345a85a..0d820cae7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,11 @@ [clientloop.c] fix memory leak in process_cmdline(), patch from Jan.Pechanec AT Sun.COM; ok dtucker@ + - deraadt@cvs.openbsd.org 2007/11/03 01:24:06 + [ssh.c] + bz #1377: getpwuid results were being clobbered by another getpw* call + inside tilde_expand_filename(); save the data we need carefully + ok djm 20071030 - (djm) OpenBSD CVS Sync @@ -3447,4 +3452,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4803 2007/12/02 12:12:30 dtucker Exp $ +$Id: ChangeLog,v 1.4804 2007/12/02 12:16:32 dtucker Exp $ diff --git a/ssh.c b/ssh.c index 365321829..f9c6252d3 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.305 2007/10/29 06:54:50 dtucker Exp $ */ +/* $OpenBSD: ssh.c,v 1.306 2007/11/03 01:24:06 deraadt Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1231,6 +1231,7 @@ static void load_public_identity_files(void) { char *filename, *cp, thishost[NI_MAXHOST]; + char *pwdir = NULL, *pwname = NULL; int i = 0; Key *public; struct passwd *pw; @@ -1259,14 +1260,16 @@ load_public_identity_files(void) #endif /* SMARTCARD */ if ((pw = getpwuid(original_real_uid)) == NULL) fatal("load_public_identity_files: getpwuid failed"); + pwname = strdup(pw->pw_name); + pwdir = strdup(pw->pw_dir); if (gethostname(thishost, sizeof(thishost)) == -1) fatal("load_public_identity_files: gethostname: %s", strerror(errno)); for (; i < options.num_identity_files; i++) { cp = tilde_expand_filename(options.identity_files[i], original_real_uid); - filename = percent_expand(cp, "d", pw->pw_dir, - "u", pw->pw_name, "l", thishost, "h", host, + filename = percent_expand(cp, "d", pwdir, + "u", pwname, "l", thishost, "h", host, "r", options.user, (char *)NULL); xfree(cp); public = key_load_public(filename, NULL); @@ -1276,6 +1279,10 @@ load_public_identity_files(void) options.identity_files[i] = filename; options.identity_keys[i] = public; } + bzero(pwname, strlen(pwname)); + free(pwname); + bzero(pwdir, strlen(pwdir)); + free(pwdir); } static void -- cgit v1.2.3 From e143f062ba1ee0d38c583acd6a8fbc8e679f45a3 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 2 Dec 2007 23:21:16 +1100 Subject: - dtucker@cvs.openbsd.org 2007/11/03 02:00:32 [ssh.c] Use xstrdup/xfree when saving pwname and pwdir; ok deraadt@ --- ChangeLog | 5 ++++- ssh.c | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index 0d820cae7..f3c118cf7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -35,6 +35,9 @@ bz #1377: getpwuid results were being clobbered by another getpw* call inside tilde_expand_filename(); save the data we need carefully ok djm + - dtucker@cvs.openbsd.org 2007/11/03 02:00:32 + [ssh.c] + Use xstrdup/xfree when saving pwname and pwdir; ok deraadt@ 20071030 - (djm) OpenBSD CVS Sync @@ -3452,4 +3455,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4804 2007/12/02 12:16:32 dtucker Exp $ +$Id: ChangeLog,v 1.4805 2007/12/02 12:21:16 dtucker Exp $ diff --git a/ssh.c b/ssh.c index f9c6252d3..7e23acff6 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.306 2007/11/03 01:24:06 deraadt Exp $ */ +/* $OpenBSD: ssh.c,v 1.307 2007/11/03 02:00:32 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1260,8 +1260,8 @@ load_public_identity_files(void) #endif /* SMARTCARD */ if ((pw = getpwuid(original_real_uid)) == NULL) fatal("load_public_identity_files: getpwuid failed"); - pwname = strdup(pw->pw_name); - pwdir = strdup(pw->pw_dir); + 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)); @@ -1280,9 +1280,9 @@ load_public_identity_files(void) options.identity_keys[i] = public; } bzero(pwname, strlen(pwname)); - free(pwname); + xfree(pwname); bzero(pwdir, strlen(pwdir)); - free(pwdir); + xfree(pwdir); } static void -- cgit v1.2.3 From 06321f5d1d328649913a1ee468d59149974e708f Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 2 Dec 2007 23:22:52 +1100 Subject: - deraadt@cvs.openbsd.org 2007/11/03 02:03:49 [ssh.c] avoid errno trashing in signal handler; ok dtucker --- ChangeLog | 5 ++++- ssh.c | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index f3c118cf7..8609e2407 100644 --- a/ChangeLog +++ b/ChangeLog @@ -38,6 +38,9 @@ - dtucker@cvs.openbsd.org 2007/11/03 02:00:32 [ssh.c] Use xstrdup/xfree when saving pwname and pwdir; ok deraadt@ + - deraadt@cvs.openbsd.org 2007/11/03 02:03:49 + [ssh.c] + avoid errno trashing in signal handler; ok dtucker 20071030 - (djm) OpenBSD CVS Sync @@ -3455,4 +3458,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4805 2007/12/02 12:21:16 dtucker Exp $ +$Id: ChangeLog,v 1.4806 2007/12/02 12:22:52 dtucker Exp $ diff --git a/ssh.c b/ssh.c index 7e23acff6..e8906e00d 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.307 2007/11/03 02:00:32 dtucker Exp $ */ +/* $OpenBSD: ssh.c,v 1.308 2007/11/03 02:03:49 deraadt Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1294,8 +1294,12 @@ control_client_sighandler(int signo) static void control_client_sigrelay(int signo) { + int save_errno = errno; + if (control_server_pid > 1) kill(control_server_pid, signo); + + errno = save_errno; } static int -- cgit v1.2.3 From d39a3cffc907b54e69c3f607c1f0b74e931696fd Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Sun, 10 Feb 2008 22:23:18 +1100 Subject: - djm@cvs.openbsd.org 2008/01/19 20:51:26 [ssh.c] ignore SIGPIPE in multiplex client mode - we can receive this if the server runs out of fds on us midway. Report and patch from gregory_shively AT fanniemae.com --- ChangeLog | 7 ++++++- ssh.c | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index 14a146dd3..0cd0ce98f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,11 @@ [clientloop.c] fd leak on session multiplexing error path. Report and patch from gregory_shively AT fanniemae.com + - djm@cvs.openbsd.org 2008/01/19 20:51:26 + [ssh.c] + ignore SIGPIPE in multiplex client mode - we can receive this if the + server runs out of fds on us midway. Report and patch from + gregory_shively AT fanniemae.com 20080119 - (djm) Silence noice from expr in ssh-copy-id; patch from @@ -3542,4 +3547,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4822 2008/02/10 11:22:53 djm Exp $ +$Id: ChangeLog,v 1.4823 2008/02/10 11:23:18 djm Exp $ diff --git a/ssh.c b/ssh.c index e8906e00d..fe2f1adfb 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.308 2007/11/03 02:03:49 deraadt Exp $ */ +/* $OpenBSD: ssh.c,v 1.309 2008/01/19 20:51:26 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1393,6 +1393,8 @@ control_client(const char *path) if (options.forward_agent) flags |= SSHMUX_FLAG_AGENT_FWD; + signal(SIGPIPE, SIG_IGN); + buffer_init(&m); /* Send our command to server */ -- cgit v1.2.3 From bfaaf960a0204d5ee8ed75af05104737a54b4a52 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 28 Feb 2008 19:13:52 +1100 Subject: - (dtucker) [includes.h ssh-add.c ssh-agent.c ssh-keygen.c ssh.c sshd.c openbsd-compat/openssl-compat.{c,h}] Bug #1437 Move the OpenSSL compat header to after OpenSSL headers, since some versions of OpenSSL have SSLeay_add_all_algorithms as a macro already. --- ChangeLog | 6 +++++- includes.h | 1 - openbsd-compat/openssl-compat.c | 6 ++++-- openbsd-compat/openssl-compat.h | 6 +++--- ssh-add.c | 1 + ssh-agent.c | 1 + ssh-keygen.c | 1 + ssh.c | 1 + sshd.c | 2 ++ 9 files changed, 18 insertions(+), 7 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index 0bd8d901a..72261d650 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ 20080228 - (dtucker) [configure.ac] Add -fstack-protector to LDFLAGS too, fixes linking problems on AIX with gcc 4.1.x. + - (dtucker) [includes.h ssh-add.c ssh-agent.c ssh-keygen.c ssh.c sshd.c + openbsd-compat/openssl-compat.{c,h}] Bug #1437 Move the OpenSSL compat + header to after OpenSSL headers, since some versions of OpenSSL have + SSLeay_add_all_algorithms as a macro already. 20080225 - (dtucker) [openbsd-compat/fake-rfc2553.h] rename ssh_gai_strerror hack @@ -3631,4 +3635,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4842 2008/02/28 04:01:13 dtucker Exp $ +$Id: ChangeLog,v 1.4843 2008/02/28 08:13:52 dtucker Exp $ diff --git a/includes.h b/includes.h index af231a9b3..9fcf1b023 100644 --- a/includes.h +++ b/includes.h @@ -166,7 +166,6 @@ #include "platform.h" #include "openbsd-compat/openbsd-compat.h" #include "openbsd-compat/bsd-nextstep.h" -#include "openbsd-compat/openssl-compat.h" #include "entropy.h" diff --git a/openbsd-compat/openssl-compat.c b/openbsd-compat/openssl-compat.c index 9c9cdb98e..49238ba80 100644 --- a/openbsd-compat/openssl-compat.c +++ b/openbsd-compat/openssl-compat.c @@ -1,4 +1,4 @@ -/* $Id: openssl-compat.c,v 1.5 2008/02/25 10:13:47 dtucker Exp $ */ +/* $Id: openssl-compat.c,v 1.6 2008/02/28 08:13:52 dtucker Exp $ */ /* * Copyright (c) 2005 Darren Tucker @@ -16,13 +16,15 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define SSH_DONT_OVERLOAD_OPENSSL_FUNCS #include "includes.h" #ifdef USE_OPENSSL_ENGINE # include #endif +#define SSH_DONT_OVERLOAD_OPENSSL_FUNCS +#include "openssl-compat.h" + #ifdef SSH_OLD_EVP int ssh_EVP_CipherInit(EVP_CIPHER_CTX *evp, const EVP_CIPHER *type, diff --git a/openbsd-compat/openssl-compat.h b/openbsd-compat/openssl-compat.h index f1d2f19fc..f53695aa8 100644 --- a/openbsd-compat/openssl-compat.h +++ b/openbsd-compat/openssl-compat.h @@ -1,4 +1,4 @@ -/* $Id: openssl-compat.h,v 1.10 2007/06/14 13:47:31 dtucker Exp $ */ +/* $Id: openssl-compat.h,v 1.11 2008/02/28 08:13:52 dtucker Exp $ */ /* * Copyright (c) 2005 Darren Tucker @@ -79,8 +79,8 @@ extern const EVP_CIPHER *evp_acss(void); # ifdef SSLeay_add_all_algorithms # undef SSLeay_add_all_algorithms # endif -# define SSLeay_add_all_algorithms() ssh_SSLeay_add_all_algorithms() -#endif +# define SSLeay_add_all_algorithms() ssh_SSLeay_add_all_algorithms() +# endif int ssh_EVP_CipherInit(EVP_CIPHER_CTX *, const EVP_CIPHER *, unsigned char *, unsigned char *, int); diff --git a/ssh-add.c b/ssh-add.c index 7f654a97e..7a43282f2 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -42,6 +42,7 @@ #include #include +#include "openbsd-compat/openssl-compat.h" #include #include diff --git a/ssh-agent.c b/ssh-agent.c index f17948349..6f8727b33 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -51,6 +51,7 @@ #include #include +#include "openbsd-compat/openssl-compat.h" #include #include diff --git a/ssh-keygen.c b/ssh-keygen.c index adacbff0b..69b16e6f5 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -21,6 +21,7 @@ #include #include +#include "openbsd-compat/openssl-compat.h" #include #include diff --git a/ssh.c b/ssh.c index fe2f1adfb..2ed76c9a1 100644 --- a/ssh.c +++ b/ssh.c @@ -72,6 +72,7 @@ #include #include +#include "openbsd-compat/openssl-compat.h" #include "xmalloc.h" #include "ssh.h" diff --git a/sshd.c b/sshd.c index 27c38ba53..9144bbaea 100644 --- a/sshd.c +++ b/sshd.c @@ -75,6 +75,8 @@ #include #include #include +#include "openbsd-compat/openssl-compat.h" + #ifdef HAVE_SECUREWARE #include #include -- cgit v1.2.3 From b84886ba3e362f54b70aefcbe1aa10606309b7d7 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 19 May 2008 15:05:07 +1000 Subject: - djm@cvs.openbsd.org 2008/05/08 12:02:23 [auth-options.c auth1.c channels.c channels.h clientloop.c gss-serv.c] [monitor.c monitor_wrap.c nchan.c servconf.c serverloop.c session.c] [ssh.c sshd.c] Implement a channel success/failure status confirmation callback mechanism. Each channel maintains a queue of callbacks, which will be drained in order (RFC4253 guarantees confirm messages are not reordered within an channel). Also includes a abandonment callback to clean up if a channel is closed without sending confirmation messages. This probably shouldn't happen in compliant implementations, but it could be abused to leak memory. ok markus@ (as part of a larger diff) --- ChangeLog | 15 +++++++++++- auth-options.c | 3 ++- auth1.c | 3 ++- channels.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- channels.h | 26 +++++++++++++++++---- clientloop.c | 10 +++++--- gss-serv.c | 3 ++- monitor.c | 3 ++- monitor_wrap.c | 3 ++- nchan.c | 3 ++- servconf.c | 3 ++- serverloop.c | 6 +++-- session.c | 3 ++- ssh.c | 6 +++-- sshd.c | 3 ++- 15 files changed, 132 insertions(+), 31 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index e7fd87ba8..567222e96 100644 --- a/ChangeLog +++ b/ChangeLog @@ -62,6 +62,19 @@ [bufaux.c buffer.h channels.c packet.c packet.h] avoid extra malloc/copy/free when receiving data over the net; ~10% speedup for localhost-scp; ok djm@ + - djm@cvs.openbsd.org 2008/05/08 12:02:23 + [auth-options.c auth1.c channels.c channels.h clientloop.c gss-serv.c] + [monitor.c monitor_wrap.c nchan.c servconf.c serverloop.c session.c] + [ssh.c sshd.c] + Implement a channel success/failure status confirmation callback + mechanism. Each channel maintains a queue of callbacks, which will + be drained in order (RFC4253 guarantees confirm messages are not + reordered within an channel). + Also includes a abandonment callback to clean up if a channel is + closed without sending confirmation messages. This probably + shouldn't happen in compliant implementations, but it could be + abused to leak memory. + ok markus@ (as part of a larger diff) 20080403 - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- @@ -3922,4 +3935,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4919 2008/05/19 04:59:37 djm Exp $ +$Id: ChangeLog,v 1.4920 2008/05/19 05:05:07 djm Exp $ diff --git a/auth-options.c b/auth-options.c index 6e2256961..3a6c3c0f3 100644 --- a/auth-options.c +++ b/auth-options.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-options.c,v 1.41 2008/03/26 21:28:14 djm Exp $ */ +/* $OpenBSD: auth-options.c,v 1.42 2008/05/08 12:02:23 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -20,6 +20,7 @@ #include #include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "match.h" #include "log.h" diff --git a/auth1.c b/auth1.c index c17cc9133..b5798f634 100644 --- a/auth1.c +++ b/auth1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth1.c,v 1.71 2007/09/21 08:15:29 djm Exp $ */ +/* $OpenBSD: auth1.c,v 1.72 2008/05/08 12:02:23 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -20,6 +20,7 @@ #include #include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "rsa.h" #include "ssh1.h" diff --git a/channels.c b/channels.c index 05c23e59c..b5e28dabf 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.274 2008/05/08 06:59:01 markus Exp $ */ +/* $OpenBSD: channels.c,v 1.275 2008/05/08 12:02:23 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -61,6 +61,7 @@ #include #include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "ssh.h" #include "ssh1.h" @@ -319,10 +320,11 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, c->single_connection = 0; c->detach_user = NULL; c->detach_close = 0; - c->confirm = NULL; - c->confirm_ctx = NULL; + c->open_confirm = NULL; + c->open_confirm_ctx = NULL; c->input_filter = NULL; c->output_filter = NULL; + TAILQ_INIT(&c->status_confirms); debug("channel %d: new [%s]", found, remote_name); return c; } @@ -379,6 +381,7 @@ channel_free(Channel *c) { char *s; u_int i, n; + struct channel_confirm *cc; for (n = 0, i = 0; i < channels_alloc; i++) if (channels[i]) @@ -402,6 +405,13 @@ channel_free(Channel *c) xfree(c->remote_name); c->remote_name = NULL; } + while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { + if (cc->abandon_cb != NULL) + cc->abandon_cb(c, cc->ctx); + TAILQ_REMOVE(&c->status_confirms, cc, entry); + bzero(cc, sizeof(*cc)); + xfree(cc); + } channels[c->self] = NULL; xfree(c); } @@ -660,16 +670,33 @@ channel_request_start(int id, char *service, int wantconfirm) } void -channel_register_confirm(int id, channel_callback_fn *fn, void *ctx) +channel_register_status_confirm(int id, channel_confirm_cb *cb, + channel_confirm_abandon_cb *abandon_cb, void *ctx) +{ + struct channel_confirm *cc; + Channel *c; + + if ((c = channel_lookup(id)) == NULL) + fatal("channel_register_expect: %d: bad id", id); + + cc = xmalloc(sizeof(*cc)); + cc->cb = cb; + cc->abandon_cb = abandon_cb; + cc->ctx = ctx; + TAILQ_INSERT_TAIL(&c->status_confirms, cc, entry); +} + +void +channel_register_open_confirm(int id, channel_callback_fn *fn, void *ctx) { Channel *c = channel_lookup(id); if (c == NULL) { - logit("channel_register_comfirm: %d: bad id", id); + logit("channel_register_open_comfirm: %d: bad id", id); return; } - c->confirm = fn; - c->confirm_ctx = ctx; + c->open_confirm = fn; + c->open_confirm_ctx = ctx; } void @@ -2209,9 +2236,9 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) if (compat20) { c->remote_window = packet_get_int(); c->remote_maxpacket = packet_get_int(); - if (c->confirm) { + if (c->open_confirm) { debug2("callback start"); - c->confirm(c->self, c->confirm_ctx); + c->open_confirm(c->self, c->open_confirm_ctx); debug2("callback done"); } debug2("channel %d: open confirm rwindow %u rmax %u", c->self, @@ -2328,6 +2355,34 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt) xfree(host); } +/* ARGSUSED */ +void +channel_input_status_confirm(int type, u_int32_t seq, void *ctxt) +{ + Channel *c; + struct channel_confirm *cc; + int remote_id; + + /* Reset keepalive timeout */ + keep_alive_timeouts = 0; + + remote_id = packet_get_int(); + packet_check_eom(); + + debug2("channel_input_confirm: type %d id %d", type, remote_id); + + if ((c = channel_lookup(remote_id)) == NULL) { + logit("channel_input_success_failure: %d: unknown", remote_id); + return; + } + ; + if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) + return; + cc->cb(type, c, cc->ctx); + TAILQ_REMOVE(&c->status_confirms, cc, entry); + bzero(cc, sizeof(*cc)); + xfree(cc); +} /* -- tcp forwarding */ diff --git a/channels.h b/channels.h index b632a86af..46cde0309 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.89 2007/06/11 09:14:00 markus Exp $ */ +/* $OpenBSD: channels.h,v 1.90 2008/05/08 12:02:23 djm Exp $ */ /* * Author: Tatu Ylonen @@ -64,6 +64,17 @@ typedef void channel_callback_fn(int, void *); typedef int channel_infilter_fn(struct Channel *, char *, int); typedef u_char *channel_outfilter_fn(struct Channel *, u_char **, u_int *); +/* Channel success/failure callbacks */ +typedef void channel_confirm_cb(int, struct Channel *, void *); +typedef void channel_confirm_abandon_cb(struct Channel *, void *); +struct channel_confirm { + TAILQ_ENTRY(channel_confirm) entry; + channel_confirm_cb *cb; + channel_confirm_abandon_cb *abandon_cb; + void *ctx; +}; +TAILQ_HEAD(channel_confirms, channel_confirm); + struct Channel { int type; /* channel type/state */ int self; /* my own channel identifier */ @@ -104,10 +115,11 @@ struct Channel { char *ctype; /* type */ /* callback */ - channel_callback_fn *confirm; - void *confirm_ctx; + channel_callback_fn *open_confirm; + void *open_confirm_ctx; channel_callback_fn *detach_user; int detach_close; + struct channel_confirms status_confirms; /* filter */ channel_infilter_fn *input_filter; @@ -170,8 +182,11 @@ void channel_stop_listening(void); void channel_send_open(int); void channel_request_start(int, char *, int); void channel_register_cleanup(int, channel_callback_fn *, int); -void channel_register_confirm(int, channel_callback_fn *, void *); -void channel_register_filter(int, channel_infilter_fn *, channel_outfilter_fn *); +void channel_register_open_confirm(int, channel_callback_fn *, void *); +void channel_register_filter(int, channel_infilter_fn *, + channel_outfilter_fn *); +void channel_register_status_confirm(int, channel_confirm_cb *, + channel_confirm_abandon_cb *, void *); void channel_cancel_cleanup(int); int channel_close_fd(int *); void channel_send_window_changes(void); @@ -188,6 +203,7 @@ void channel_input_open_confirmation(int, u_int32_t, void *); void channel_input_open_failure(int, u_int32_t, void *); void channel_input_port_open(int, u_int32_t, void *); void channel_input_window_adjust(int, u_int32_t, void *); +void channel_input_status_confirm(int, u_int32_t, void *); /* file descriptor handling (read/write) */ diff --git a/clientloop.c b/clientloop.c index 8a40bc71e..edd801440 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.188 2008/02/22 20:44:02 dtucker Exp $ */ +/* $OpenBSD: clientloop.c,v 1.189 2008/05/08 12:02:23 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -86,6 +86,7 @@ #include #include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "ssh.h" #include "ssh1.h" @@ -700,7 +701,7 @@ client_extra_session2_setup(int id, void *arg) cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env, client_subsystem_reply); - c->confirm_ctx = NULL; + c->open_confirm_ctx = NULL; buffer_free(&cctx->cmd); xfree(cctx->term); if (cctx->env != NULL) { @@ -940,7 +941,8 @@ client_process_control(fd_set *readset) debug3("%s: channel_new: %d", __func__, c->self); channel_send_open(c->self); - channel_register_confirm(c->self, client_extra_session2_setup, cctx); + channel_register_open_confirm(c->self, + client_extra_session2_setup, cctx); } static void @@ -2068,6 +2070,8 @@ client_init_dispatch_20(void) dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req); dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); + dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm); + dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm); dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request); /* rekeying */ diff --git a/gss-serv.c b/gss-serv.c index bc498fd47..2ec7ea19c 100644 --- a/gss-serv.c +++ b/gss-serv.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gss-serv.c,v 1.21 2007/06/12 08:20:00 djm Exp $ */ +/* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */ /* * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. @@ -35,6 +35,7 @@ #include #include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "buffer.h" #include "key.h" diff --git a/monitor.c b/monitor.c index cc0e0fcac..04f6924b6 100644 --- a/monitor.c +++ b/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.94 2007/10/29 04:08:08 dtucker Exp $ */ +/* $OpenBSD: monitor.c,v 1.95 2008/05/08 12:02:23 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -51,6 +51,7 @@ #include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "ssh.h" #include "key.h" diff --git a/monitor_wrap.c b/monitor_wrap.c index e895f1924..72fd5c83c 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.60 2007/10/29 04:08:08 dtucker Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.61 2008/05/08 12:02:23 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -41,6 +41,7 @@ #include #include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "ssh.h" #include "dh.h" diff --git a/nchan.c b/nchan.c index ad461f4af..0d0faddb3 100644 --- a/nchan.c +++ b/nchan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nchan.c,v 1.57 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: nchan.c,v 1.58 2008/05/08 12:02:23 djm Exp $ */ /* * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. * @@ -32,6 +32,7 @@ #include #include +#include "openbsd-compat/sys-queue.h" #include "ssh1.h" #include "ssh2.h" #include "buffer.h" diff --git a/servconf.c b/servconf.c index e6d49099b..b8a968aa3 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.178 2008/05/07 05:49:37 pyr Exp $ */ +/* $OpenBSD: servconf.c,v 1.179 2008/05/08 12:02:23 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -24,6 +24,7 @@ #include #include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "ssh.h" #include "log.h" diff --git a/serverloop.c b/serverloop.c index bf3f9c9f0..20991c3ce 100644 --- a/serverloop.c +++ b/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.148 2008/02/22 20:44:02 dtucker Exp $ */ +/* $OpenBSD: serverloop.c,v 1.149 2008/05/08 12:02:23 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -56,6 +56,7 @@ #include #include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "packet.h" #include "buffer.h" @@ -1188,8 +1189,9 @@ server_init_dispatch_20(void) dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req); dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); + dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm); + dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm); /* client_alive */ - dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive); dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive); dispatch_set(SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive); /* rekeying */ diff --git a/session.c b/session.c index 16e455588..ca04a4532 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.235 2008/05/07 05:49:37 pyr Exp $ */ +/* $OpenBSD: session.c,v 1.236 2008/05/08 12:02:23 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -59,6 +59,7 @@ #include #include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "ssh.h" #include "ssh1.h" diff --git a/ssh.c b/ssh.c index 2ed76c9a1..b144a7130 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.309 2008/01/19 20:51:26 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.310 2008/05/08 12:02:23 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -73,6 +73,7 @@ #include #include #include "openbsd-compat/openssl-compat.h" +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "ssh.h" @@ -1195,7 +1196,8 @@ ssh_session2_open(void) channel_send_open(c->self); if (!no_shell_flag) - channel_register_confirm(c->self, ssh_session2_setup, NULL); + channel_register_open_confirm(c->self, + ssh_session2_setup, NULL); return c->self; } diff --git a/sshd.c b/sshd.c index 796310b03..aefbaaa42 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.356 2008/04/13 00:22:17 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.357 2008/05/08 12:02:23 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -54,6 +54,7 @@ # include #endif #include "openbsd-compat/sys-tree.h" +#include "openbsd-compat/sys-queue.h" #include #include -- cgit v1.2.3 From 5771ed7d1b5af26bc991151ab977e77bf1e87666 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 19 May 2008 15:35:33 +1000 Subject: - djm@cvs.openbsd.org 2008/05/08 13:06:11 [clientloop.c clientloop.h ssh.c] Use new channel status confirmation callback system to properly deal with "important" channel requests that fail, in particular command exec, shell and subsystem requests. Previously we would optimistically assume that the requests would always succeed, which could cause hangs if they did not (e.g. when the server runs out of fds) or were unimplemented by the server (bz #1384) Also, properly report failing multiplex channel requests via the mux client stderr (subject to LogLevel in the mux master) - better than silently failing. most bits ok markus@ (as part of a larger diff) --- ChangeLog | 14 +++++++- clientloop.c | 106 ++++++++++++++++++++++++++++++++++++++++------------------- clientloop.h | 4 +-- ssh.c | 19 ++--------- 4 files changed, 90 insertions(+), 53 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index 5ea4afcac..bd6b640b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -92,6 +92,18 @@ sending channel errors instead of than exiting with fatal(). bz#1090; MaxSessions config bits and manpage from junyer AT gmail.com ok markus@ + - djm@cvs.openbsd.org 2008/05/08 13:06:11 + [clientloop.c clientloop.h ssh.c] + Use new channel status confirmation callback system to properly deal + with "important" channel requests that fail, in particular command exec, + shell and subsystem requests. Previously we would optimistically assume + that the requests would always succeed, which could cause hangs if they + did not (e.g. when the server runs out of fds) or were unimplemented by + the server (bz #1384) + Also, properly report failing multiplex channel requests via the mux + client stderr (subject to LogLevel in the mux master) - better than + silently failing. + most bits ok markus@ (as part of a larger diff) 20080403 - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- @@ -3952,4 +3964,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4923 2008/05/19 05:34:50 djm Exp $ +$Id: ChangeLog,v 1.4924 2008/05/19 05:36:08 djm Exp $ diff --git a/clientloop.c b/clientloop.c index edd801440..c40f2c303 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.189 2008/05/08 12:02:23 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.190 2008/05/08 13:06:10 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -173,6 +173,11 @@ struct confirm_ctx { char **env; }; +struct channel_reply_ctx { + const char *request_type; + int id, do_close; +}; + /*XXX*/ extern Kex *xxx_kex; @@ -645,25 +650,60 @@ client_process_net_input(fd_set *readset) } static void -client_subsystem_reply(int type, u_int32_t seq, void *ctxt) +client_status_confirm(int type, Channel *c, void *ctx) { - int id; - Channel *c; + struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx; + char errmsg[256]; + int tochan; + + /* XXX supress on mux _client_ quietmode */ + tochan = options.log_level >= SYSLOG_LEVEL_ERROR && + c->ctl_fd != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; + + if (type == SSH2_MSG_CHANNEL_SUCCESS) { + debug2("%s request accepted on channel %d", + cr->request_type, c->self); + } else if (type == SSH2_MSG_CHANNEL_FAILURE) { + if (tochan) { + snprintf(errmsg, sizeof(errmsg), + "%s request failed\r\n", cr->request_type); + } else { + snprintf(errmsg, sizeof(errmsg), + "%s request failed on channel %d", + cr->request_type, c->self); + } + /* If error occurred on primary session channel, then exit */ + if (cr->do_close && c->self == session_ident) + fatal("%s", errmsg); + /* If error occurred on mux client, append to their stderr */ + if (tochan) + buffer_append(&c->extended, errmsg, strlen(errmsg)); + else + error("%s", errmsg); + if (cr->do_close) { + chan_read_failed(c); + chan_write_failed(c); + } + } + xfree(cr); +} - id = packet_get_int(); - packet_check_eom(); +static void +client_abandon_status_confirm(Channel *c, void *ctx) +{ + xfree(ctx); +} - if ((c = channel_lookup(id)) == NULL) { - error("%s: no channel for id %d", __func__, id); - return; - } +static void +client_expect_confirm(int id, const char *request, int do_close) +{ + struct channel_reply_ctx *cr = xmalloc(sizeof(*cr)); - if (type == SSH2_MSG_CHANNEL_SUCCESS) - debug2("Request suceeded on channel %d", id); - else if (type == SSH2_MSG_CHANNEL_FAILURE) { - error("Request failed on channel %d", id); - channel_free(c); - } + cr->request_type = request; + cr->do_close = do_close; + + channel_register_status_confirm(id, client_status_confirm, + client_abandon_status_confirm, cr); } static void @@ -698,8 +738,7 @@ client_extra_session2_setup(int id, void *arg) } client_session2_setup(id, cctx->want_tty, cctx->want_subsys, - cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env, - client_subsystem_reply); + cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); c->open_confirm_ctx = NULL; buffer_free(&cctx->cmd); @@ -1366,7 +1405,9 @@ client_process_buffered_input_packets(void) static int simple_escape_filter(Channel *c, char *buf, int len) { - /* XXX we assume c->extended is writeable */ + if (c->extended_usage != CHAN_EXTENDED_WRITE) + return 0; + return process_escapes(&c->input, &c->output, &c->extended, buf, len); } @@ -1962,8 +2003,7 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt) void client_session2_setup(int id, int want_tty, int want_subsystem, - const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env, - dispatch_fn *subsys_repl) + const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env) { int len; Channel *c = NULL; @@ -1981,7 +2021,8 @@ client_session2_setup(int id, int want_tty, int want_subsystem, if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) memset(&ws, 0, sizeof(ws)); - channel_request_start(id, "pty-req", 0); + channel_request_start(id, "pty-req", 1); + client_expect_confirm(id, "PTY allocation", 0); packet_put_cstring(term != NULL ? term : ""); packet_put_int((u_int)ws.ws_col); packet_put_int((u_int)ws.ws_row); @@ -2036,22 +2077,21 @@ client_session2_setup(int id, int want_tty, int want_subsystem, if (len > 900) len = 900; if (want_subsystem) { - debug("Sending subsystem: %.*s", len, (u_char*)buffer_ptr(cmd)); - channel_request_start(id, "subsystem", subsys_repl != NULL); - if (subsys_repl != NULL) { - /* register callback for reply */ - /* XXX we assume that client_loop has already been called */ - dispatch_set(SSH2_MSG_CHANNEL_FAILURE, subsys_repl); - dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, subsys_repl); - } + debug("Sending subsystem: %.*s", + len, (u_char*)buffer_ptr(cmd)); + channel_request_start(id, "subsystem", 1); + client_expect_confirm(id, "subsystem", 1); } else { - debug("Sending command: %.*s", len, (u_char*)buffer_ptr(cmd)); - channel_request_start(id, "exec", 0); + debug("Sending command: %.*s", + len, (u_char*)buffer_ptr(cmd)); + channel_request_start(id, "exec", 1); + client_expect_confirm(id, "exec", 1); } packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); packet_send(); } else { - channel_request_start(id, "shell", 0); + channel_request_start(id, "shell", 1); + client_expect_confirm(id, "shell", 1); packet_send(); } } diff --git a/clientloop.h b/clientloop.h index c7d2233d0..cb2d7c089 100644 --- a/clientloop.h +++ b/clientloop.h @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.h,v 1.17 2007/08/07 07:32:53 djm Exp $ */ +/* $OpenBSD: clientloop.h,v 1.18 2008/05/08 13:06:11 djm Exp $ */ /* * Author: Tatu Ylonen @@ -43,7 +43,7 @@ void client_x11_get_proto(const char *, const char *, u_int, char **, char **); void client_global_request_reply_fwd(int, u_int32_t, void *); void client_session2_setup(int, int, int, const char *, struct termios *, - int, Buffer *, char **, dispatch_fn *); + int, Buffer *, char **); int client_request_tun_fwd(int, int, int); /* Multiplexing protocol version */ diff --git a/ssh.c b/ssh.c index b144a7130..cfefadef9 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.310 2008/05/08 12:02:23 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.311 2008/05/08 13:06:11 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1039,21 +1039,6 @@ ssh_session(void) options.escape_char : SSH_ESCAPECHAR_NONE, 0); } -static void -ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt) -{ - int id, len; - - id = packet_get_int(); - len = buffer_len(&command); - if (len > 900) - len = 900; - packet_check_eom(); - if (type == SSH2_MSG_CHANNEL_FAILURE) - fatal("Request for subsystem '%.*s' failed on channel %d", - len, (u_char *)buffer_ptr(&command), id); -} - void client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt) { @@ -1150,7 +1135,7 @@ ssh_session2_setup(int id, void *arg) } client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"), - NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply); + NULL, fileno(stdin), &command, environ); packet_set_interactive(interactive); } -- cgit v1.2.3 From b1cbfa25f1618b277de670b943acb07ff5dbb1ac Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 19 May 2008 16:00:08 +1000 Subject: - djm@cvs.openbsd.org 2008/05/09 14:18:44 [clientloop.c clientloop.h ssh.c mux.c] tidy up session multiplexing code, moving it into its own file and making the function names more consistent - making ssh.c and clientloop.c a fair bit more readable. ok markus@ --- ChangeLog | 8 +- Makefile.in | 4 +- clientloop.c | 308 +--------------------------- clientloop.h | 20 +- mux.c | 646 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ssh.c | 309 ++-------------------------- 6 files changed, 699 insertions(+), 596 deletions(-) create mode 100644 mux.c (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index 9e683143a..90ee86ac8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -111,6 +111,12 @@ was to try the first address and give up. Reported by stig AT venaas.com in bz#343 great feedback and ok markus@ + - djm@cvs.openbsd.org 2008/05/09 14:18:44 + [clientloop.c clientloop.h ssh.c mux.c] + tidy up session multiplexing code, moving it into its own file and + making the function names more consistent - making ssh.c and + clientloop.c a fair bit more readable. + ok markus@ 20080403 - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- @@ -3971,4 +3977,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4925 2008/05/19 05:37:09 djm Exp $ +$Id: ChangeLog,v 1.4926 2008/05/19 06:00:08 djm Exp $ diff --git a/Makefile.in b/Makefile.in index 6b488feca..b57b9b72d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in,v 1.289 2008/03/13 01:41:31 djm Exp $ +# $Id: Makefile.in,v 1.290 2008/05/19 06:00:08 djm Exp $ # uncomment if you run a non bourne compatable shell. Ie. csh #SHELL = @SH@ @@ -74,7 +74,7 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \ entropy.o scard-opensc.o gss-genr.o umac.o SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect1.o sshconnect2.o + sshconnect.o sshconnect1.o sshconnect2.o mux.o SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ sshpty.o sshlogin.o servconf.o serverloop.o \ diff --git a/clientloop.c b/clientloop.c index 7bd1af60c..c87aa5a0a 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.191 2008/05/09 04:55:56 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.192 2008/05/09 14:18:44 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -121,7 +121,7 @@ extern int stdin_null_flag; extern int no_shell_flag; /* Control socket */ -extern int control_fd; +extern int muxserver_sock; /* * Name of the host we are connecting to. This is the name given on the @@ -162,17 +162,6 @@ static int session_closed = 0; /* In SSH2: login session closed. */ static void client_init_dispatch(void); int session_ident = -1; -struct confirm_ctx { - int want_tty; - int want_subsys; - int want_x_fwd; - int want_agent_fwd; - Buffer cmd; - char *term; - struct termios tio; - char **env; -}; - struct channel_reply_ctx { const char *request_type; int id, do_close; @@ -538,8 +527,8 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, if (packet_have_data_to_write()) FD_SET(connection_out, *writesetp); - if (control_fd != -1) - FD_SET(control_fd, *readsetp); + if (muxserver_sock != -1) + FD_SET(muxserver_sock, *readsetp); /* * Wait for something to happen. This will suspend the process until @@ -706,284 +695,6 @@ client_expect_confirm(int id, const char *request, int do_close) client_abandon_status_confirm, cr); } -static void -client_extra_session2_setup(int id, void *arg) -{ - struct confirm_ctx *cctx = arg; - const char *display; - Channel *c; - int i; - - if (cctx == NULL) - fatal("%s: cctx == NULL", __func__); - if ((c = channel_lookup(id)) == NULL) - fatal("%s: no channel for id %d", __func__, id); - - display = getenv("DISPLAY"); - if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { - char *proto, *data; - /* Get reasonable local authentication information. */ - client_x11_get_proto(display, options.xauth_location, - options.forward_x11_trusted, &proto, &data); - /* Request forwarding with authentication spoofing. */ - debug("Requesting X11 forwarding with authentication spoofing."); - x11_request_forwarding_with_spoofing(id, display, proto, data); - /* XXX wait for reply */ - } - - if (cctx->want_agent_fwd && options.forward_agent) { - debug("Requesting authentication agent forwarding."); - channel_request_start(id, "auth-agent-req@openssh.com", 0); - packet_send(); - } - - client_session2_setup(id, cctx->want_tty, cctx->want_subsys, - cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); - - c->open_confirm_ctx = NULL; - buffer_free(&cctx->cmd); - xfree(cctx->term); - if (cctx->env != NULL) { - for (i = 0; cctx->env[i] != NULL; i++) - xfree(cctx->env[i]); - xfree(cctx->env); - } - xfree(cctx); -} - -static void -client_process_control(fd_set *readset) -{ - Buffer m; - Channel *c; - int client_fd, new_fd[3], ver, allowed, window, packetmax; - socklen_t addrlen; - struct sockaddr_storage addr; - struct confirm_ctx *cctx; - char *cmd; - u_int i, j, len, env_len, command, flags; - uid_t euid; - gid_t egid; - - /* - * Accept connection on control socket - */ - if (control_fd == -1 || !FD_ISSET(control_fd, readset)) - return; - - memset(&addr, 0, sizeof(addr)); - addrlen = sizeof(addr); - if ((client_fd = accept(control_fd, - (struct sockaddr*)&addr, &addrlen)) == -1) { - error("%s accept: %s", __func__, strerror(errno)); - return; - } - - if (getpeereid(client_fd, &euid, &egid) < 0) { - error("%s getpeereid failed: %s", __func__, strerror(errno)); - close(client_fd); - return; - } - if ((euid != 0) && (getuid() != euid)) { - error("control mode uid mismatch: peer euid %u != uid %u", - (u_int) euid, (u_int) getuid()); - close(client_fd); - return; - } - - unset_nonblock(client_fd); - - /* Read command */ - buffer_init(&m); - if (ssh_msg_recv(client_fd, &m) == -1) { - error("%s: client msg_recv failed", __func__); - close(client_fd); - buffer_free(&m); - return; - } - if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { - error("%s: wrong client version %d", __func__, ver); - buffer_free(&m); - close(client_fd); - return; - } - - allowed = 1; - command = buffer_get_int(&m); - flags = buffer_get_int(&m); - - buffer_clear(&m); - - switch (command) { - case SSHMUX_COMMAND_OPEN: - if (options.control_master == SSHCTL_MASTER_ASK || - options.control_master == SSHCTL_MASTER_AUTO_ASK) - allowed = ask_permission("Allow shared connection " - "to %s? ", host); - /* continue below */ - break; - case SSHMUX_COMMAND_TERMINATE: - if (options.control_master == SSHCTL_MASTER_ASK || - options.control_master == SSHCTL_MASTER_AUTO_ASK) - allowed = ask_permission("Terminate shared connection " - "to %s? ", host); - if (allowed) - quit_pending = 1; - /* FALLTHROUGH */ - case SSHMUX_COMMAND_ALIVE_CHECK: - /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */ - buffer_clear(&m); - buffer_put_int(&m, allowed); - buffer_put_int(&m, getpid()); - if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { - error("%s: client msg_send failed", __func__); - close(client_fd); - buffer_free(&m); - return; - } - buffer_free(&m); - close(client_fd); - return; - default: - error("Unsupported command %d", command); - buffer_free(&m); - close(client_fd); - return; - } - - /* Reply for SSHMUX_COMMAND_OPEN */ - buffer_clear(&m); - buffer_put_int(&m, allowed); - buffer_put_int(&m, getpid()); - if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { - error("%s: client msg_send failed", __func__); - close(client_fd); - buffer_free(&m); - return; - } - - if (!allowed) { - error("Refused control connection"); - close(client_fd); - buffer_free(&m); - return; - } - - buffer_clear(&m); - if (ssh_msg_recv(client_fd, &m) == -1) { - error("%s: client msg_recv failed", __func__); - close(client_fd); - buffer_free(&m); - return; - } - if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { - error("%s: wrong client version %d", __func__, ver); - buffer_free(&m); - close(client_fd); - return; - } - - cctx = xcalloc(1, sizeof(*cctx)); - cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0; - cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0; - cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0; - cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0; - cctx->term = buffer_get_string(&m, &len); - - cmd = buffer_get_string(&m, &len); - buffer_init(&cctx->cmd); - buffer_append(&cctx->cmd, cmd, strlen(cmd)); - - env_len = buffer_get_int(&m); - env_len = MIN(env_len, 4096); - debug3("%s: receiving %d env vars", __func__, env_len); - if (env_len != 0) { - cctx->env = xcalloc(env_len + 1, sizeof(*cctx->env)); - for (i = 0; i < env_len; i++) - cctx->env[i] = buffer_get_string(&m, &len); - cctx->env[i] = NULL; - } - - debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__, - cctx->want_tty, cctx->want_subsys, cmd); - xfree(cmd); - - /* Gather fds from client */ - for(i = 0; i < 3; i++) { - if ((new_fd[i] = mm_receive_fd(client_fd)) == -1) { - error("%s: failed to receive fd %d from slave", - __func__, i); - for (j = 0; j < i; j++) - close(new_fd[j]); - for (j = 0; j < env_len; j++) - xfree(cctx->env[j]); - if (env_len > 0) - xfree(cctx->env); - xfree(cctx->term); - buffer_free(&cctx->cmd); - close(client_fd); - xfree(cctx); - return; - } - } - - debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__, - new_fd[0], new_fd[1], new_fd[2]); - - /* Try to pick up ttymodes from client before it goes raw */ - if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) - error("%s: tcgetattr: %s", __func__, strerror(errno)); - - /* This roundtrip is just for synchronisation of ttymodes */ - buffer_clear(&m); - if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { - error("%s: client msg_send failed", __func__); - close(client_fd); - close(new_fd[0]); - close(new_fd[1]); - close(new_fd[2]); - buffer_free(&m); - xfree(cctx->term); - if (env_len != 0) { - for (i = 0; i < env_len; i++) - xfree(cctx->env[i]); - xfree(cctx->env); - } - return; - } - buffer_free(&m); - - /* enable nonblocking unless tty */ - if (!isatty(new_fd[0])) - set_nonblock(new_fd[0]); - if (!isatty(new_fd[1])) - set_nonblock(new_fd[1]); - if (!isatty(new_fd[2])) - set_nonblock(new_fd[2]); - - set_nonblock(client_fd); - - window = CHAN_SES_WINDOW_DEFAULT; - packetmax = CHAN_SES_PACKET_DEFAULT; - if (cctx->want_tty) { - window >>= 1; - packetmax >>= 1; - } - - c = channel_new("session", SSH_CHANNEL_OPENING, - new_fd[0], new_fd[1], new_fd[2], window, packetmax, - CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); - - /* XXX */ - c->ctl_fd = client_fd; - - debug3("%s: channel_new: %d", __func__, c->self); - - channel_send_open(c->self); - channel_register_open_confirm(c->self, - client_extra_session2_setup, cctx); -} - static void process_cmdline(void) { @@ -1448,8 +1159,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) connection_in = packet_get_connection_in(); connection_out = packet_get_connection_out(); max_fd = MAX(connection_in, connection_out); - if (control_fd != -1) - max_fd = MAX(max_fd, control_fd); + if (muxserver_sock != -1) + max_fd = MAX(max_fd, muxserver_sock); if (!compat20) { /* enable nonblocking unless tty */ @@ -1569,7 +1280,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) client_process_net_input(readset); /* Accept control connections. */ - client_process_control(readset); + if (muxserver_sock != -1 &&FD_ISSET(muxserver_sock, readset)) { + if (muxserver_accept_control()) + quit_pending = 1; + } if (quit_pending) break; @@ -2157,7 +1871,7 @@ cleanup_exit(int i) { leave_raw_mode(); leave_non_blocking(); - if (options.control_path != NULL && control_fd != -1) + if (options.control_path != NULL && muxserver_sock != -1) unlink(options.control_path); _exit(i); } diff --git a/clientloop.h b/clientloop.h index cb2d7c089..6f8e70123 100644 --- a/clientloop.h +++ b/clientloop.h @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.h,v 1.18 2008/05/08 13:06:11 djm Exp $ */ +/* $OpenBSD: clientloop.h,v 1.19 2008/05/09 14:18:44 djm Exp $ */ /* * Author: Tatu Ylonen @@ -58,3 +58,21 @@ int client_request_tun_fwd(int, int, int); #define SSHMUX_FLAG_SUBSYS (1<<1) /* Subsystem request on open */ #define SSHMUX_FLAG_X11_FWD (1<<2) /* Request X11 forwarding */ #define SSHMUX_FLAG_AGENT_FWD (1<<3) /* Request agent forwarding */ + +/* Multiplexing routines */ + +struct mux_session_confirm_ctx { + int want_tty; + int want_subsys; + int want_x_fwd; + int want_agent_fwd; + Buffer cmd; + char *term; + struct termios tio; + char **env; +}; + +/* mux.c */ +void muxserver_listen(void); +int muxserver_accept_control(void); +void muxclient(const char *); diff --git a/mux.c b/mux.c new file mode 100644 index 000000000..78ba63153 --- /dev/null +++ b/mux.c @@ -0,0 +1,646 @@ +/* $OpenBSD: mux.c,v 1.1 2008/05/09 14:18:44 djm Exp $ */ +/* + * Copyright (c) 2002-2008 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ssh session multiplexing support */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openbsd-compat/sys-queue.h" +#include "xmalloc.h" +#include "log.h" +#include "ssh.h" +#include "pathnames.h" +#include "misc.h" +#include "match.h" +#include "buffer.h" +#include "channels.h" +#include "msg.h" +#include "packet.h" +#include "monitor_fdpass.h" +#include "sshpty.h" +#include "key.h" +#include "readconf.h" +#include "clientloop.h" + +/* from ssh.c */ +extern int tty_flag; +extern Options options; +extern int stdin_null_flag; +extern char *host; +int subsystem_flag; +extern Buffer command; + +/* fd to control socket */ +int muxserver_sock = -1; + +/* Multiplexing control command */ +u_int muxclient_command = 0; + +/* Set when signalled. */ +static volatile sig_atomic_t muxclient_terminate = 0; + +/* PID of multiplex server */ +static u_int muxserver_pid = 0; + + +/* ** Multiplexing master support */ + +/* Prepare a mux master to listen on a Unix domain socket. */ +void +muxserver_listen(void) +{ + struct sockaddr_un addr; + mode_t old_umask; + int addr_len; + + if (options.control_path == NULL || + options.control_master == SSHCTL_MASTER_NO) + return; + + debug("setting up multiplex master socket"); + + memset(&addr, '\0', sizeof(addr)); + addr.sun_family = AF_UNIX; + addr_len = offsetof(struct sockaddr_un, sun_path) + + strlen(options.control_path) + 1; + + if (strlcpy(addr.sun_path, options.control_path, + sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) + fatal("ControlPath too long"); + + if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + fatal("%s socket(): %s", __func__, strerror(errno)); + + old_umask = umask(0177); + if (bind(muxserver_sock, (struct sockaddr *)&addr, addr_len) == -1) { + muxserver_sock = -1; + if (errno == EINVAL || errno == EADDRINUSE) + fatal("ControlSocket %s already exists", + options.control_path); + else + fatal("%s bind(): %s", __func__, strerror(errno)); + } + umask(old_umask); + + if (listen(muxserver_sock, 64) == -1) + fatal("%s listen(): %s", __func__, strerror(errno)); + + set_nonblock(muxserver_sock); +} + +/* Callback on open confirmation in mux master for a mux client session. */ +static void +client_extra_session2_setup(int id, void *arg) +{ + struct mux_session_confirm_ctx *cctx = arg; + const char *display; + Channel *c; + int i; + + if (cctx == NULL) + fatal("%s: cctx == NULL", __func__); + if ((c = channel_lookup(id)) == NULL) + fatal("%s: no channel for id %d", __func__, id); + + display = getenv("DISPLAY"); + if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { + char *proto, *data; + /* Get reasonable local authentication information. */ + client_x11_get_proto(display, options.xauth_location, + options.forward_x11_trusted, &proto, &data); + /* Request forwarding with authentication spoofing. */ + debug("Requesting X11 forwarding with authentication spoofing."); + x11_request_forwarding_with_spoofing(id, display, proto, data); + /* XXX wait for reply */ + } + + if (cctx->want_agent_fwd && options.forward_agent) { + debug("Requesting authentication agent forwarding."); + channel_request_start(id, "auth-agent-req@openssh.com", 0); + packet_send(); + } + + client_session2_setup(id, cctx->want_tty, cctx->want_subsys, + cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); + + c->open_confirm_ctx = NULL; + buffer_free(&cctx->cmd); + xfree(cctx->term); + if (cctx->env != NULL) { + for (i = 0; cctx->env[i] != NULL; i++) + xfree(cctx->env[i]); + xfree(cctx->env); + } + xfree(cctx); +} + +/* + * Accept a connection on the mux master socket and process the + * client's request. Returns flag indicating whether mux master should + * begin graceful close. + */ +int +muxserver_accept_control(void) +{ + Buffer m; + Channel *c; + int client_fd, new_fd[3], ver, allowed, window, packetmax; + socklen_t addrlen; + struct sockaddr_storage addr; + struct mux_session_confirm_ctx *cctx; + char *cmd; + u_int i, j, len, env_len, mux_command, flags; + uid_t euid; + gid_t egid; + int start_close = 0; + + /* + * Accept connection on control socket + */ + memset(&addr, 0, sizeof(addr)); + addrlen = sizeof(addr); + if ((client_fd = accept(muxserver_sock, + (struct sockaddr*)&addr, &addrlen)) == -1) { + error("%s accept: %s", __func__, strerror(errno)); + return 0; + } + + if (getpeereid(client_fd, &euid, &egid) < 0) { + error("%s getpeereid failed: %s", __func__, strerror(errno)); + close(client_fd); + return 0; + } + if ((euid != 0) && (getuid() != euid)) { + error("control mode uid mismatch: peer euid %u != uid %u", + (u_int) euid, (u_int) getuid()); + close(client_fd); + return 0; + } + + /* XXX handle asynchronously */ + unset_nonblock(client_fd); + + /* Read command */ + buffer_init(&m); + if (ssh_msg_recv(client_fd, &m) == -1) { + error("%s: client msg_recv failed", __func__); + close(client_fd); + buffer_free(&m); + return 0; + } + if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { + error("%s: wrong client version %d", __func__, ver); + buffer_free(&m); + close(client_fd); + return 0; + } + + allowed = 1; + mux_command = buffer_get_int(&m); + flags = buffer_get_int(&m); + + buffer_clear(&m); + + switch (mux_command) { + case SSHMUX_COMMAND_OPEN: + if (options.control_master == SSHCTL_MASTER_ASK || + options.control_master == SSHCTL_MASTER_AUTO_ASK) + allowed = ask_permission("Allow shared connection " + "to %s? ", host); + /* continue below */ + break; + case SSHMUX_COMMAND_TERMINATE: + if (options.control_master == SSHCTL_MASTER_ASK || + options.control_master == SSHCTL_MASTER_AUTO_ASK) + allowed = ask_permission("Terminate shared connection " + "to %s? ", host); + if (allowed) + start_close = 1; + /* FALLTHROUGH */ + case SSHMUX_COMMAND_ALIVE_CHECK: + /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */ + buffer_clear(&m); + buffer_put_int(&m, allowed); + buffer_put_int(&m, getpid()); + if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { + error("%s: client msg_send failed", __func__); + close(client_fd); + buffer_free(&m); + return start_close; + } + buffer_free(&m); + close(client_fd); + return start_close; + default: + error("Unsupported command %d", mux_command); + buffer_free(&m); + close(client_fd); + return 0; + } + + /* Reply for SSHMUX_COMMAND_OPEN */ + buffer_clear(&m); + buffer_put_int(&m, allowed); + buffer_put_int(&m, getpid()); + if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { + error("%s: client msg_send failed", __func__); + close(client_fd); + buffer_free(&m); + return 0; + } + + if (!allowed) { + error("Refused control connection"); + close(client_fd); + buffer_free(&m); + return 0; + } + + buffer_clear(&m); + if (ssh_msg_recv(client_fd, &m) == -1) { + error("%s: client msg_recv failed", __func__); + close(client_fd); + buffer_free(&m); + return 0; + } + if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { + error("%s: wrong client version %d", __func__, ver); + buffer_free(&m); + close(client_fd); + return 0; + } + + cctx = xcalloc(1, sizeof(*cctx)); + cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0; + cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0; + cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0; + cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0; + cctx->term = buffer_get_string(&m, &len); + + cmd = buffer_get_string(&m, &len); + buffer_init(&cctx->cmd); + buffer_append(&cctx->cmd, cmd, strlen(cmd)); + + env_len = buffer_get_int(&m); + env_len = MIN(env_len, 4096); + debug3("%s: receiving %d env vars", __func__, env_len); + if (env_len != 0) { + cctx->env = xcalloc(env_len + 1, sizeof(*cctx->env)); + for (i = 0; i < env_len; i++) + cctx->env[i] = buffer_get_string(&m, &len); + cctx->env[i] = NULL; + } + + debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__, + cctx->want_tty, cctx->want_subsys, cmd); + xfree(cmd); + + /* Gather fds from client */ + for(i = 0; i < 3; i++) { + if ((new_fd[i] = mm_receive_fd(client_fd)) == -1) { + error("%s: failed to receive fd %d from slave", + __func__, i); + for (j = 0; j < i; j++) + close(new_fd[j]); + for (j = 0; j < env_len; j++) + xfree(cctx->env[j]); + if (env_len > 0) + xfree(cctx->env); + xfree(cctx->term); + buffer_free(&cctx->cmd); + close(client_fd); + xfree(cctx); + return 0; + } + } + + debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__, + new_fd[0], new_fd[1], new_fd[2]); + + /* Try to pick up ttymodes from client before it goes raw */ + if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) + error("%s: tcgetattr: %s", __func__, strerror(errno)); + + /* This roundtrip is just for synchronisation of ttymodes */ + buffer_clear(&m); + if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { + error("%s: client msg_send failed", __func__); + close(client_fd); + close(new_fd[0]); + close(new_fd[1]); + close(new_fd[2]); + buffer_free(&m); + xfree(cctx->term); + if (env_len != 0) { + for (i = 0; i < env_len; i++) + xfree(cctx->env[i]); + xfree(cctx->env); + } + return 0; + } + buffer_free(&m); + + /* enable nonblocking unless tty */ + if (!isatty(new_fd[0])) + set_nonblock(new_fd[0]); + if (!isatty(new_fd[1])) + set_nonblock(new_fd[1]); + if (!isatty(new_fd[2])) + set_nonblock(new_fd[2]); + + set_nonblock(client_fd); + + window = CHAN_SES_WINDOW_DEFAULT; + packetmax = CHAN_SES_PACKET_DEFAULT; + if (cctx->want_tty) { + window >>= 1; + packetmax >>= 1; + } + + c = channel_new("session", SSH_CHANNEL_OPENING, + new_fd[0], new_fd[1], new_fd[2], window, packetmax, + CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); + + /* XXX */ + c->ctl_fd = client_fd; + + debug3("%s: channel_new: %d", __func__, c->self); + + channel_send_open(c->self); + channel_register_open_confirm(c->self, + client_extra_session2_setup, cctx); + return 0; +} + +/* ** Multiplexing client support */ + +/* Exit signal handler */ +static void +control_client_sighandler(int signo) +{ + muxclient_terminate = signo; +} + +/* + * Relay signal handler - used to pass some signals from mux client to + * mux master. + */ +static void +control_client_sigrelay(int signo) +{ + int save_errno = errno; + + if (muxserver_pid > 1) + kill(muxserver_pid, signo); + + errno = save_errno; +} + +/* Check mux client environment variables before passing them to mux master. */ +static int +env_permitted(char *env) +{ + int i, ret; + char name[1024], *cp; + + if ((cp = strchr(env, '=')) == NULL || cp == env) + return (0); + ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env); + if (ret <= 0 || (size_t)ret >= sizeof(name)) + fatal("env_permitted: name '%.100s...' too long", env); + + for (i = 0; i < options.num_send_env; i++) + if (match_pattern(name, options.send_env[i])) + return (1); + + return (0); +} + +/* Multiplex client main loop. */ +void +muxclient(const char *path) +{ + struct sockaddr_un addr; + int i, r, fd, sock, exitval[2], num_env, addr_len; + Buffer m; + char *term; + extern char **environ; + u_int flags; + + if (muxclient_command == 0) + muxclient_command = SSHMUX_COMMAND_OPEN; + + switch (options.control_master) { + case SSHCTL_MASTER_AUTO: + case SSHCTL_MASTER_AUTO_ASK: + debug("auto-mux: Trying existing master"); + /* FALLTHROUGH */ + case SSHCTL_MASTER_NO: + break; + default: + return; + } + + memset(&addr, '\0', sizeof(addr)); + addr.sun_family = AF_UNIX; + addr_len = offsetof(struct sockaddr_un, sun_path) + + strlen(path) + 1; + + if (strlcpy(addr.sun_path, path, + sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) + fatal("ControlPath too long"); + + if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + fatal("%s socket(): %s", __func__, strerror(errno)); + + if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) { + if (muxclient_command != SSHMUX_COMMAND_OPEN) { + fatal("Control socket connect(%.100s): %s", path, + strerror(errno)); + } + if (errno == ENOENT) + debug("Control socket \"%.100s\" does not exist", path); + else { + error("Control socket connect(%.100s): %s", path, + strerror(errno)); + } + close(sock); + return; + } + + if (stdin_null_flag) { + if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) + fatal("open(/dev/null): %s", strerror(errno)); + if (dup2(fd, STDIN_FILENO) == -1) + fatal("dup2: %s", strerror(errno)); + if (fd > STDERR_FILENO) + close(fd); + } + + term = getenv("TERM"); + + flags = 0; + if (tty_flag) + flags |= SSHMUX_FLAG_TTY; + if (subsystem_flag) + flags |= SSHMUX_FLAG_SUBSYS; + if (options.forward_x11) + flags |= SSHMUX_FLAG_X11_FWD; + if (options.forward_agent) + flags |= SSHMUX_FLAG_AGENT_FWD; + + signal(SIGPIPE, SIG_IGN); + + buffer_init(&m); + + /* Send our command to server */ + buffer_put_int(&m, muxclient_command); + buffer_put_int(&m, flags); + if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) + fatal("%s: msg_send", __func__); + buffer_clear(&m); + + /* Get authorisation status and PID of controlee */ + if (ssh_msg_recv(sock, &m) == -1) + fatal("%s: msg_recv", __func__); + if (buffer_get_char(&m) != SSHMUX_VER) + fatal("%s: wrong version", __func__); + if (buffer_get_int(&m) != 1) + fatal("Connection to master denied"); + muxserver_pid = buffer_get_int(&m); + + buffer_clear(&m); + + switch (muxclient_command) { + case SSHMUX_COMMAND_ALIVE_CHECK: + fprintf(stderr, "Master running (pid=%d)\r\n", + muxserver_pid); + exit(0); + case SSHMUX_COMMAND_TERMINATE: + fprintf(stderr, "Exit request sent.\r\n"); + exit(0); + case SSHMUX_COMMAND_OPEN: + /* continue below */ + break; + default: + fatal("silly muxclient_command %d", muxclient_command); + } + + /* SSHMUX_COMMAND_OPEN */ + buffer_put_cstring(&m, term ? term : ""); + buffer_append(&command, "\0", 1); + buffer_put_cstring(&m, buffer_ptr(&command)); + + if (options.num_send_env == 0 || environ == NULL) { + buffer_put_int(&m, 0); + } else { + /* Pass environment */ + num_env = 0; + for (i = 0; environ[i] != NULL; i++) + if (env_permitted(environ[i])) + num_env++; /* Count */ + + buffer_put_int(&m, num_env); + + for (i = 0; environ[i] != NULL && num_env >= 0; i++) + if (env_permitted(environ[i])) { + num_env--; + buffer_put_cstring(&m, environ[i]); + } + } + + if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) + fatal("%s: msg_send", __func__); + + if (mm_send_fd(sock, STDIN_FILENO) == -1 || + mm_send_fd(sock, STDOUT_FILENO) == -1 || + mm_send_fd(sock, STDERR_FILENO) == -1) + fatal("%s: send fds failed", __func__); + + /* Wait for reply, so master has a chance to gather ttymodes */ + buffer_clear(&m); + if (ssh_msg_recv(sock, &m) == -1) + fatal("%s: msg_recv", __func__); + if (buffer_get_char(&m) != SSHMUX_VER) + fatal("%s: wrong version", __func__); + buffer_free(&m); + + signal(SIGHUP, control_client_sighandler); + signal(SIGINT, control_client_sighandler); + signal(SIGTERM, control_client_sighandler); + signal(SIGWINCH, control_client_sigrelay); + + if (tty_flag) + enter_raw_mode(); + + /* + * Stick around until the controlee closes the client_fd. + * Before it does, it is expected to write this process' exit + * value (one int). This process must read the value and wait for + * the closure of the client_fd; if this one closes early, the + * multiplex master will terminate early too (possibly losing data). + */ + exitval[0] = 0; + for (i = 0; !muxclient_terminate && i < (int)sizeof(exitval);) { + r = read(sock, (char *)exitval + i, sizeof(exitval) - i); + if (r == 0) { + debug2("Received EOF from master"); + break; + } + if (r == -1) { + if (errno == EINTR) + continue; + fatal("%s: read %s", __func__, strerror(errno)); + } + i += r; + } + + close(sock); + leave_raw_mode(); + if (i > (int)sizeof(int)) + fatal("%s: master returned too much data (%d > %lu)", + __func__, i, sizeof(int)); + if (muxclient_terminate) { + debug2("Exiting on signal %d", muxclient_terminate); + exitval[0] = 255; + } else if (i < (int)sizeof(int)) { + debug2("Control master terminated unexpectedly"); + exitval[0] = 255; + } else + debug2("Received exit status from master %d", exitval[0]); + + if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) + fprintf(stderr, "Shared connection to %s closed.\r\n", host); + + exit(exitval[0]); +} diff --git a/ssh.c b/ssh.c index cfefadef9..c944d0ad6 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.311 2008/05/08 13:06:11 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.312 2008/05/09 14:18:44 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -49,7 +49,6 @@ #include #include #include -#include #include #include @@ -99,7 +98,6 @@ #include "sshpty.h" #include "match.h" #include "msg.h" -#include "monitor_fdpass.h" #include "uidswap.h" #include "version.h" @@ -171,15 +169,9 @@ static int client_global_request_id = 0; /* pid of proxycommand child process */ pid_t proxy_command_pid = 0; -/* fd to control socket */ -int control_fd = -1; - -/* Multiplexing control command */ -static u_int mux_command = 0; - -/* Only used in control client mode */ -volatile sig_atomic_t control_client_terminate = 0; -u_int control_server_pid = 0; +/* mux.c */ +extern int muxserver_sock; +extern u_int muxclient_command; /* Prints a help message to the user. This function never returns. */ @@ -200,7 +192,10 @@ usage(void) static int ssh_session(void); static int ssh_session2(void); static void load_public_identity_files(void); -static void control_client(const char *path); + +/* from muxclient.c */ +void muxclient(const char *); +void muxserver_listen(void); /* * Main program for the ssh client. @@ -310,9 +305,9 @@ main(int ac, char **av) break; case 'O': if (strcmp(optarg, "check") == 0) - mux_command = SSHMUX_COMMAND_ALIVE_CHECK; + muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK; else if (strcmp(optarg, "exit") == 0) - mux_command = SSHMUX_COMMAND_TERMINATE; + muxclient_command = SSHMUX_COMMAND_TERMINATE; else fatal("Invalid multiplex command."); break; @@ -683,10 +678,10 @@ main(int ac, char **av) "r", options.user, "l", thishost, (char *)NULL); xfree(cp); } - if (mux_command != 0 && options.control_path == NULL) + if (muxclient_command != 0 && options.control_path == NULL) fatal("No ControlPath specified for \"-O\" command"); if (options.control_path != NULL) - control_client(options.control_path); + muxclient(options.control_path); timeout_ms = options.connection_timeout * 1000; @@ -809,7 +804,7 @@ main(int ac, char **av) exit_status = compat20 ? ssh_session2() : ssh_session(); packet_close(); - if (options.control_path != NULL && control_fd != -1) + if (options.control_path != NULL && muxserver_sock != -1) unlink(options.control_path); /* @@ -1064,48 +1059,6 @@ client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt) } } -static void -ssh_control_listener(void) -{ - struct sockaddr_un addr; - mode_t old_umask; - int addr_len; - - if (options.control_path == NULL || - options.control_master == SSHCTL_MASTER_NO) - return; - - debug("setting up multiplex master socket"); - - memset(&addr, '\0', sizeof(addr)); - addr.sun_family = AF_UNIX; - addr_len = offsetof(struct sockaddr_un, sun_path) + - strlen(options.control_path) + 1; - - if (strlcpy(addr.sun_path, options.control_path, - sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) - fatal("ControlPath too long"); - - if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) - fatal("%s socket(): %s", __func__, strerror(errno)); - - old_umask = umask(0177); - if (bind(control_fd, (struct sockaddr *)&addr, addr_len) == -1) { - control_fd = -1; - if (errno == EINVAL || errno == EADDRINUSE) - fatal("ControlSocket %s already exists", - options.control_path); - else - fatal("%s bind(): %s", __func__, strerror(errno)); - } - umask(old_umask); - - if (listen(control_fd, 64) == -1) - fatal("%s listen(): %s", __func__, strerror(errno)); - - set_nonblock(control_fd); -} - /* request pty/x11/agent/tcpfwd/shell for channel */ static void ssh_session2_setup(int id, void *arg) @@ -1204,7 +1157,7 @@ ssh_session2(void) ssh_local_cmd(options.local_command); /* Start listening for multiplex clients */ - ssh_control_listener(); + muxserver_listen(); /* If requested, let ssh continue in the background. */ if (fork_after_authentication_flag) @@ -1272,237 +1225,3 @@ load_public_identity_files(void) bzero(pwdir, strlen(pwdir)); xfree(pwdir); } - -static void -control_client_sighandler(int signo) -{ - control_client_terminate = signo; -} - -static void -control_client_sigrelay(int signo) -{ - int save_errno = errno; - - if (control_server_pid > 1) - kill(control_server_pid, signo); - - errno = save_errno; -} - -static int -env_permitted(char *env) -{ - int i, ret; - char name[1024], *cp; - - if ((cp = strchr(env, '=')) == NULL || cp == env) - return (0); - ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env); - if (ret <= 0 || (size_t)ret >= sizeof(name)) - fatal("env_permitted: name '%.100s...' too long", env); - - for (i = 0; i < options.num_send_env; i++) - if (match_pattern(name, options.send_env[i])) - return (1); - - return (0); -} - -static void -control_client(const char *path) -{ - struct sockaddr_un addr; - int i, r, fd, sock, exitval[2], num_env, addr_len; - Buffer m; - char *term; - extern char **environ; - u_int flags; - - if (mux_command == 0) - mux_command = SSHMUX_COMMAND_OPEN; - - switch (options.control_master) { - case SSHCTL_MASTER_AUTO: - case SSHCTL_MASTER_AUTO_ASK: - debug("auto-mux: Trying existing master"); - /* FALLTHROUGH */ - case SSHCTL_MASTER_NO: - break; - default: - return; - } - - memset(&addr, '\0', sizeof(addr)); - addr.sun_family = AF_UNIX; - addr_len = offsetof(struct sockaddr_un, sun_path) + - strlen(path) + 1; - - if (strlcpy(addr.sun_path, path, - sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) - fatal("ControlPath too long"); - - if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) - fatal("%s socket(): %s", __func__, strerror(errno)); - - if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) { - if (mux_command != SSHMUX_COMMAND_OPEN) { - fatal("Control socket connect(%.100s): %s", path, - strerror(errno)); - } - if (errno == ENOENT) - debug("Control socket \"%.100s\" does not exist", path); - else { - error("Control socket connect(%.100s): %s", path, - strerror(errno)); - } - close(sock); - return; - } - - if (stdin_null_flag) { - if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) - fatal("open(/dev/null): %s", strerror(errno)); - if (dup2(fd, STDIN_FILENO) == -1) - fatal("dup2: %s", strerror(errno)); - if (fd > STDERR_FILENO) - close(fd); - } - - term = getenv("TERM"); - - flags = 0; - if (tty_flag) - flags |= SSHMUX_FLAG_TTY; - if (subsystem_flag) - flags |= SSHMUX_FLAG_SUBSYS; - if (options.forward_x11) - flags |= SSHMUX_FLAG_X11_FWD; - if (options.forward_agent) - flags |= SSHMUX_FLAG_AGENT_FWD; - - signal(SIGPIPE, SIG_IGN); - - buffer_init(&m); - - /* Send our command to server */ - buffer_put_int(&m, mux_command); - buffer_put_int(&m, flags); - if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) - fatal("%s: msg_send", __func__); - buffer_clear(&m); - - /* Get authorisation status and PID of controlee */ - if (ssh_msg_recv(sock, &m) == -1) - fatal("%s: msg_recv", __func__); - if (buffer_get_char(&m) != SSHMUX_VER) - fatal("%s: wrong version", __func__); - if (buffer_get_int(&m) != 1) - fatal("Connection to master denied"); - control_server_pid = buffer_get_int(&m); - - buffer_clear(&m); - - switch (mux_command) { - case SSHMUX_COMMAND_ALIVE_CHECK: - fprintf(stderr, "Master running (pid=%d)\r\n", - control_server_pid); - exit(0); - case SSHMUX_COMMAND_TERMINATE: - fprintf(stderr, "Exit request sent.\r\n"); - exit(0); - case SSHMUX_COMMAND_OPEN: - /* continue below */ - break; - default: - fatal("silly mux_command %d", mux_command); - } - - /* SSHMUX_COMMAND_OPEN */ - buffer_put_cstring(&m, term ? term : ""); - buffer_append(&command, "\0", 1); - buffer_put_cstring(&m, buffer_ptr(&command)); - - if (options.num_send_env == 0 || environ == NULL) { - buffer_put_int(&m, 0); - } else { - /* Pass environment */ - num_env = 0; - for (i = 0; environ[i] != NULL; i++) - if (env_permitted(environ[i])) - num_env++; /* Count */ - - buffer_put_int(&m, num_env); - - for (i = 0; environ[i] != NULL && num_env >= 0; i++) - if (env_permitted(environ[i])) { - num_env--; - buffer_put_cstring(&m, environ[i]); - } - } - - if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) - fatal("%s: msg_send", __func__); - - if (mm_send_fd(sock, STDIN_FILENO) == -1 || - mm_send_fd(sock, STDOUT_FILENO) == -1 || - mm_send_fd(sock, STDERR_FILENO) == -1) - fatal("%s: send fds failed", __func__); - - /* Wait for reply, so master has a chance to gather ttymodes */ - buffer_clear(&m); - if (ssh_msg_recv(sock, &m) == -1) - fatal("%s: msg_recv", __func__); - if (buffer_get_char(&m) != SSHMUX_VER) - fatal("%s: wrong version", __func__); - buffer_free(&m); - - signal(SIGHUP, control_client_sighandler); - signal(SIGINT, control_client_sighandler); - signal(SIGTERM, control_client_sighandler); - signal(SIGWINCH, control_client_sigrelay); - - if (tty_flag) - enter_raw_mode(); - - /* - * Stick around until the controlee closes the client_fd. - * Before it does, it is expected to write this process' exit - * value (one int). This process must read the value and wait for - * the closure of the client_fd; if this one closes early, the - * multiplex master will terminate early too (possibly losing data). - */ - exitval[0] = 0; - for (i = 0; !control_client_terminate && i < (int)sizeof(exitval);) { - r = read(sock, (char *)exitval + i, sizeof(exitval) - i); - if (r == 0) { - debug2("Received EOF from master"); - break; - } - if (r == -1) { - if (errno == EINTR) - continue; - fatal("%s: read %s", __func__, strerror(errno)); - } - i += r; - } - - close(sock); - leave_raw_mode(); - if (i > (int)sizeof(int)) - fatal("%s: master returned too much data (%d > %lu)", - __func__, i, sizeof(int)); - if (control_client_terminate) { - debug2("Exiting on signal %d", control_client_terminate); - exitval[0] = 255; - } else if (i < (int)sizeof(int)) { - debug2("Control master terminated unexpectedly"); - exitval[0] = 255; - } else - debug2("Received exit status from master %d", exitval[0]); - - if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) - fprintf(stderr, "Shared connection to %s closed.\r\n", host); - - exit(exitval[0]); -} -- cgit v1.2.3 From b3da593962885883feca47ceb36617ab3eafcee8 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 19 May 2008 16:02:37 +1000 Subject: - djm@cvs.openbsd.org 2008/05/09 14:26:08 [ssh.c] dingo stole my diff hunk --- ChangeLog | 5 ++++- ssh.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index 90ee86ac8..e4cff0070 100644 --- a/ChangeLog +++ b/ChangeLog @@ -117,6 +117,9 @@ making the function names more consistent - making ssh.c and clientloop.c a fair bit more readable. ok markus@ + - djm@cvs.openbsd.org 2008/05/09 14:26:08 + [ssh.c] + dingo stole my diff hunk 20080403 - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- @@ -3977,4 +3980,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4926 2008/05/19 06:00:08 djm Exp $ +$Id: ChangeLog,v 1.4927 2008/05/19 06:02:37 djm Exp $ diff --git a/ssh.c b/ssh.c index c944d0ad6..3bcca53ee 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.312 2008/05/09 14:18:44 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.313 2008/05/09 14:26:08 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland -- cgit v1.2.3 From 8901fa9c88d52ac1f099e7a3ce5bd75089e7e731 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Wed, 11 Jun 2008 09:34:01 +1000 Subject: - djm@cvs.openbsd.org 2008/06/10 22:15:23 [PROTOCOL ssh.c serverloop.c] Add a no-more-sessions@openssh.com global request extension that the client sends when it knows that it will never request another session (i.e. when session multiplexing is disabled). This allows a server to disallow further session requests and terminate the session. Why would a non-multiplexing client ever issue additional session requests? It could have been attacked with something like SSH'jack: http://www.storm.net.nz/projects/7 feedback & ok markus --- ChangeLog | 12 +++++++++++- PROTOCOL | 33 ++++++++++++++++++++++++++++----- serverloop.c | 12 +++++++++++- ssh.c | 11 ++++++++++- 4 files changed, 60 insertions(+), 8 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index 5239fd539..9701f255a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -41,6 +41,16 @@ - dtucker@cvs.openbsd.org 2008/06/10 18:21:24 [ssh_config.5] clarify that Host patterns are space-separated. ok deraadt + - djm@cvs.openbsd.org 2008/06/10 22:15:23 + [PROTOCOL ssh.c serverloop.c] + Add a no-more-sessions@openssh.com global request extension that the + client sends when it knows that it will never request another session + (i.e. when session multiplexing is disabled). This allows a server to + disallow further session requests and terminate the session. + Why would a non-multiplexing client ever issue additional session + requests? It could have been attacked with something like SSH'jack: + http://www.storm.net.nz/projects/7 + feedback & ok markus - (dtucker) [openbsd-compat/fake-rfc2553.h] Add sin6_scope_id to sockaddr_in6 since the new CIDR code in addmatch.c references it. - (dtucker) [Makefile.in configure.ac regress/addrmatch.sh] Skip IPv6 @@ -4133,4 +4143,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4961 2008/06/10 23:33:01 dtucker Exp $ +$Id: ChangeLog,v 1.4962 2008/06/10 23:34:01 dtucker Exp $ diff --git a/PROTOCOL b/PROTOCOL index 4d7a447b0..76e6adb4b 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -61,7 +61,30 @@ remain open after a "eow@openssh.com" has been sent and more data may still be sent in the other direction. This message does not consume window space and may be sent even if no window space is available. -4. sftp: Reversal of arguments to SSH_FXP_SYMLINK +4. connection: disallow additional sessions extension + "no-more-sessions@openssh.com" + +Most SSH connections will only ever request a single session, but a +attacker may abuse a running ssh client to surreptitiously open +additional sessions under their control. OpenSSH provides a global +request "no-more-sessions@openssh.com" to mitigate this attack. + +When an OpenSSH client expects that it will never open another session +(i.e. it has been started with connection multiplexing disabled), it +will send the following global request: + + byte SSH_MSG_GLOBAL_REQUEST + string "no-more-sessions@openssh.com" + char want-reply + +On receipt of such a message, an OpenSSH server will refuse to open +future channels of type "session" and instead immediately abort the +connection. + +Note that this is not a general defence against compromised clients +(that is impossible), but it thwarts a simple attack. + +5. sftp: Reversal of arguments to SSH_FXP_SYMLINK When OpenSSH's sftp-server was implemented, the order of the arguments to the SSH_FXP_SYMLINK method was inadvertendly reversed. Unfortunately, @@ -74,7 +97,7 @@ SSH_FXP_SYMLINK as follows: string targetpath string linkpath -5. sftp: Server extension announcement in SSH_FXP_VERSION +6. sftp: Server extension announcement in SSH_FXP_VERSION OpenSSH's sftp-server lists the extensions it supports using the standard extension announcement mechanism in the SSH_FXP_VERSION server @@ -95,7 +118,7 @@ ever changed in an incompatible way. The server MAY advertise the same extension with multiple versions (though this is unlikely). Clients MUST check the version number before attemping to use the extension. -6. sftp: Extension request "posix-rename@openssh.com" +7. sftp: Extension request "posix-rename@openssh.com" This operation provides a rename operation with POSIX semantics, which are different to those provided by the standard SSH_FXP_RENAME in @@ -112,7 +135,7 @@ rename(oldpath, newpath) and will respond with a SSH_FXP_STATUS message. This extension is advertised in the SSH_FXP_VERSION hello with version "1". -7. sftp: Extension requests "statvfs@openssh.com" and +8. sftp: Extension requests "statvfs@openssh.com" and "fstatvfs@openssh.com" These requests correspond to the statvfs and fstatvfs POSIX system @@ -153,5 +176,5 @@ The values of the f_flag bitmask are as follows: This extension is advertised in the SSH_FXP_VERSION hello with version "2". -$OpenBSD: PROTOCOL,v 1.5 2008/06/09 13:38:46 dtucker Exp $ +$OpenBSD: PROTOCOL,v 1.6 2008/06/10 22:15:23 djm Exp $ diff --git a/serverloop.c b/serverloop.c index 6bc140f8b..76d76bab9 100644 --- a/serverloop.c +++ b/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.151 2008/05/09 16:21:13 markus Exp $ */ +/* $OpenBSD: serverloop.c,v 1.152 2008/06/10 22:15:23 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -105,6 +105,7 @@ static int connection_in; /* Connection to client (input). */ static int connection_out; /* Connection to client (output). */ static int connection_closed = 0; /* Connection to client closed. */ static u_int buffer_high; /* "Soft" max buffer size. */ +static int no_more_sessions = 0; /* Disallow further sessions. */ /* * This SIGCHLD kludge is used to detect when the child exits. The server @@ -1013,6 +1014,12 @@ server_request_session(void) debug("input_session_request"); packet_check_eom(); + + if (no_more_sessions) { + packet_disconnect("Possible attack: attempt to open a session " + "after additional sessions disabled"); + } + /* * A server session has no fd to read or write until a * CHANNEL_REQUEST for a shell is made, so we set the type to @@ -1133,6 +1140,9 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) success = channel_cancel_rport_listener(cancel_address, cancel_port); xfree(cancel_address); + } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) { + no_more_sessions = 1; + success = 1; } if (want_reply) { packet_start(success ? diff --git a/ssh.c b/ssh.c index 3bcca53ee..e3737bb9c 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.313 2008/05/09 14:26:08 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.314 2008/06/10 22:15:23 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1151,6 +1151,15 @@ ssh_session2(void) if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) id = ssh_session2_open(); + /* If we don't expect to open a new session, then disallow it */ + if (options.control_master == SSHCTL_MASTER_NO) { + debug("Requesting no-more-sessions@openssh.com"); + packet_start(SSH2_MSG_GLOBAL_REQUEST); + packet_put_cstring("no-more-sessions@openssh.com"); + packet_put_char(0); + packet_send(); + } + /* Execute a local command */ if (options.local_command != NULL && options.permit_local_command) -- cgit v1.2.3 From 9f407c4422a7f8283eda674e10755d0b4f1c2413 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 13 Jun 2008 04:50:27 +1000 Subject: - djm@cvs.openbsd.org 2008/06/12 04:06:00 [clientloop.h ssh.c clientloop.c] maintain an ordered queue of outstanding global requests that we expect replies to, similar to the per-channel confirmation queue. Use this queue to verify success or failure for remote forward establishment in a race free way. ok dtucker@ --- ChangeLog | 9 ++++++++- clientloop.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- clientloop.h | 6 +++++- ssh.c | 53 ++++++++++++++++++++++++++--------------------------- 4 files changed, 86 insertions(+), 31 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index ca0d8ea57..215f67820 100644 --- a/ChangeLog +++ b/ChangeLog @@ -78,6 +78,13 @@ mux client will not be able to connect to a running old ssh mux master. ok dtucker@ + - djm@cvs.openbsd.org 2008/06/12 04:06:00 + [clientloop.h ssh.c clientloop.c] + maintain an ordered queue of outstanding global requests that we + expect replies to, similar to the per-channel confirmation queue. + Use this queue to verify success or failure for remote forward + establishment in a race free way. + ok dtucker@ 20080611 - (djm) [channels.c configure.ac] @@ -4240,4 +4247,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4977 2008/06/12 18:49:33 dtucker Exp $ +$Id: ChangeLog,v 1.4978 2008/06/12 18:50:27 dtucker Exp $ diff --git a/clientloop.c b/clientloop.c index b45e7298a..37cecf5a6 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.195 2008/06/12 03:40:52 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.196 2008/06/12 04:06:00 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -174,6 +174,17 @@ struct channel_reply_ctx { int id, do_close; }; +/* Global request success/failure callbacks */ +struct global_confirm { + TAILQ_ENTRY(global_confirm) entry; + global_confirm_cb *cb; + void *ctx; + int ref_count; +}; +TAILQ_HEAD(global_confirms, global_confirm); +static struct global_confirms global_confirms = + TAILQ_HEAD_INITIALIZER(global_confirms); + /*XXX*/ extern Kex *xxx_kex; @@ -468,8 +479,19 @@ client_check_window_change(void) static void client_global_request_reply(int type, u_int32_t seq, void *ctxt) { + struct global_confirm *gc; + + if ((gc = TAILQ_FIRST(&global_confirms)) == NULL) + return; + if (gc->cb != NULL) + gc->cb(type, seq, gc->ctx); + if (--gc->ref_count <= 0) { + TAILQ_REMOVE(&global_confirms, gc, entry); + bzero(gc, sizeof(*gc)); + xfree(gc); + } + keep_alive_timeouts = 0; - client_global_request_reply_fwd(type, seq, ctxt); } static void @@ -483,6 +505,8 @@ server_alive_check(void) packet_put_cstring("keepalive@openssh.com"); packet_put_char(1); /* boolean: want reply */ packet_send(); + /* Insert an empty placeholder to maintain ordering */ + client_register_global_confirm(NULL, NULL); } /* @@ -702,6 +726,27 @@ client_expect_confirm(int id, const char *request, int do_close) client_abandon_status_confirm, cr); } +void +client_register_global_confirm(global_confirm_cb *cb, void *ctx) +{ + struct global_confirm *gc, *first_gc; + + /* Coalesce identical callbacks */ + first_gc = TAILQ_FIRST(&global_confirms); + if (first_gc && first_gc->cb == cb && first_gc->ctx == ctx) { + if (++first_gc->ref_count >= INT_MAX) + fatal("%s: first_gc->ref_count = %d", + __func__, first_gc->ref_count); + return; + } + + gc = xmalloc(sizeof(*gc)); + gc->cb = cb; + gc->ctx = ctx; + gc->ref_count = 1; + TAILQ_INSERT_TAIL(&global_confirms, gc, entry); +} + static void process_cmdline(void) { diff --git a/clientloop.h b/clientloop.h index cecbfb1a8..3353a9a80 100644 --- a/clientloop.h +++ b/clientloop.h @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.h,v 1.20 2008/06/12 03:40:52 djm Exp $ */ +/* $OpenBSD: clientloop.h,v 1.21 2008/06/12 04:06:00 djm Exp $ */ /* * Author: Tatu Ylonen @@ -50,6 +50,10 @@ int client_request_tun_fwd(int, int, int); void *client_new_escape_filter_ctx(int); int client_simple_escape_filter(Channel *, char *, int); +/* Global request confirmation callbacks */ +typedef void global_confirm_cb(int, u_int32_t seq, void *); +void client_register_global_confirm(global_confirm_cb *, void *); + /* Multiplexing protocol version */ #define SSHMUX_VER 2 diff --git a/ssh.c b/ssh.c index e3737bb9c..6c39c85b9 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.314 2008/06/10 22:15:23 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.315 2008/06/12 04:06:00 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -164,7 +164,7 @@ Buffer command; int subsystem_flag = 0; /* # of replies received for global requests */ -static int client_global_request_id = 0; +static int remote_forward_confirms_received = 0; /* pid of proxycommand child process */ pid_t proxy_command_pid = 0; @@ -817,6 +817,28 @@ main(int ac, char **av) return exit_status; } +/* Callback for remote forward global requests */ +static void +ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) +{ + Forward *rfwd = (Forward *)ctxt; + + debug("remote forward %s for: listen %d, connect %s:%d", + type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", + rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); + if (type == SSH2_MSG_REQUEST_FAILURE) { + if (options.exit_on_forward_failure) + fatal("Error: remote port forwarding failed for " + "listen port %d", rfwd->listen_port); + else + logit("Warning: remote port forwarding failed for " + "listen port %d", rfwd->listen_port); + } + if (++remote_forward_confirms_received == options.num_remote_forwards) + debug("All remote forwarding requests processed"); + /* XXX fork-after-authentication */ +} + static void ssh_init_forwarding(void) { @@ -865,6 +887,8 @@ ssh_init_forwarding(void) logit("Warning: Could not request remote " "forwarding."); } + client_register_global_confirm(ssh_confirm_remote_forward, + &options.remote_forwards[i]); } /* Initiate tunnel forwarding. */ @@ -1034,31 +1058,6 @@ ssh_session(void) options.escape_char : SSH_ESCAPECHAR_NONE, 0); } -void -client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt) -{ - int i; - - i = client_global_request_id++; - if (i >= options.num_remote_forwards) - return; - debug("remote forward %s for: listen %d, connect %s:%d", - type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", - options.remote_forwards[i].listen_port, - options.remote_forwards[i].connect_host, - options.remote_forwards[i].connect_port); - if (type == SSH2_MSG_REQUEST_FAILURE) { - if (options.exit_on_forward_failure) - fatal("Error: remote port forwarding failed for " - "listen port %d", - options.remote_forwards[i].listen_port); - else - logit("Warning: remote port forwarding failed for " - "listen port %d", - options.remote_forwards[i].listen_port); - } -} - /* request pty/x11/agent/tcpfwd/shell for channel */ static void ssh_session2_setup(int id, void *arg) -- cgit v1.2.3 From d6173c0bd7acf5880640bb3a89cf19cb5d4e092d Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 13 Jun 2008 04:52:53 +1000 Subject: - djm@cvs.openbsd.org 2008/06/12 04:24:06 [ssh.c] thal shalt not code past the eightieth column --- ChangeLog | 5 ++++- ssh.c | 72 +++++++++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 51 insertions(+), 26 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index d905ca3c5..074ca25b2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -88,6 +88,9 @@ - djm@cvs.openbsd.org 2008/06/12 04:17:47 [clientloop.c] thall shalt not code past the eightieth column + - djm@cvs.openbsd.org 2008/06/12 04:24:06 + [ssh.c] + thal shalt not code past the eightieth column 20080611 - (djm) [channels.c configure.ac] @@ -4250,4 +4253,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4979 2008/06/12 18:51:14 dtucker Exp $ +$Id: ChangeLog,v 1.4980 2008/06/12 18:52:53 dtucker Exp $ diff --git a/ssh.c b/ssh.c index 6c39c85b9..96bfed9d5 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.315 2008/06/12 04:06:00 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.316 2008/06/12 04:24:06 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -107,7 +107,7 @@ extern char *__progname; -/* Flag indicating whether debug mode is on. This can be set on the command line. */ +/* Flag indicating whether debug mode is on. May be set on the command line. */ int debug_flag = 0; /* Flag indicating whether a tty should be allocated */ @@ -261,15 +261,18 @@ main(int ac, char **av) */ umask(022); - /* Initialize option structure to indicate that no values have been set. */ + /* + * Initialize option structure to indicate that no values have been + * set. + */ initialize_options(&options); /* Parse command-line arguments. */ host = NULL; again: - while ((opt = getopt(ac, av, - "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) { + while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" + "ACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) { switch (opt) { case '1': options.protocol = SSH_PROTO_1; @@ -374,7 +377,8 @@ main(int ac, char **av) options.tun_open = SSH_TUNMODE_DEFAULT; options.tun_local = a2tun(optarg, &options.tun_remote); if (options.tun_local == SSH_TUNID_ERR) { - fprintf(stderr, "Bad tun device '%s'\n", optarg); + fprintf(stderr, + "Bad tun device '%s'\n", optarg); exit(255); } break; @@ -477,7 +481,8 @@ main(int ac, char **av) } if (cp != NULL) { fwd.listen_port = a2port(cp); - fwd.listen_host = cleanhostname(fwd.listen_host); + fwd.listen_host = + cleanhostname(fwd.listen_host); } else { fwd.listen_port = a2port(fwd.listen_host); fwd.listen_host = NULL; @@ -583,8 +588,10 @@ main(int ac, char **av) } /* Cannot fork to background if no command. */ - if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag) - fatal("Cannot fork into background without a command to execute."); + if (fork_after_authentication_flag && buffer_len(&command) == 0 && + !no_shell_flag) + fatal("Cannot fork into background without a command " + "to execute."); /* Allocate a tty by default if no command specified. */ if (buffer_len(&command) == 0) @@ -596,7 +603,8 @@ main(int ac, char **av) /* Do not allocate a tty if stdin is not a tty. */ if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) { if (tty_flag) - logit("Pseudo-terminal will not be allocated because stdin is not a terminal."); + logit("Pseudo-terminal will not be allocated because " + "stdin is not a terminal."); tty_flag = 0; } @@ -604,7 +612,8 @@ main(int ac, char **av) * Initialize "log" output. Since we are the client all output * actually goes to stderr. */ - log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, + log_init(av[0], + options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, SYSLOG_FACILITY_USER, 1); /* @@ -753,7 +762,8 @@ main(int ac, char **av) * Now that we are back to our own permissions, create ~/.ssh * directory if it doesn't already exist. */ - snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); + snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, + strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); if (stat(buf, &st) < 0) if (mkdir(buf, 0700) < 0) error("Could not create directory '%.200s'.", buf); @@ -774,7 +784,7 @@ main(int ac, char **av) signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ - /* Log into the remote system. This never returns if the login fails. */ + /* Log into the remote system. Never returns if the login fails. */ ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw, timeout_ms); @@ -925,10 +935,13 @@ ssh_session(void) /* Enable compression if requested. */ if (options.compression) { - debug("Requesting compression at level %d.", options.compression_level); + debug("Requesting compression at level %d.", + options.compression_level); - if (options.compression_level < 1 || options.compression_level > 9) - fatal("Compression level must be from 1 (fast) to 9 (slow, best)."); + if (options.compression_level < 1 || + options.compression_level > 9) + fatal("Compression level must be from 1 (fast) to " + "9 (slow, best)."); /* Send the request. */ packet_start(SSH_CMSG_REQUEST_COMPRESSION); @@ -941,7 +954,8 @@ ssh_session(void) else if (type == SSH_SMSG_FAILURE) logit("Warning: Remote host refused compression."); else - packet_disconnect("Protocol error waiting for compression response."); + packet_disconnect("Protocol error waiting for " + "compression response."); } /* Allocate a pseudo tty if appropriate. */ if (tty_flag) { @@ -978,9 +992,11 @@ ssh_session(void) interactive = 1; have_tty = 1; } else if (type == SSH_SMSG_FAILURE) - logit("Warning: Remote host failed or refused to allocate a pseudo tty."); + logit("Warning: Remote host failed or refused to " + "allocate a pseudo tty."); else - packet_disconnect("Protocol error waiting for pty request response."); + packet_disconnect("Protocol error waiting for pty " + "request response."); } /* Request X11 forwarding if enabled and DISPLAY is set. */ display = getenv("DISPLAY"); @@ -990,7 +1006,8 @@ ssh_session(void) client_x11_get_proto(display, options.xauth_location, options.forward_x11_trusted, &proto, &data); /* Request forwarding with authentication spoofing. */ - debug("Requesting X11 forwarding with authentication spoofing."); + debug("Requesting X11 forwarding with authentication " + "spoofing."); x11_request_forwarding_with_spoofing(0, display, proto, data); /* Read response from the server. */ @@ -1000,7 +1017,8 @@ ssh_session(void) } else if (type == SSH_SMSG_FAILURE) { logit("Warning: Remote host denied X11 forwarding."); } else { - packet_disconnect("Protocol error waiting for X11 forwarding"); + packet_disconnect("Protocol error waiting for X11 " + "forwarding"); } } /* Tell the packet module whether this is an interactive session. */ @@ -1041,7 +1059,8 @@ ssh_session(void) int len = buffer_len(&command); if (len > 900) len = 900; - debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command)); + debug("Sending command: %.*s", len, + (u_char *)buffer_ptr(&command)); packet_start(SSH_CMSG_EXEC_CMD); packet_put_string(buffer_ptr(&command), buffer_len(&command)); packet_send(); @@ -1073,7 +1092,8 @@ ssh_session2_setup(int id, void *arg) client_x11_get_proto(display, options.xauth_location, options.forward_x11_trusted, &proto, &data); /* Request forwarding with authentication spoofing. */ - debug("Requesting X11 forwarding with authentication spoofing."); + debug("Requesting X11 forwarding with authentication " + "spoofing."); x11_request_forwarding_with_spoofing(id, display, proto, data); interactive = 1; /* XXX wait for reply */ @@ -1193,9 +1213,11 @@ load_public_identity_files(void) int count = 0; for (i = 0; keys[i] != NULL; i++) { count++; - memmove(&options.identity_files[1], &options.identity_files[0], + memmove(&options.identity_files[1], + &options.identity_files[0], sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1)); - memmove(&options.identity_keys[1], &options.identity_keys[0], + memmove(&options.identity_keys[1], + &options.identity_keys[0], sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); options.num_identity_files++; options.identity_keys[0] = keys[i]; -- cgit v1.2.3 From f6b01b758f4003a5cc59cf6a27afdc5123eb4fc4 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 13 Jun 2008 04:56:37 +1000 Subject: - dtucker@cvs.openbsd.org 2008/06/12 16:35:31 [ssh_config.5 ssh.c] keyword expansion for localcommand. ok djm@ --- ChangeLog | 5 ++++- ssh.c | 30 +++++++++++++++++++++++------- ssh_config.5 | 19 +++++++++++++++++-- 3 files changed, 44 insertions(+), 10 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index 0aec356d3..cbf5a0851 100644 --- a/ChangeLog +++ b/ChangeLog @@ -112,6 +112,9 @@ [clientloop.h channels.h clientloop.c channels.c mux.c] The multiplexing escape char handler commit last night introduced a small memory leak per session; plug it. + - dtucker@cvs.openbsd.org 2008/06/12 16:35:31 + [ssh_config.5 ssh.c] + keyword expansion for localcommand. ok djm@ 20080611 - (djm) [channels.c configure.ac] @@ -4274,4 +4277,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4984 2008/06/12 18:55:46 dtucker Exp $ +$Id: ChangeLog,v 1.4985 2008/06/12 18:56:37 dtucker Exp $ diff --git a/ssh.c b/ssh.c index 96bfed9d5..c15a1e483 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.316 2008/06/12 04:24:06 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.317 2008/06/12 16:35:31 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -647,6 +647,28 @@ main(int ac, char **av) if (options.user == NULL) options.user = xstrdup(pw->pw_name); + /* Get default port if port has not been set. */ + if (options.port == 0) { + sp = getservbyname(SSH_SERVICE_NAME, "tcp"); + options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; + } + + if (options.local_command != NULL) { + char thishost[NI_MAXHOST]; + + if (gethostname(thishost, sizeof(thishost)) == -1) + fatal("gethostname: %s", strerror(errno)); + snprintf(buf, sizeof(buf), "%d", options.port); + debug3("expanding LocalCommand: %s", options.local_command); + cp = options.local_command; + options.local_command = percent_expand(cp, "d", pw->pw_dir, + "h", options.hostname? options.hostname : host, + "l", thishost, "n", host, "r", options.user, "p", buf, + "u", pw->pw_name, (char *)NULL); + debug3("expanded LocalCommand: %s", options.local_command); + xfree(cp); + } + if (options.hostname != NULL) host = options.hostname; @@ -657,12 +679,6 @@ main(int ac, char **av) *p = (char)tolower(*p); } - /* Get default port if port has not been set. */ - if (options.port == 0) { - sp = getservbyname(SSH_SERVICE_NAME, "tcp"); - options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; - } - if (options.proxy_command != NULL && strcmp(options.proxy_command, "none") == 0) { xfree(options.proxy_command); diff --git a/ssh_config.5 b/ssh_config.5 index 8bcf323cc..98cd9ac5b 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -34,8 +34,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.108 2008/06/11 23:03:56 grunk Exp $ -.Dd $Mdocdate: June 11 2008 $ +.\" $OpenBSD: ssh_config.5,v 1.109 2008/06/12 16:35:31 dtucker Exp $ +.Dd $Mdocdate: June 12 2008 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -606,6 +606,21 @@ Specifies a command to execute on the local machine after successfully connecting to the server. The command string extends to the end of the line, and is executed with the user's shell. +The following escape character substitutions will be performed: +.Ql %d +(local user's home directory), +.Ql %h +(remote host name), +.Ql %l +(local host name), +.Ql %n +(host name as provided on the command line), +.Ql %p +(remote port), +.Ql %r +(remote user name) or +.Ql %u +(local user name). This directive is ignored unless .Cm PermitLocalCommand has been enabled. -- cgit v1.2.3 From 9a2a60986bf33414acf63b6d92d93a2f690c3a17 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 4 Jul 2008 12:53:50 +1000 Subject: - djm@cvs.openbsd.org 2008/07/02 13:47:39 [ssh.1 ssh.c] When forking after authentication ("ssh -f") with ExitOnForwardFailure enabled, delay the fork until after replies for any -R forwards have been seen. Allows for robust detection of -R forward failure when using -f (similar to bz#92); ok dtucker@ --- ChangeLog | 8 +++++++- ssh.1 | 13 +++++++++++-- ssh.c | 27 +++++++++++++++++++++------ 3 files changed, 39 insertions(+), 9 deletions(-) (limited to 'ssh.c') diff --git a/ChangeLog b/ChangeLog index 6f69442f4..c35092898 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,12 @@ - djm@cvs.openbsd.org 2008/07/02 13:30:34 [auth2.c] really really remove the freebie "none" auth try for protocol 2 + - djm@cvs.openbsd.org 2008/07/02 13:47:39 + [ssh.1 ssh.c] + When forking after authentication ("ssh -f") with ExitOnForwardFailure + enabled, delay the fork until after replies for any -R forwards have + been seen. Allows for robust detection of -R forward failure when + using -f (similar to bz#92); ok dtucker@ 20080702 - (dtucker) OpenBSD CVS Sync @@ -4538,4 +4544,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.5049 2008/07/04 02:53:23 dtucker Exp $ +$Id: ChangeLog,v 1.5050 2008/07/04 02:53:50 dtucker Exp $ diff --git a/ssh.1 b/ssh.1 index a58f5a02a..1883578f2 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,8 +34,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.276 2008/06/26 21:11:46 jmc Exp $ -.Dd $Mdocdate: June 26 2008 $ +.\" $OpenBSD: ssh.1,v 1.277 2008/07/02 13:47:39 djm Exp $ +.Dd $Mdocdate: July 2 2008 $ .Dt SSH 1 .Os .Sh NAME @@ -290,6 +290,15 @@ This implies The recommended way to start X11 programs at a remote site is with something like .Ic ssh -f host xterm . +.Pp +If the +.Cm ExitOnForwardFailure +configuration option is set to +.Dq yes , +then a client started with +.Fl f +will wait for all remote port forwards to be successfully established +before placing itself in the background. .It Fl g Allows remote hosts to connect to local forwarded ports. .It Fl I Ar smartcard_device diff --git a/ssh.c b/ssh.c index c15a1e483..e2dd67d68 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.317 2008/06/12 16:35:31 dtucker Exp $ */ +/* $OpenBSD: ssh.c,v 1.318 2008/07/02 13:47:39 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -860,9 +860,15 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) logit("Warning: remote port forwarding failed for " "listen port %d", rfwd->listen_port); } - if (++remote_forward_confirms_received == options.num_remote_forwards) + if (++remote_forward_confirms_received == options.num_remote_forwards) { debug("All remote forwarding requests processed"); - /* XXX fork-after-authentication */ + if (fork_after_authentication_flag) { + fork_after_authentication_flag = 0; + if (daemon(1, 1) < 0) + fatal("daemon() failed: %.200s", + strerror(errno)); + } + } } static void @@ -1062,10 +1068,17 @@ ssh_session(void) options.permit_local_command) ssh_local_cmd(options.local_command); - /* If requested, let ssh continue in the background. */ - if (fork_after_authentication_flag) + /* + * If requested and we are not interested in replies to remote + * forwarding requests, then let ssh continue in the background. + */ + if (fork_after_authentication_flag && + (!options.exit_on_forward_failure || + options.num_remote_forwards == 0)) { + fork_after_authentication_flag = 0; if (daemon(1, 1) < 0) fatal("daemon() failed: %.200s", strerror(errno)); + } /* * If a command was specified on the command line, execute the @@ -1204,9 +1217,11 @@ ssh_session2(void) muxserver_listen(); /* If requested, let ssh continue in the background. */ - if (fork_after_authentication_flag) + if (fork_after_authentication_flag) { + fork_after_authentication_flag = 0; if (daemon(1, 1) < 0) fatal("daemon() failed: %.200s", strerror(errno)); + } return client_loop(tty_flag, tty_flag ? options.escape_char : SSH_ESCAPECHAR_NONE, id); -- cgit v1.2.3