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) --- channels.h | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'channels.h') 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) */ -- cgit v1.2.3 From bd74025c7b08104828986d01e60f04372b3d5337 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 19 May 2008 15:37:09 +1000 Subject: - djm@cvs.openbsd.org 2008/05/09 04:55:56 [channels.c channels.h clientloop.c serverloop.c] Try additional addresses when connecting to a port forward destination whose DNS name resolves to more than one address. The previous behaviour was to try the first address and give up. Reported by stig AT venaas.com in bz#343 great feedback and ok markus@ --- ChangeLog | 9 +++- channels.c | 167 +++++++++++++++++++++++++++++++++++++++-------------------- channels.h | 21 ++++++-- clientloop.c | 21 +++----- serverloop.c | 19 +++---- 5 files changed, 149 insertions(+), 88 deletions(-) (limited to 'channels.h') diff --git a/ChangeLog b/ChangeLog index bd6b640b1..9e683143a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -104,6 +104,13 @@ client stderr (subject to LogLevel in the mux master) - better than silently failing. most bits ok markus@ (as part of a larger diff) + - djm@cvs.openbsd.org 2008/05/09 04:55:56 + [channels.c channels.h clientloop.c serverloop.c] + Try additional addresses when connecting to a port forward destination + whose DNS name resolves to more than one address. The previous behaviour + was to try the first address and give up. + Reported by stig AT venaas.com in bz#343 + great feedback and ok markus@ 20080403 - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- @@ -3964,4 +3971,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.4924 2008/05/19 05:36:08 djm Exp $ +$Id: ChangeLog,v 1.4925 2008/05/19 05:37:09 djm Exp $ diff --git a/channels.c b/channels.c index b5e28dabf..1e57951dc 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.275 2008/05/08 12:02:23 djm Exp $ */ +/* $OpenBSD: channels.c,v 1.276 2008/05/09 04:55:56 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -165,6 +165,10 @@ static int IPv4or6 = AF_UNSPEC; /* helper */ static void port_open_helper(Channel *c, char *rtype); +/* non-blocking connect helpers */ +static int connect_next(struct channel_connect *); +static void channel_connect_ctx_free(struct channel_connect *); + /* -- channel core */ Channel * @@ -1425,7 +1429,7 @@ channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset) static void channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset) { - int err = 0; + int err = 0, sock; socklen_t sz = sizeof(err); if (FD_ISSET(c->sock, writeset)) { @@ -1434,7 +1438,9 @@ channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset) error("getsockopt SO_ERROR failed"); } if (err == 0) { - debug("channel %d: connected", c->self); + debug("channel %d: connected to %s port %d", + c->self, c->connect_ctx.host, c->connect_ctx.port); + channel_connect_ctx_free(&c->connect_ctx); c->type = SSH_CHANNEL_OPEN; if (compat20) { packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); @@ -1448,8 +1454,19 @@ channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset) packet_put_int(c->self); } } else { - debug("channel %d: not connected: %s", + debug("channel %d: connection failed: %s", c->self, strerror(err)); + /* Try next address, if any */ + if ((sock = connect_next(&c->connect_ctx)) > 0) { + close(c->sock); + c->sock = c->rfd = c->wfd = sock; + channel_max_fd = channel_find_maxfd(); + return; + } + /* Exhausted all addresses */ + error("connect_to %.100s port %d: failed.", + c->connect_ctx.host, c->connect_ctx.port); + channel_connect_ctx_free(&c->connect_ctx); if (compat20) { packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); packet_put_int(c->remote_id); @@ -2327,7 +2344,7 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt) Channel *c = NULL; u_short host_port; char *host, *originator_string; - int remote_id, sock = -1; + int remote_id; remote_id = packet_get_int(); host = packet_get_string(NULL); @@ -2339,20 +2356,16 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt) originator_string = xstrdup("unknown (remote did not supply name)"); } packet_check_eom(); - sock = channel_connect_to(host, host_port); - if (sock != -1) { - c = channel_new("connected socket", - SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0, - originator_string, 1); - c->remote_id = remote_id; - } + c = channel_connect_to(host, host_port, + "connected socket", originator_string); xfree(originator_string); + xfree(host); if (c == NULL) { packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); packet_put_int(remote_id); packet_send(); - } - xfree(host); + } else + c->remote_id = remote_id; } /* ARGSUSED */ @@ -2770,35 +2783,26 @@ channel_clear_adm_permitted_opens(void) num_adm_permitted_opens = 0; } -/* return socket to remote host, port */ +/* Try to start non-blocking connect to next host in cctx list */ static int -connect_to(const char *host, u_short port) +connect_next(struct channel_connect *cctx) { - struct addrinfo hints, *ai, *aitop; + int sock, saved_errno; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; - int gaierr; - int sock = -1; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = IPv4or6; - hints.ai_socktype = SOCK_STREAM; - snprintf(strport, sizeof strport, "%d", port); - if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { - error("connect_to %.100s: unknown host (%s)", host, - ssh_gai_strerror(gaierr)); - return -1; - } - for (ai = aitop; ai; ai = ai->ai_next) { - if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + for (; cctx->ai; cctx->ai = cctx->ai->ai_next) { + if (cctx->ai->ai_family != AF_INET && + cctx->ai->ai_family != AF_INET6) continue; - if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), - strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { - error("connect_to: getnameinfo failed"); + if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen, + ntop, sizeof(ntop), strport, sizeof(strport), + NI_NUMERICHOST|NI_NUMERICSERV) != 0) { + error("connect_next: getnameinfo failed"); continue; } - sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sock < 0) { - if (ai->ai_next == NULL) + if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype, + cctx->ai->ai_protocol)) == -1) { + if (cctx->ai->ai_next == NULL) error("socket: %.100s", strerror(errno)); else verbose("socket: %.100s", strerror(errno)); @@ -2806,45 +2810,94 @@ connect_to(const char *host, u_short port) } if (set_nonblock(sock) == -1) fatal("%s: set_nonblock(%d)", __func__, sock); - if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && - errno != EINPROGRESS) { - error("connect_to %.100s port %s: %.100s", ntop, strport, + if (connect(sock, cctx->ai->ai_addr, + cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) { + debug("connect_next: host %.100s ([%.100s]:%s): " + "%.100s", cctx->host, ntop, strport, strerror(errno)); + saved_errno = errno; close(sock); + errno = saved_errno; continue; /* fail -- try next */ } - break; /* success */ + debug("connect_next: host %.100s ([%.100s]:%s) " + "in progress, fd=%d", cctx->host, ntop, strport, sock); + cctx->ai = cctx->ai->ai_next; + set_nodelay(sock); + return sock; + } + return -1; +} + +static void +channel_connect_ctx_free(struct channel_connect *cctx) +{ + xfree(cctx->host); + if (cctx->aitop) + freeaddrinfo(cctx->aitop); + bzero(cctx, sizeof(*cctx)); + cctx->host = NULL; + cctx->ai = cctx->aitop = NULL; +} +/* Return CONNECTING channel to remote host, port */ +static Channel * +connect_to(const char *host, u_short port, char *ctype, char *rname) +{ + struct addrinfo hints; + int gaierr; + int sock = -1; + char strport[NI_MAXSERV]; + struct channel_connect cctx; + Channel *c; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = IPv4or6; + hints.ai_socktype = SOCK_STREAM; + snprintf(strport, sizeof strport, "%d", port); + if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) { + error("connect_to %.100s: unknown host (%s)", host, + ssh_gai_strerror(gaierr)); + return NULL; } - freeaddrinfo(aitop); - if (!ai) { - error("connect_to %.100s port %d: failed.", host, port); - return -1; + + cctx.host = xstrdup(host); + cctx.port = port; + cctx.ai = cctx.aitop; + + if ((sock = connect_next(&cctx)) == -1) { + error("connect to %.100s port %d failed: %s", + host, port, strerror(errno)); + channel_connect_ctx_free(&cctx); + return NULL; } - /* success */ - set_nodelay(sock); - return sock; + c = channel_new(ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1); + c->connect_ctx = cctx; + return c; } -int -channel_connect_by_listen_address(u_short listen_port) +Channel * +channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname) { int i; - for (i = 0; i < num_permitted_opens; i++) + for (i = 0; i < num_permitted_opens; i++) { if (permitted_opens[i].host_to_connect != NULL && - permitted_opens[i].listen_port == listen_port) + permitted_opens[i].listen_port == listen_port) { return connect_to( permitted_opens[i].host_to_connect, - permitted_opens[i].port_to_connect); + permitted_opens[i].port_to_connect, ctype, rname); + } + } error("WARNING: Server requests forwarding for unknown listen_port %d", listen_port); - return -1; + return NULL; } /* Check if connecting to that port is permitted and connect. */ -int -channel_connect_to(const char *host, u_short port) +Channel * +channel_connect_to(const char *host, u_short port, char *ctype, char *rname) { int i, permit, permit_adm = 1; @@ -2870,9 +2923,9 @@ channel_connect_to(const char *host, u_short port) if (!permit || !permit_adm) { logit("Received request to connect to host %.100s port %d, " "but the request was denied.", host, port); - return -1; + return NULL; } - return connect_to(host, port); + return connect_to(host, port, ctype, rname); } void diff --git a/channels.h b/channels.h index 46cde0309..d4ac24a51 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.90 2008/05/08 12:02:23 djm Exp $ */ +/* $OpenBSD: channels.h,v 1.91 2008/05/09 04:55:56 djm Exp $ */ /* * Author: Tatu Ylonen @@ -75,6 +75,13 @@ struct channel_confirm { }; TAILQ_HEAD(channel_confirms, channel_confirm); +/* Context for non-blocking connects */ +struct channel_connect { + char *host; + int port; + struct addrinfo *ai, *aitop; +}; + struct Channel { int type; /* channel type/state */ int self; /* my own channel identifier */ @@ -125,7 +132,11 @@ struct Channel { channel_infilter_fn *input_filter; channel_outfilter_fn *output_filter; - int datagram; /* keep boundaries */ + /* keep boundaries */ + int datagram; + + /* non-blocking connect */ + struct channel_connect connect_ctx; }; #define CHAN_EXTENDED_IGNORE 0 @@ -225,8 +236,8 @@ int channel_add_adm_permitted_opens(char *, int); void channel_clear_permitted_opens(void); void channel_clear_adm_permitted_opens(void); int channel_input_port_forward_request(int, int); -int channel_connect_to(const char *, u_short); -int channel_connect_by_listen_address(u_short); +Channel *channel_connect_to(const char *, u_short, char *, char *); +Channel *channel_connect_by_listen_address(u_short, char *, char *); int channel_request_remote_forwarding(const char *, u_short, const char *, u_short); int channel_setup_local_fwd_listener(const char *, u_short, @@ -241,7 +252,7 @@ int x11_connect_display(void); int x11_create_display_inet(int, int, int, u_int *, int **); void x11_input_open(int, u_int32_t, void *); void x11_request_forwarding_with_spoofing(int, const char *, const char *, - const char *); + const char *); void deny_input_open(int, u_int32_t, void *); /* agent forwarding */ diff --git a/clientloop.c b/clientloop.c index c40f2c303..7bd1af60c 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.190 2008/05/08 13:06:10 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.191 2008/05/09 04:55:56 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1762,7 +1762,6 @@ client_request_forwarded_tcpip(const char *request_type, int rchan) Channel *c = NULL; char *listen_address, *originator_address; int listen_port, originator_port; - int sock; /* Get rest of the packet */ listen_address = packet_get_string(NULL); @@ -1771,19 +1770,13 @@ client_request_forwarded_tcpip(const char *request_type, int rchan) originator_port = packet_get_int(); packet_check_eom(); - debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d", - listen_address, listen_port, originator_address, originator_port); + debug("client_request_forwarded_tcpip: listen %s port %d, " + "originator %s port %d", listen_address, listen_port, + originator_address, originator_port); + + c = channel_connect_by_listen_address(listen_port, + "forwarded-tcpip", originator_address); - sock = channel_connect_by_listen_address(listen_port); - if (sock < 0) { - xfree(originator_address); - xfree(listen_address); - return NULL; - } - c = channel_new("forwarded-tcpip", - SSH_CHANNEL_CONNECTING, sock, sock, -1, - CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, - originator_address, 1); xfree(originator_address); xfree(listen_address); return c; diff --git a/serverloop.c b/serverloop.c index 20991c3ce..2142f3809 100644 --- a/serverloop.c +++ b/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.149 2008/05/08 12:02:23 djm Exp $ */ +/* $OpenBSD: serverloop.c,v 1.150 2008/05/09 04:55:56 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -938,7 +938,6 @@ static Channel * server_request_direct_tcpip(void) { Channel *c; - int sock; char *target, *originator; int target_port, originator_port; @@ -948,18 +947,16 @@ server_request_direct_tcpip(void) originator_port = packet_get_int(); packet_check_eom(); - debug("server_request_direct_tcpip: originator %s port %d, target %s port %d", - originator, originator_port, target, target_port); + debug("server_request_direct_tcpip: originator %s port %d, target %s " + "port %d", originator, originator_port, target, target_port); /* XXX check permission */ - sock = channel_connect_to(target, target_port); - xfree(target); + c = channel_connect_to(target, target_port, + "direct-tcpip", "direct-tcpip"); + xfree(originator); - if (sock < 0) - return NULL; - c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING, - sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, - CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1); + xfree(target); + return c; } -- cgit v1.2.3 From bab9bd4c20dac1d513fbf16d1214e0c0f9a1bf3b Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 19 May 2008 16:06:47 +1000 Subject: - markus@cvs.openbsd.org 2008/05/09 16:21:13 [channels.h clientloop.c nchan.c serverloop.c] unbreak ssh -2 localhost od /bin/ls | true ignoring SIGPIPE by adding a new channel message (EOW) that signals the peer that we're not interested in any data it might send. fixes bz #85; discussion, debugging and ok djm@ --- ChangeLog | 9 ++++++++- channels.h | 3 ++- clientloop.c | 5 ++++- nchan.c | 30 +++++++++++++++++++++++++++++- serverloop.c | 7 +++++-- 5 files changed, 48 insertions(+), 6 deletions(-) (limited to 'channels.h') diff --git a/ChangeLog b/ChangeLog index fd75c3404..7d9b0f853 100644 --- a/ChangeLog +++ b/ChangeLog @@ -133,6 +133,13 @@ for channels with both in- and output closed, since the channel will go away before we call select(); report, lots of debugging help and ok djm@ + - markus@cvs.openbsd.org 2008/05/09 16:21:13 + [channels.h clientloop.c nchan.c serverloop.c] + unbreak + ssh -2 localhost od /bin/ls | true + ignoring SIGPIPE by adding a new channel message (EOW) that signals + the peer that we're not interested in any data it might send. + fixes bz #85; discussion, debugging and ok djm@ 20080403 - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- @@ -3993,4 +4000,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.4929 2008/05/19 06:05:41 djm Exp $ +$Id: ChangeLog,v 1.4930 2008/05/19 06:06:47 djm Exp $ diff --git a/channels.h b/channels.h index d4ac24a51..ec2435df0 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.91 2008/05/09 04:55:56 djm Exp $ */ +/* $OpenBSD: channels.h,v 1.92 2008/05/09 16:21:13 markus Exp $ */ /* * Author: Tatu Ylonen @@ -267,6 +267,7 @@ void chan_mark_dead(Channel *); /* channel events */ void chan_rcvd_oclose(Channel *); +void chan_rcvd_eow(Channel *); /* SSH2-only */ void chan_read_failed(Channel *); void chan_ibuf_empty(Channel *); diff --git a/clientloop.c b/clientloop.c index c87aa5a0a..584afb76a 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.192 2008/05/09 14:18:44 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.193 2008/05/09 16:21:13 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1666,6 +1666,9 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt) error("client_input_channel_req: request for channel -1"); } else if ((c = channel_lookup(id)) == NULL) { error("client_input_channel_req: channel %d: unknown channel", id); + } else if (strcmp(rtype, "eow@openssh.com") == 0) { + packet_check_eom(); + chan_rcvd_eow(c); } else if (strcmp(rtype, "exit-status") == 0) { exitval = packet_get_int(); if (id == session_ident) { diff --git a/nchan.c b/nchan.c index 0d0faddb3..a4a456eab 100644 --- a/nchan.c +++ b/nchan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nchan.c,v 1.58 2008/05/08 12:02:23 djm Exp $ */ +/* $OpenBSD: nchan.c,v 1.59 2008/05/09 16:21:13 markus Exp $ */ /* * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. * @@ -78,6 +78,7 @@ static void chan_send_ieof1(Channel *); static void chan_send_oclose1(Channel *); static void chan_send_close2(Channel *); static void chan_send_eof2(Channel *); +static void chan_send_eow2(Channel *); /* helper */ static void chan_shutdown_write(Channel *); @@ -306,6 +307,17 @@ chan_rcvd_close2(Channel *c) break; } } +void +chan_rcvd_eow(Channel *c) +{ + debug2("channel %d: rcvd eow", c->self); + switch (c->istate) { + case CHAN_INPUT_OPEN: + chan_shutdown_read(c); + chan_set_istate(c, CHAN_INPUT_CLOSED); + break; + } +} static void chan_rcvd_eof2(Channel *c) { @@ -322,6 +334,7 @@ chan_write_failed2(Channel *c) case CHAN_OUTPUT_OPEN: case CHAN_OUTPUT_WAIT_DRAIN: chan_shutdown_write(c); + chan_send_eow2(c); chan_set_ostate(c, CHAN_OUTPUT_CLOSED); break; default: @@ -364,6 +377,21 @@ chan_send_close2(Channel *c) c->flags |= CHAN_CLOSE_SENT; } } +static void +chan_send_eow2(Channel *c) +{ + debug2("channel %d: send eow", c->self); + if (c->ostate == CHAN_OUTPUT_CLOSED) { + error("channel %d: must not sent eow on closed output", + c->self); + return; + } + packet_start(SSH2_MSG_CHANNEL_REQUEST); + packet_put_int(c->remote_id); + packet_put_cstring("eow@openssh.com"); + packet_put_char(0); + packet_send(); +} /* shared */ diff --git a/serverloop.c b/serverloop.c index 2142f3809..6bc140f8b 100644 --- a/serverloop.c +++ b/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.150 2008/05/09 04:55:56 djm Exp $ */ +/* $OpenBSD: serverloop.c,v 1.151 2008/05/09 16:21:13 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1160,7 +1160,10 @@ server_input_channel_req(int type, u_int32_t seq, void *ctxt) if ((c = channel_lookup(id)) == NULL) packet_disconnect("server_input_channel_req: " "unknown channel %d", id); - if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN) + if (!strcmp(rtype, "eow@openssh.com")) { + packet_check_eom(); + chan_rcvd_eow(c); + } else if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN) success = session_input_channel_req(c, rtype); if (reply) { packet_start(success ? -- cgit v1.2.3 From e7140f20cb2da1456e6080059eef54cf0f3533f2 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 10 Jun 2008 23:01:51 +1000 Subject: - dtucker@cvs.openbsd.org 2008/06/10 04:50:25 [sshd.c channels.h channels.c log.c servconf.c log.h servconf.h sshd.8] Add extended test mode (-T) and connection parameters for test mode (-C). -T causes sshd to write its effective configuration to stdout and exit. -C causes any relevant Match rules to be applied before output. The combination allows tesing of the parser and config files. ok deraadt djm --- ChangeLog | 8 +- channels.c | 13 +++- channels.h | 3 +- log.c | 24 +++++- log.h | 6 +- servconf.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- servconf.h | 3 +- sshd.8 | 34 ++++++++- sshd.c | 47 +++++++++++- 9 files changed, 355 insertions(+), 24 deletions(-) (limited to 'channels.h') diff --git a/ChangeLog b/ChangeLog index e16603175..3c2cc2168 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,12 @@ - djm@cvs.openbsd.org 2008/06/10 04:17:46 [sshd_config.5] better reference for pattern-list + - dtucker@cvs.openbsd.org 2008/06/10 04:50:25 + [sshd.c channels.h channels.c log.c servconf.c log.h servconf.h sshd.8] + Add extended test mode (-T) and connection parameters for test mode (-C). + -T causes sshd to write its effective configuration to stdout and exit. + -C causes any relevant Match rules to be applied before output. The + combination allows tesing of the parser and config files. ok deraadt djm 20080609 - (dtucker) OpenBSD CVS Sync @@ -4098,4 +4104,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.4950 2008/06/10 12:59:53 dtucker Exp $ +$Id: ChangeLog,v 1.4951 2008/06/10 13:01:51 dtucker Exp $ diff --git a/channels.c b/channels.c index 99b23d75f..6808d3a05 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.277 2008/05/09 16:17:51 markus Exp $ */ +/* $OpenBSD: channels.c,v 1.278 2008/06/10 04:50:25 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2784,6 +2784,17 @@ channel_clear_adm_permitted_opens(void) num_adm_permitted_opens = 0; } +void +channel_print_adm_permitted_opens(void) +{ + static int i; + + for (i = 0; i < num_adm_permitted_opens; i++) + if (permitted_adm_opens[i].host_to_connect != NULL) + printf(" %s:%d", permitted_adm_opens[i].host_to_connect, + permitted_adm_opens[i].port_to_connect); +} + /* Try to start non-blocking connect to next host in cctx list */ static int connect_next(struct channel_connect *cctx) diff --git a/channels.h b/channels.h index ec2435df0..dc1f483ed 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.92 2008/05/09 16:21:13 markus Exp $ */ +/* $OpenBSD: channels.h,v 1.93 2008/06/10 04:50:25 dtucker Exp $ */ /* * Author: Tatu Ylonen @@ -235,6 +235,7 @@ void channel_add_permitted_opens(char *, int); int channel_add_adm_permitted_opens(char *, int); void channel_clear_permitted_opens(void); void channel_clear_adm_permitted_opens(void); +void channel_print_adm_permitted_opens(void); int channel_input_port_forward_request(int, int); Channel *channel_connect_to(const char *, u_short, char *, char *); Channel *channel_connect_by_listen_address(u_short, char *, char *); diff --git a/log.c b/log.c index fae5b043f..4a8239b93 100644 --- a/log.c +++ b/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.40 2007/05/17 07:50:31 djm Exp $ */ +/* $OpenBSD: log.c,v 1.41 2008/06/10 04:50:25 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -114,6 +114,17 @@ log_facility_number(char *name) return SYSLOG_FACILITY_NOT_SET; } +const char * +log_facility_name(SyslogFacility facility) +{ + u_int i; + + for (i = 0; log_facilities[i].name; i++) + if (log_facilities[i].val == facility) + return log_facilities[i].name; + return NULL; +} + LogLevel log_level_number(char *name) { @@ -126,6 +137,17 @@ log_level_number(char *name) return SYSLOG_LEVEL_NOT_SET; } +const char * +log_level_name(LogLevel level) +{ + u_int i; + + for (i = 0; log_levels[i].name != NULL; i++) + if (log_levels[i].val == level) + return log_levels[i].name; + return NULL; +} + /* Error messages that should be logged. */ void diff --git a/log.h b/log.h index 7a8c57079..fa0996ad5 100644 --- a/log.h +++ b/log.h @@ -1,4 +1,4 @@ -/* $OpenBSD: log.h,v 1.15 2006/08/18 09:13:25 deraadt Exp $ */ +/* $OpenBSD: log.h,v 1.16 2008/06/10 04:50:25 dtucker Exp $ */ /* * Author: Tatu Ylonen @@ -49,7 +49,9 @@ typedef enum { void log_init(char *, LogLevel, SyslogFacility, int); SyslogFacility log_facility_number(char *); -LogLevel log_level_number(char *); +const char * log_facility_name(SyslogFacility); +LogLevel log_level_number(char *); +const char * log_level_name(LogLevel); void fatal(const char *, ...) __dead __attribute__((format(printf, 1, 2))); void error(const char *, ...) __attribute__((format(printf, 1, 2))); diff --git a/servconf.c b/servconf.c index 07a201034..63704fb33 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.181 2008/06/10 03:57:27 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.182 2008/06/10 04:50:25 dtucker Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -23,6 +23,7 @@ #include #include #include +#include #include "openbsd-compat/sys-queue.h" #include "xmalloc.h" @@ -417,6 +418,17 @@ static struct { { NULL, sBadOption, 0 } }; +static struct { + int val; + char *text; +} tunmode_desc[] = { + { SSH_TUNMODE_NO, "no" }, + { SSH_TUNMODE_POINTOPOINT, "point-to-point" }, + { SSH_TUNMODE_ETHERNET, "ethernet" }, + { SSH_TUNMODE_YES, "yes" }, + { -1, NULL } +}; + /* * Returns the number of the token pointed to by cp or sBadOption. */ @@ -1211,16 +1223,13 @@ process_server_config_line(ServerOptions *options, char *line, if (!arg || *arg == '\0') fatal("%s line %d: Missing yes/point-to-point/" "ethernet/no argument.", filename, linenum); - value = 0; /* silence compiler */ - if (strcasecmp(arg, "ethernet") == 0) - value = SSH_TUNMODE_ETHERNET; - else if (strcasecmp(arg, "point-to-point") == 0) - value = SSH_TUNMODE_POINTOPOINT; - else if (strcasecmp(arg, "yes") == 0) - value = SSH_TUNMODE_YES; - else if (strcasecmp(arg, "no") == 0) - value = SSH_TUNMODE_NO; - else + value = -1; + for (i = 0; tunmode_desc[i].val != -1; i++) + if (strcmp(tunmode_desc[i].text, arg) == 0) { + value = tunmode_desc[i].val; + break; + } + if (value == -1) fatal("%s line %d: Bad yes/point-to-point/ethernet/" "no argument: %s", filename, linenum, arg); if (*intptr == -1) @@ -1426,3 +1435,213 @@ parse_server_config(ServerOptions *options, const char *filename, Buffer *conf, fatal("%s: terminating, %d bad configuration options", filename, bad_options); } + +static const char * +fmt_intarg(ServerOpCodes code, int val) +{ + if (code == sAddressFamily) { + switch (val) { + case AF_INET: + return "inet"; + case AF_INET6: + return "inet6"; + case AF_UNSPEC: + return "any"; + default: + return "UNKNOWN"; + } + } + if (code == sPermitRootLogin) { + switch (val) { + case PERMIT_NO_PASSWD: + return "without-passord"; + case PERMIT_FORCED_ONLY: + return "forced-commands-only"; + case PERMIT_YES: + return "yes"; + } + } + if (code == sProtocol) { + switch (val) { + case SSH_PROTO_1: + return "1"; + case SSH_PROTO_2: + return "2"; + case (SSH_PROTO_1|SSH_PROTO_2): + return "2,1"; + default: + return "UNKNOWN"; + } + } + if (code == sGatewayPorts && val == 2) + return "clientspecified"; + if (code == sCompression && val == COMP_DELAYED) + return "delayed"; + switch (val) { + case -1: + return "unset"; + case 0: + return "no"; + case 1: + return "yes"; + } + return "UNKNOWN"; +} + +static const char * +lookup_opcode_name(ServerOpCodes code) +{ + u_int i; + + for (i = 0; keywords[i].name != NULL; i++) + if (keywords[i].opcode == code) + return(keywords[i].name); + return "UNKNOWN"; +} + +static void +dump_cfg_int(ServerOpCodes code, int val) +{ + printf("%s %d\n", lookup_opcode_name(code), val); +} + +static void +dump_cfg_fmtint(ServerOpCodes code, int val) +{ + printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val)); +} + +static void +dump_cfg_string(ServerOpCodes code, const char *val) +{ + if (val == NULL) + return; + printf("%s %s\n", lookup_opcode_name(code), val); +} + +static void +dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals) +{ + u_int i; + + for (i = 0; i < count; i++) + printf("%s %s\n", lookup_opcode_name(code), vals[i]); +} + +void +dump_config(ServerOptions *o) +{ + u_int i; + int ret; + struct addrinfo *ai; + char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL; + + /* these are usually at the top of the config */ + for (i = 0; i < o->num_ports; i++) + printf("port %d\n", o->ports[i]); + dump_cfg_fmtint(sProtocol, o->protocol); + dump_cfg_fmtint(sAddressFamily, o->address_family); + + /* ListenAddress must be after Port */ + for (ai = o->listen_addrs; ai; ai = ai->ai_next) { + if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, + sizeof(addr), port, sizeof(port), + NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { + error("getnameinfo failed: %.100s", + (ret != EAI_SYSTEM) ? gai_strerror(ret) : + strerror(errno)); + } else { + if (ai->ai_family == AF_INET6) + printf("listenaddress [%s]:%s\n", addr, port); + else + printf("listenaddress %s:%s\n", addr, port); + } + } + + /* integer arguments */ + dump_cfg_int(sServerKeyBits, o->server_key_bits); + dump_cfg_int(sLoginGraceTime, o->login_grace_time); + dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time); + dump_cfg_int(sX11DisplayOffset, o->x11_display_offset); + dump_cfg_int(sMaxAuthTries, o->max_authtries); + dump_cfg_int(sClientAliveInterval, o->client_alive_interval); + dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max); + + /* formatted integer arguments */ + dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login); + dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts); + dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts); + dump_cfg_fmtint(sRhostsRSAAuthentication, o->rhosts_rsa_authentication); + dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication); + dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly, + o->hostbased_uses_name_from_packet_only); + dump_cfg_fmtint(sRSAAuthentication, o->rsa_authentication); + dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication); + dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication); + dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd); + dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup); + dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token); + dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); + dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); + dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); + dump_cfg_fmtint(sKbdInteractiveAuthentication, + o->kbd_interactive_authentication); + dump_cfg_fmtint(sChallengeResponseAuthentication, + o->challenge_response_authentication); + dump_cfg_fmtint(sPrintMotd, o->print_motd); + dump_cfg_fmtint(sPrintLastLog, o->print_lastlog); + dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding); + dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost); + dump_cfg_fmtint(sStrictModes, o->strict_modes); + dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive); + dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd); + dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env); + dump_cfg_fmtint(sUseLogin, o->use_login); + dump_cfg_fmtint(sCompression, o->compression); + dump_cfg_fmtint(sGatewayPorts, o->gateway_ports); + dump_cfg_fmtint(sUseDNS, o->use_dns); + dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); + dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); + + /* string arguments */ + dump_cfg_string(sPidFile, o->pid_file); + dump_cfg_string(sXAuthLocation, o->xauth_location); + dump_cfg_string(sCiphers, o->ciphers); + dump_cfg_string(sMacs, o->macs); + dump_cfg_string(sBanner, o->banner); + dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file); + dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2); + dump_cfg_string(sForceCommand, o->adm_forced_command); + + /* string arguments requiring a lookup */ + dump_cfg_string(sLogLevel, log_level_name(o->log_level)); + dump_cfg_string(sLogFacility, log_facility_name(o->log_facility)); + + /* string array arguments */ + dump_cfg_strarray(sHostKeyFile, o->num_host_key_files, + o->host_key_files); + dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users); + dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users); + dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups); + dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups); + dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env); + + /* other arguments */ + for (i = 0; i < o->num_subsystems; i++) + printf("subsystem %s %s\n", o->subsystem_name[i], + o->subsystem_args[i]); + + printf("maxstartups %d:%d:%d\n", o->max_startups_begin, + o->max_startups_rate, o->max_startups); + + for (i = 0; tunmode_desc[i].val != -1; i++) + if (tunmode_desc[i].val == o->permit_tun) { + s = tunmode_desc[i].text; + break; + } + dump_cfg_string(sPermitTunnel, s); + + printf("permitopen"); + channel_print_adm_permitted_opens(); + printf("\n"); +} diff --git a/servconf.h b/servconf.h index 819a028c8..40ac64f13 100644 --- a/servconf.h +++ b/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.84 2008/05/08 12:21:16 djm Exp $ */ +/* $OpenBSD: servconf.h,v 1.85 2008/06/10 04:50:25 dtucker Exp $ */ /* * Author: Tatu Ylonen @@ -161,5 +161,6 @@ void parse_server_config(ServerOptions *, const char *, Buffer *, void parse_server_match_config(ServerOptions *, const char *, const char *, const char *); void copy_set_server_options(ServerOptions *, ServerOptions *, int); +void dump_config(ServerOptions *); #endif /* SERVCONF_H */ diff --git a/sshd.8 b/sshd.8 index 750d64c3e..7274d0928 100644 --- a/sshd.8 +++ b/sshd.8 @@ -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: sshd.8,v 1.241 2008/03/27 22:37:57 jmc Exp $ -.Dd $Mdocdate: March 27 2008 $ +.\" $OpenBSD: sshd.8,v 1.242 2008/06/10 04:50:25 dtucker Exp $ +.Dd $Mdocdate: June 10 2008 $ .Dt SSHD 8 .Os .Sh NAME @@ -44,8 +44,9 @@ .Sh SYNOPSIS .Nm sshd .Bk -words -.Op Fl 46Ddeiqt +.Op Fl 46DTdeiqt .Op Fl b Ar bits +.Op Fl C Ar connection_spec .Op Fl f Ar config_file .Op Fl g Ar login_grace_time .Op Fl h Ar host_key_file @@ -197,6 +198,33 @@ Only check the validity of the configuration file and sanity of the keys. This is useful for updating .Nm reliably as configuration options may change. +.It Fl T +Extended test mode. +Check the validity of the configuration file, output the effective configuration +to stdout and then exit. +Optionally, +.Cm Match +rules may be applied by specifying the connection parameters using one or more +.Fl C +options. +.It Fl C +Specify the connection parameters to use for the the +.Fl T +extended test mode. +If provided, any +.Cm Match +directives in the configuration file +that would apply to the specified user, host and address will be set before +the configuration is written to standard output. +The connection parameters are supplied as keyword=value pairs. +The keywords are +.Dq user , +.Dq host +and +.Dq addr +All are required and may be supplied in any order, either with multiple +.Fl C +options or as a comma-separated list. .It Fl u Ar len This option is used to specify the size of the field in the diff --git a/sshd.c b/sshd.c index aefbaaa42..ccff65d06 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.357 2008/05/08 12:02:23 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.358 2008/06/10 04:50:25 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1240,8 +1240,9 @@ main(int ac, char **av) int opt, i, on = 1; int sock_in = -1, sock_out = -1, newsock = -1; const char *remote_ip; + char *test_user = NULL, *test_host = NULL, *test_addr = NULL; int remote_port; - char *line; + char *line, *p, *cp; int config_s[2] = { -1 , -1 }; Key *key; Authctxt *authctxt; @@ -1276,7 +1277,7 @@ main(int ac, char **av) initialize_server_options(&options); /* Parse command-line arguments. */ - while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:dDeiqrtQR46")) != -1) { + while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:C:dDeiqrtQRT46")) != -1) { switch (opt) { case '4': options.address_family = AF_INET; @@ -1354,6 +1355,25 @@ main(int ac, char **av) case 't': test_flag = 1; break; + case 'T': + test_flag = 2; + break; + case 'C': + cp = optarg; + while ((p = strsep(&cp, ",")) && *p != '\0') { + if (strncmp(p, "addr=", 5) == 0) + test_addr = xstrdup(p + 5); + else if (strncmp(p, "host=", 5) == 0) + test_host = xstrdup(p + 5); + else if (strncmp(p, "user=", 5) == 0) + test_user = xstrdup(p + 5); + else { + fprintf(stderr, "Invalid test " + "mode specification %s\n", p); + exit(1); + } + } + break; case 'u': utmp_len = (u_int)strtonum(optarg, 0, MAXHOSTNAMELEN+1, NULL); if (utmp_len > MAXHOSTNAMELEN) { @@ -1415,6 +1435,20 @@ main(int ac, char **av) sensitive_data.have_ssh1_key = 0; sensitive_data.have_ssh2_key = 0; + /* + * If we're doing an extended config test, make sure we have all of + * the parameters we need. If we're not doing an extended test, + * do not silently ignore connection test params. + */ + if (test_flag >= 2 && (test_user != NULL || test_host != NULL || test_addr != NULL) + && (test_user == NULL || test_host == NULL || test_addr == NULL)) + fatal("user, host and addr are all required when testing " + "Match configs"); + if (test_flag < 2 && (test_user != NULL || test_host != NULL || + test_addr != NULL)) + fatal("Config test connection parameter (-C) provided without " + "test mode (-T)"); + /* Fetch our configuration */ buffer_init(&cfg); if (rexeced_flag) @@ -1543,6 +1577,13 @@ main(int ac, char **av) "world-writable.", _PATH_PRIVSEP_CHROOT_DIR); } + if (test_flag > 1) { + if (test_user != NULL && test_addr != NULL && test_host != NULL) + parse_server_match_config(&options, test_user, + test_host, test_addr); + dump_config(&options); + } + /* Configuration looks good, so exit if in test mode. */ if (test_flag) exit(0); -- cgit v1.2.3 From 2fb66caca2c9e69c6a0584060114fcd52e59d5ff Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 13 Jun 2008 04:49:33 +1000 Subject: - djm@cvs.openbsd.org 2008/06/12 03:40:52 [clientloop.h mux.c channels.c clientloop.c channels.h] Enable ~ escapes for multiplex slave sessions; give each channel its own escape state and hook the escape filters up to muxed channels. bz #1331 Mux slaves do not currently support the ~^Z and ~& escapes. NB. this change cranks the mux protocol version, so a new ssh mux client will not be able to connect to a running old ssh mux master. ok dtucker@ --- ChangeLog | 12 ++++- channels.c | 5 +- channels.h | 5 +- clientloop.c | 154 +++++++++++++++++++++++++++++++++++++++++++++-------------- clientloop.h | 22 +++------ mux.c | 93 ++++++++++++++++++++++++------------ 6 files changed, 202 insertions(+), 89 deletions(-) (limited to 'channels.h') diff --git a/ChangeLog b/ChangeLog index 27a2a7abc..ca0d8ea57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -68,6 +68,16 @@ [key.c] use an odd number of rows and columns and a separate start marker, looks better; ok grunk@ + - djm@cvs.openbsd.org 2008/06/12 03:40:52 + [clientloop.h mux.c channels.c clientloop.c channels.h] + Enable ~ escapes for multiplex slave sessions; give each channel + its own escape state and hook the escape filters up to muxed + channels. bz #1331 + Mux slaves do not currently support the ~^Z and ~& escapes. + NB. this change cranks the mux protocol version, so a new ssh + mux client will not be able to connect to a running old ssh + mux master. + ok dtucker@ 20080611 - (djm) [channels.c configure.ac] @@ -4230,4 +4240,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.4976 2008/06/12 18:48:11 dtucker Exp $ +$Id: ChangeLog,v 1.4977 2008/06/12 18:49:33 dtucker Exp $ diff --git a/channels.c b/channels.c index 233c2247b..c539990f6 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.278 2008/06/10 04:50:25 dtucker Exp $ */ +/* $OpenBSD: channels.c,v 1.279 2008/06/12 03:40:52 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -731,7 +731,7 @@ channel_cancel_cleanup(int id) void channel_register_filter(int id, channel_infilter_fn *ifn, - channel_outfilter_fn *ofn) + channel_outfilter_fn *ofn, void *ctx) { Channel *c = channel_lookup(id); @@ -741,6 +741,7 @@ channel_register_filter(int id, channel_infilter_fn *ifn, } c->input_filter = ifn; c->output_filter = ofn; + c->filter_ctx = ctx; } void diff --git a/channels.h b/channels.h index dc1f483ed..450321d43 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.93 2008/06/10 04:50:25 dtucker Exp $ */ +/* $OpenBSD: channels.h,v 1.94 2008/06/12 03:40:52 djm Exp $ */ /* * Author: Tatu Ylonen @@ -131,6 +131,7 @@ struct Channel { /* filter */ channel_infilter_fn *input_filter; channel_outfilter_fn *output_filter; + void *filter_ctx; /* keep boundaries */ int datagram; @@ -195,7 +196,7 @@ void channel_request_start(int, char *, int); void channel_register_cleanup(int, channel_callback_fn *, int); void channel_register_open_confirm(int, channel_callback_fn *, void *); void channel_register_filter(int, channel_infilter_fn *, - channel_outfilter_fn *); + channel_outfilter_fn *, void *); void channel_register_status_confirm(int, channel_confirm_cb *, channel_confirm_abandon_cb *, void *); void channel_cancel_cleanup(int); diff --git a/clientloop.c b/clientloop.c index 3bc8bb8d0..b45e7298a 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.194 2008/05/19 20:53:52 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.195 2008/06/12 03:40:52 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -144,8 +144,8 @@ static int in_non_blocking_mode = 0; /* Common data for the client loop code. */ static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ -static int escape_char; /* Escape character. */ -static int escape_pending; /* Last character was the escape character */ +static int escape_char1; /* Escape character. (proto1 only) */ +static int escape_pending1; /* Last character was an escape (proto1 only) */ static int last_was_cr; /* Last character was a newline. */ static int exit_status; /* Used to store the exit status of the command. */ static int stdin_eof; /* EOF has been encountered on standard error. */ @@ -162,6 +162,13 @@ static int session_closed = 0; /* In SSH2: login session closed. */ static void client_init_dispatch(void); int session_ident = -1; +/* Track escape per proto2 channel */ +struct escape_filter_ctx { + int escape_pending; + int escape_char; +}; + +/* Context for channel confirmation replies */ struct channel_reply_ctx { const char *request_type; int id, do_close; @@ -385,8 +392,8 @@ client_check_initial_eof_on_stdin(void) * and also process it as an escape character if * appropriate. */ - if ((u_char) buf[0] == escape_char) - escape_pending = 1; + if ((u_char) buf[0] == escape_char1) + escape_pending1 = 1; else buffer_append(&stdin_buffer, buf, 1); } @@ -813,9 +820,12 @@ out: xfree(fwd.connect_host); } -/* process the characters one by one */ +/* + * Process the characters one by one, call with c==NULL for proto1 case. + */ static int -process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) +process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, + char *buf, int len) { char string[1024]; pid_t pid; @@ -823,7 +833,20 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) u_int i; u_char ch; char *s; + int *escape_pendingp, escape_char; + struct escape_filter_ctx *efc; + if (c == NULL) { + escape_pendingp = &escape_pending1; + escape_char = escape_char1; + } else { + if (c->filter_ctx == NULL) + return 0; + efc = (struct escape_filter_ctx *)c->filter_ctx; + escape_pendingp = &efc->escape_pending; + escape_char = efc->escape_char; + } + if (len <= 0) return (0); @@ -831,25 +854,43 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) /* Get one character at a time. */ ch = buf[i]; - if (escape_pending) { + if (*escape_pendingp) { /* We have previously seen an escape character. */ /* Clear the flag now. */ - escape_pending = 0; + *escape_pendingp = 0; /* Process the escaped character. */ switch (ch) { case '.': /* Terminate the connection. */ - snprintf(string, sizeof string, "%c.\r\n", escape_char); + snprintf(string, sizeof string, "%c.\r\n", + escape_char); buffer_append(berr, string, strlen(string)); - quit_pending = 1; + if (c && c->ctl_fd != -1) { + chan_read_failed(c); + chan_write_failed(c); + return 0; + } else + quit_pending = 1; return -1; case 'Z' - 64: + /* XXX support this for mux clients */ + if (c && c->ctl_fd != -1) { + noescape: + snprintf(string, sizeof string, + "%c%c escape not available to " + "multiplexed sessions\r\n", + escape_char, ch); + buffer_append(berr, string, + strlen(string)); + continue; + } /* Suspend the program. */ /* Print a message to that effect to the user. */ - snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char); + snprintf(string, sizeof string, + "%c^Z [suspend ssh]\r\n", escape_char); buffer_append(berr, string, strlen(string)); /* Restore terminal modes and suspend. */ @@ -881,6 +922,8 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) continue; case '&': + if (c && c->ctl_fd != -1) + goto noescape; /* * Detach the program (continue to serve connections, * but put in background and no more new connections). @@ -929,27 +972,50 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) continue; case '?': - snprintf(string, sizeof string, + if (c && c->ctl_fd != -1) { + snprintf(string, sizeof string, "%c?\r\n\ Supported escape sequences:\r\n\ -%c. - terminate connection\r\n\ -%cB - send a BREAK to the remote system\r\n\ -%cC - open a command line\r\n\ -%cR - Request rekey (SSH protocol 2 only)\r\n\ -%c^Z - suspend ssh\r\n\ -%c# - list forwarded connections\r\n\ -%c& - background ssh (when waiting for connections to terminate)\r\n\ -%c? - this message\r\n\ -%c%c - send the escape character by typing it twice\r\n\ + %c. - terminate session\r\n\ + %cB - send a BREAK to the remote system\r\n\ + %cC - open a command line\r\n\ + %cR - Request rekey (SSH protocol 2 only)\r\n\ + %c# - list forwarded connections\r\n\ + %c? - this message\r\n\ + %c%c - send the escape character by typing it twice\r\n\ (Note that escapes are only recognized immediately after newline.)\r\n", - escape_char, escape_char, escape_char, escape_char, - escape_char, escape_char, escape_char, escape_char, - escape_char, escape_char, escape_char); + escape_char, escape_char, + escape_char, escape_char, + escape_char, escape_char, + escape_char, escape_char, + escape_char); + } else { + snprintf(string, sizeof string, +"%c?\r\n\ +Supported escape sequences:\r\n\ + %c. - terminate connection (and any multiplexed sessions)\r\n\ + %cB - send a BREAK to the remote system\r\n\ + %cC - open a command line\r\n\ + %cR - Request rekey (SSH protocol 2 only)\r\n\ + %c^Z - suspend ssh\r\n\ + %c# - list forwarded connections\r\n\ + %c& - background ssh (when waiting for connections to terminate)\r\n\ + %c? - this message\r\n\ + %c%c - send the escape character by typing it twice\r\n\ +(Note that escapes are only recognized immediately after newline.)\r\n", + escape_char, escape_char, + escape_char, escape_char, + escape_char, escape_char, + escape_char, escape_char, + escape_char, escape_char, + escape_char); + } buffer_append(berr, string, strlen(string)); continue; case '#': - snprintf(string, sizeof string, "%c#\r\n", escape_char); + snprintf(string, sizeof string, "%c#\r\n", + escape_char); buffer_append(berr, string, strlen(string)); s = channel_open_message(); buffer_append(berr, s, strlen(s)); @@ -975,7 +1041,7 @@ Supported escape sequences:\r\n\ */ if (last_was_cr && ch == escape_char) { /* It is. Set the flag and continue to next character. */ - escape_pending = 1; + *escape_pendingp = 1; continue; } } @@ -1026,7 +1092,7 @@ client_process_input(fd_set *readset) packet_start(SSH_CMSG_EOF); packet_send(); } - } else if (escape_char == SSH_ESCAPECHAR_NONE) { + } else if (escape_char1 == SSH_ESCAPECHAR_NONE) { /* * Normal successful read, and no escape character. * Just append the data to buffer. @@ -1037,8 +1103,8 @@ client_process_input(fd_set *readset) * Normal, successful read. But we have an escape character * and have to process the characters one by one. */ - if (process_escapes(&stdin_buffer, &stdout_buffer, - &stderr_buffer, buf, len) == -1) + if (process_escapes(NULL, &stdin_buffer, + &stdout_buffer, &stderr_buffer, buf, len) == -1) return; } } @@ -1113,13 +1179,26 @@ client_process_buffered_input_packets(void) /* scan buf[] for '~' before sending data to the peer */ -static int -simple_escape_filter(Channel *c, char *buf, int len) +/* Helper: allocate a new escape_filter_ctx and fill in its escape char */ +void * +client_new_escape_filter_ctx(int escape_char) +{ + struct escape_filter_ctx *ret; + + ret = xmalloc(sizeof(*ret)); + ret->escape_pending = 0; + ret->escape_char = escape_char; + return (void *)ret; +} + +int +client_simple_escape_filter(Channel *c, char *buf, int len) { if (c->extended_usage != CHAN_EXTENDED_WRITE) return 0; - return process_escapes(&c->input, &c->output, &c->extended, buf, len); + return process_escapes(c, &c->input, &c->output, &c->extended, + buf, len); } static void @@ -1151,7 +1230,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) start_time = get_current_time(); /* Initialize variables. */ - escape_pending = 0; + escape_pending1 = 0; last_was_cr = 1; exit_status = -1; stdin_eof = 0; @@ -1178,7 +1257,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) stdout_bytes = 0; stderr_bytes = 0; quit_pending = 0; - escape_char = escape_char_arg; + escape_char1 = escape_char_arg; /* Initialize buffers. */ buffer_init(&stdin_buffer); @@ -1206,9 +1285,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) if (compat20) { session_ident = ssh2_chan_id; - if (escape_char != SSH_ESCAPECHAR_NONE) + if (escape_char_arg != SSH_ESCAPECHAR_NONE) channel_register_filter(session_ident, - simple_escape_filter, NULL); + client_simple_escape_filter, NULL, + client_new_escape_filter_ctx(escape_char_arg)); if (session_ident != -1) channel_register_cleanup(session_ident, client_channel_closed, 0); diff --git a/clientloop.h b/clientloop.h index 6f8e70123..cecbfb1a8 100644 --- a/clientloop.h +++ b/clientloop.h @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.h,v 1.19 2008/05/09 14:18:44 djm Exp $ */ +/* $OpenBSD: clientloop.h,v 1.20 2008/06/12 03:40:52 djm Exp $ */ /* * Author: Tatu Ylonen @@ -46,8 +46,12 @@ void client_session2_setup(int, int, int, const char *, struct termios *, int, Buffer *, char **); int client_request_tun_fwd(int, int, int); +/* Escape filter for protocol 2 sessions */ +void *client_new_escape_filter_ctx(int); +int client_simple_escape_filter(Channel *, char *, int); + /* Multiplexing protocol version */ -#define SSHMUX_VER 1 +#define SSHMUX_VER 2 /* Multiplexing control protocol flags */ #define SSHMUX_COMMAND_OPEN 1 /* Open new connection */ @@ -59,20 +63,6 @@ int client_request_tun_fwd(int, int, int); #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 index 8b9105b04..efc3840cb 100644 --- a/mux.c +++ b/mux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mux.c,v 1.1 2008/05/09 14:18:44 djm Exp $ */ +/* $OpenBSD: mux.c,v 1.2 2008/06/12 03:40:52 djm Exp $ */ /* * Copyright (c) 2002-2008 Damien Miller * @@ -19,6 +19,20 @@ #include "includes.h" +/* + * TODO: + * 1. partial reads in muxserver_accept_control (maybe make channels + * from accepted connections) + * 2. Better signalling from master to slave, especially passing of + * error messages + * 3. Better fall-back from mux slave error to new connection. + * 3. Add/delete forwardings via slave + * 4. ExitOnForwardingFailure (after #3 obviously) + * 5. Maybe extension mechanisms for multi-X11/multi-agent forwarding + * 6. Document the mux mini-protocol somewhere. + * 6. Support ~^Z in mux slaves. + */ + #include #include #include @@ -71,6 +85,18 @@ extern char *host; int subsystem_flag; extern Buffer command; +/* Context for session open confirmation callback */ +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; +}; + /* fd to control socket */ int muxserver_sock = -1; @@ -131,7 +157,7 @@ muxserver_listen(void) /* Callback on open confirmation in mux master for a mux client session. */ static void -client_extra_session2_setup(int id, void *arg) +mux_session_confirm(int id, void *arg) { struct mux_session_confirm_ctx *cctx = arg; const char *display; @@ -190,7 +216,7 @@ muxserver_accept_control(void) struct sockaddr_storage addr; struct mux_session_confirm_ctx *cctx; char *cmd; - u_int i, j, len, env_len, mux_command, flags; + u_int i, j, len, env_len, mux_command, flags, escape_char; uid_t euid; gid_t egid; int start_close = 0; @@ -317,6 +343,7 @@ muxserver_accept_control(void) 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); + escape_char = buffer_get_int(&m); cmd = buffer_get_string(&m, &len); buffer_init(&cctx->cmd); @@ -402,14 +429,17 @@ muxserver_accept_control(void) new_fd[0], new_fd[1], new_fd[2], window, packetmax, CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); - /* XXX */ c->ctl_fd = client_fd; + if (cctx->want_tty && escape_char != 0xffffffff) { + channel_register_filter(c->self, + client_simple_escape_filter, NULL, + client_new_escape_filter_ctx((int)escape_char)); + } debug3("%s: channel_new: %d", __func__, c->self); channel_send_open(c->self); - channel_register_open_confirm(c->self, - client_extra_session2_setup, cctx); + channel_register_open_confirm(c->self, mux_session_confirm, cctx); return 0; } @@ -561,33 +591,34 @@ muxclient(const char *path) fprintf(stderr, "Exit request sent.\r\n"); exit(0); case SSHMUX_COMMAND_OPEN: - /* continue below */ + buffer_put_cstring(&m, term ? term : ""); + if (options.escape_char == SSH_ESCAPECHAR_NONE) + buffer_put_int(&m, 0xffffffff); + else + buffer_put_int(&m, options.escape_char); + 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]); + } + } + } 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]); - } + fatal("unrecognised muxclient_command %d", muxclient_command); } if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) -- cgit v1.2.3 From 84c56f536ca664f79172d595e088fce6aa84be21 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 13 Jun 2008 04:55:46 +1000 Subject: - djm@cvs.openbsd.org 2008/06/12 15:19:17 [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. --- ChangeLog | 6 +++++- channels.c | 9 +++++++-- channels.h | 6 ++++-- clientloop.c | 10 +++++++++- clientloop.h | 3 ++- mux.c | 3 ++- 6 files changed, 29 insertions(+), 8 deletions(-) (limited to 'channels.h') diff --git a/ChangeLog b/ChangeLog index 12471ba3b..0aec356d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -108,6 +108,10 @@ We already mark the start of the worm, now also mark the end of the worm in our random art drawings. ok djm@ + - djm@cvs.openbsd.org 2008/06/12 15:19:17 + [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. 20080611 - (djm) [channels.c configure.ac] @@ -4270,4 +4274,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.4983 2008/06/12 18:55:10 dtucker Exp $ +$Id: ChangeLog,v 1.4984 2008/06/12 18:55:46 dtucker Exp $ diff --git a/channels.c b/channels.c index c539990f6..04cd6b0a7 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.279 2008/06/12 03:40:52 djm Exp $ */ +/* $OpenBSD: channels.c,v 1.280 2008/06/12 15:19:17 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -328,6 +328,8 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, c->open_confirm_ctx = NULL; c->input_filter = NULL; c->output_filter = NULL; + c->filter_ctx = NULL; + c->filter_cleanup = NULL; TAILQ_INIT(&c->status_confirms); debug("channel %d: new [%s]", found, remote_name); return c; @@ -416,6 +418,8 @@ channel_free(Channel *c) bzero(cc, sizeof(*cc)); xfree(cc); } + if (c->filter_cleanup != NULL && c->filter_ctx != NULL) + c->filter_cleanup(c->self, c->filter_ctx); channels[c->self] = NULL; xfree(c); } @@ -731,7 +735,7 @@ channel_cancel_cleanup(int id) void channel_register_filter(int id, channel_infilter_fn *ifn, - channel_outfilter_fn *ofn, void *ctx) + channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx) { Channel *c = channel_lookup(id); @@ -742,6 +746,7 @@ channel_register_filter(int id, channel_infilter_fn *ifn, c->input_filter = ifn; c->output_filter = ofn; c->filter_ctx = ctx; + c->filter_cleanup = cfn; } void diff --git a/channels.h b/channels.h index 450321d43..ec8ea1c40 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.94 2008/06/12 03:40:52 djm Exp $ */ +/* $OpenBSD: channels.h,v 1.95 2008/06/12 15:19:17 djm Exp $ */ /* * Author: Tatu Ylonen @@ -62,6 +62,7 @@ typedef struct Channel Channel; typedef void channel_callback_fn(int, void *); typedef int channel_infilter_fn(struct Channel *, char *, int); +typedef void channel_filter_cleanup_fn(int, void *); typedef u_char *channel_outfilter_fn(struct Channel *, u_char **, u_int *); /* Channel success/failure callbacks */ @@ -132,6 +133,7 @@ struct Channel { channel_infilter_fn *input_filter; channel_outfilter_fn *output_filter; void *filter_ctx; + channel_filter_cleanup_fn *filter_cleanup; /* keep boundaries */ int datagram; @@ -196,7 +198,7 @@ void channel_request_start(int, char *, int); void channel_register_cleanup(int, channel_callback_fn *, int); void channel_register_open_confirm(int, channel_callback_fn *, void *); void channel_register_filter(int, channel_infilter_fn *, - channel_outfilter_fn *, void *); + channel_outfilter_fn *, channel_filter_cleanup_fn *, void *); void channel_register_status_confirm(int, channel_confirm_cb *, channel_confirm_abandon_cb *, void *); void channel_cancel_cleanup(int); diff --git a/clientloop.c b/clientloop.c index 663daae76..d2407ed7e 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.197 2008/06/12 04:17:47 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.198 2008/06/12 15:19:17 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1260,6 +1260,13 @@ client_new_escape_filter_ctx(int escape_char) return (void *)ret; } +/* Free the escape filter context on channel free */ +void +client_filter_cleanup(int cid, void *ctx) +{ + xfree(ctx); +} + int client_simple_escape_filter(Channel *c, char *buf, int len) { @@ -1357,6 +1364,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) if (escape_char_arg != SSH_ESCAPECHAR_NONE) channel_register_filter(session_ident, client_simple_escape_filter, NULL, + client_filter_cleanup, client_new_escape_filter_ctx(escape_char_arg)); if (session_ident != -1) channel_register_cleanup(session_ident, diff --git a/clientloop.h b/clientloop.h index 3353a9a80..8bb874b38 100644 --- a/clientloop.h +++ b/clientloop.h @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.h,v 1.21 2008/06/12 04:06:00 djm Exp $ */ +/* $OpenBSD: clientloop.h,v 1.22 2008/06/12 15:19:17 djm Exp $ */ /* * Author: Tatu Ylonen @@ -48,6 +48,7 @@ int client_request_tun_fwd(int, int, int); /* Escape filter for protocol 2 sessions */ void *client_new_escape_filter_ctx(int); +void client_filter_cleanup(int, void *); int client_simple_escape_filter(Channel *, char *, int); /* Global request confirmation callbacks */ diff --git a/mux.c b/mux.c index f5e68f653..8f7bfb793 100644 --- a/mux.c +++ b/mux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mux.c,v 1.3 2008/06/12 05:32:30 djm Exp $ */ +/* $OpenBSD: mux.c,v 1.4 2008/06/12 15:19:17 djm Exp $ */ /* * Copyright (c) 2002-2008 Damien Miller * @@ -436,6 +436,7 @@ muxserver_accept_control(void) if (cctx->want_tty && escape_char != 0xffffffff) { channel_register_filter(c->self, client_simple_escape_filter, NULL, + client_filter_cleanup, client_new_escape_filter_ctx((int)escape_char)); } -- cgit v1.2.3 From d310d51badf6bbd1df56c8a0971d24e2d3e61887 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 16 Jun 2008 07:59:23 +1000 Subject: - djm@cvs.openbsd.org 2008/06/15 20:06:26 [channels.c channels.h session.c] don't call isatty() on a pty master, instead pass a flag down to channel_set_fds() indicating that te fds refer to a tty. Fixes a hang on exit on Solaris (bz#1463) in portable but is actually a generic bug; ok dtucker deraadt markus --- ChangeLog | 8 +++++++- channels.c | 23 +++++++---------------- channels.h | 4 ++-- session.c | 15 +++++++-------- 4 files changed, 23 insertions(+), 27 deletions(-) (limited to 'channels.h') diff --git a/ChangeLog b/ChangeLog index 1a3b3b1a8..77d7739dc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,6 +21,12 @@ - dtucker@cvs.openbsd.org 2008/06/15 16:58:40 [servconf.c sshd_config.5] Allow MaxAuthTries within a Match block. ok djm@ + - djm@cvs.openbsd.org 2008/06/15 20:06:26 + [channels.c channels.h session.c] + don't call isatty() on a pty master, instead pass a flag down to + channel_set_fds() indicating that te fds refer to a tty. Fixes a + hang on exit on Solaris (bz#1463) in portable but is actually + a generic bug; ok dtucker deraadt markus 20080614 - (djm) [openbsd-compat/sigact.c] Avoid NULL derefs in ancient sigaction @@ -4393,4 +4399,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.5018 2008/06/15 21:56:20 djm Exp $ +$Id: ChangeLog,v 1.5019 2008/06/15 21:59:23 djm Exp $ diff --git a/channels.c b/channels.c index 04cd6b0a7..b1e544519 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.280 2008/06/12 15:19:17 djm Exp $ */ +/* $OpenBSD: channels.c,v 1.281 2008/06/15 20:06:26 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -221,7 +221,7 @@ channel_lookup(int id) */ static void channel_register_fds(Channel *c, int rfd, int wfd, int efd, - int extusage, int nonblock) + int extusage, int nonblock, int isatty) { /* Update the maximum file descriptor value. */ channel_max_fd = MAX(channel_max_fd, rfd); @@ -237,18 +237,9 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, c->efd = efd; c->extended_usage = extusage; - /* XXX ugly hack: nonblock is only set by the server */ - if (nonblock && isatty(c->rfd)) { + if ((c->isatty = isatty) != 0) debug2("channel %d: rfd %d isatty", c->self, c->rfd); - c->isatty = 1; - if (!isatty(c->wfd)) { - error("channel %d: wfd %d is not a tty?", - c->self, c->wfd); - } - } else { - c->isatty = 0; - } - c->wfd_isatty = isatty(c->wfd); + c->wfd_isatty = isatty || isatty(c->wfd); /* enable nonblocking mode */ if (nonblock) { @@ -308,7 +299,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, c->ostate = CHAN_OUTPUT_OPEN; c->istate = CHAN_INPUT_OPEN; c->flags = 0; - channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); + channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0); c->self = found; c->type = type; c->ctype = ctype; @@ -751,13 +742,13 @@ channel_register_filter(int id, channel_infilter_fn *ifn, void channel_set_fds(int id, int rfd, int wfd, int efd, - int extusage, int nonblock, u_int window_max) + int extusage, int nonblock, int isatty, u_int window_max) { Channel *c = channel_lookup(id); if (c == NULL || c->type != SSH_CHANNEL_LARVAL) fatal("channel_activate for non-larval channel %d.", id); - channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); + channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, isatty); c->type = SSH_CHANNEL_OPEN; c->local_window = c->local_window_max = window_max; packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); diff --git a/channels.h b/channels.h index ec8ea1c40..108b36068 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.95 2008/06/12 15:19:17 djm Exp $ */ +/* $OpenBSD: channels.h,v 1.96 2008/06/15 20:06:26 djm Exp $ */ /* * Author: Tatu Ylonen @@ -188,7 +188,7 @@ struct Channel { Channel *channel_by_id(int); Channel *channel_lookup(int); Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int); -void channel_set_fds(int, int, int, int, int, int, u_int); +void channel_set_fds(int, int, int, int, int, int, int, u_int); void channel_free(Channel *); void channel_free_all(void); void channel_stop_listening(void); diff --git a/session.c b/session.c index 3ea783f63..d692bc709 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.239 2008/06/14 18:33:43 djm Exp $ */ +/* $OpenBSD: session.c,v 1.240 2008/06/15 20:06:26 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -98,7 +98,7 @@ /* func */ Session *session_new(void); -void session_set_fds(Session *, int, int, int); +void session_set_fds(Session *, int, int, int, int); void session_pty_cleanup(Session *); void session_proctitle(Session *); int session_setup_x11fwd(Session *); @@ -591,7 +591,7 @@ do_exec_no_pty(Session *s, const char *command) close(perr[0]); perr[0] = -1; } - session_set_fds(s, pin[1], pout[0], perr[0]); + session_set_fds(s, pin[1], pout[0], perr[0], 0); } else { /* Enter the interactive session. */ server_loop(pid, pin[1], pout[0], perr[0]); @@ -608,7 +608,7 @@ do_exec_no_pty(Session *s, const char *command) */ if (compat20) { session_set_fds(s, inout[1], inout[1], - s->is_subsystem ? -1 : err[1]); + s->is_subsystem ? -1 : err[1], 0); if (s->is_subsystem) close(err[1]); } else { @@ -733,7 +733,7 @@ do_exec_pty(Session *s, const char *command) s->ptymaster = ptymaster; packet_set_interactive(1); if (compat20) { - session_set_fds(s, ptyfd, fdout, -1); + session_set_fds(s, ptyfd, fdout, -1, 1); } else { server_loop(pid, ptyfd, fdout, -1); /* server_loop _has_ closed ptyfd and fdout. */ @@ -2285,7 +2285,7 @@ session_input_channel_req(Channel *c, const char *rtype) } void -session_set_fds(Session *s, int fdin, int fdout, int fderr) +session_set_fds(Session *s, int fdin, int fdout, int fderr, int isatty) { if (!compat20) fatal("session_set_fds: called for proto != 2.0"); @@ -2298,8 +2298,7 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr) channel_set_fds(s->chanid, fdout, fdin, fderr, fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, - 1, - CHAN_SES_WINDOW_DEFAULT); + 1, isatty, CHAN_SES_WINDOW_DEFAULT); } /* -- cgit v1.2.3