diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 79 |
1 files changed, 44 insertions, 35 deletions
diff --git a/channels.c b/channels.c index c85d46abd..657381b80 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.386 2018/10/04 01:04:52 djm Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.389 2019/01/19 21:37:13 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -227,11 +227,7 @@ channel_init_channels(struct ssh *ssh) | |||
227 | { | 227 | { |
228 | struct ssh_channels *sc; | 228 | struct ssh_channels *sc; |
229 | 229 | ||
230 | if ((sc = calloc(1, sizeof(*sc))) == NULL || | 230 | if ((sc = calloc(1, sizeof(*sc))) == NULL) |
231 | (sc->channel_pre = calloc(SSH_CHANNEL_MAX_TYPE, | ||
232 | sizeof(*sc->channel_pre))) == NULL || | ||
233 | (sc->channel_post = calloc(SSH_CHANNEL_MAX_TYPE, | ||
234 | sizeof(*sc->channel_post))) == NULL) | ||
235 | fatal("%s: allocation failed", __func__); | 231 | fatal("%s: allocation failed", __func__); |
236 | sc->channels_alloc = 10; | 232 | sc->channels_alloc = 10; |
237 | sc->channels = xcalloc(sc->channels_alloc, sizeof(*sc->channels)); | 233 | sc->channels = xcalloc(sc->channels_alloc, sizeof(*sc->channels)); |
@@ -2104,16 +2100,18 @@ channel_handle_efd_read(struct ssh *ssh, Channel *c, | |||
2104 | fd_set *readset, fd_set *writeset) | 2100 | fd_set *readset, fd_set *writeset) |
2105 | { | 2101 | { |
2106 | char buf[CHAN_RBUF]; | 2102 | char buf[CHAN_RBUF]; |
2107 | int r; | ||
2108 | ssize_t len; | 2103 | ssize_t len; |
2104 | int r, force; | ||
2105 | |||
2106 | force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED; | ||
2109 | 2107 | ||
2110 | if (!c->detach_close && !FD_ISSET(c->efd, readset)) | 2108 | if (c->efd == -1 || (!force && !FD_ISSET(c->efd, readset))) |
2111 | return 1; | 2109 | return 1; |
2112 | 2110 | ||
2113 | len = read(c->efd, buf, sizeof(buf)); | 2111 | len = read(c->efd, buf, sizeof(buf)); |
2114 | debug2("channel %d: read %zd from efd %d", c->self, len, c->efd); | 2112 | debug2("channel %d: read %zd from efd %d", c->self, len, c->efd); |
2115 | if (len < 0 && (errno == EINTR || ((errno == EAGAIN || | 2113 | if (len < 0 && (errno == EINTR || ((errno == EAGAIN || |
2116 | errno == EWOULDBLOCK) && !c->detach_close))) | 2114 | errno == EWOULDBLOCK) && !force))) |
2117 | return 1; | 2115 | return 1; |
2118 | if (len <= 0) { | 2116 | if (len <= 0) { |
2119 | debug2("channel %d: closing read-efd %d", | 2117 | debug2("channel %d: closing read-efd %d", |
@@ -2995,10 +2993,10 @@ channel_input_data(int type, u_int32_t seq, struct ssh *ssh) | |||
2995 | return 0; | 2993 | return 0; |
2996 | 2994 | ||
2997 | /* Get the data. */ | 2995 | /* Get the data. */ |
2998 | if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0) | 2996 | if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0 || |
2997 | (r = sshpkt_get_end(ssh)) != 0) | ||
2999 | fatal("%s: channel %d: get data: %s", __func__, | 2998 | fatal("%s: channel %d: get data: %s", __func__, |
3000 | c->self, ssh_err(r)); | 2999 | c->self, ssh_err(r)); |
3001 | ssh_packet_check_eom(ssh); | ||
3002 | 3000 | ||
3003 | win_len = data_len; | 3001 | win_len = data_len; |
3004 | if (c->datagram) | 3002 | if (c->datagram) |
@@ -3072,11 +3070,11 @@ channel_input_extended_data(int type, u_int32_t seq, struct ssh *ssh) | |||
3072 | logit("channel %d: bad ext data", c->self); | 3070 | logit("channel %d: bad ext data", c->self); |
3073 | return 0; | 3071 | return 0; |
3074 | } | 3072 | } |
3075 | if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0) { | 3073 | if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0 || |
3074 | (r = sshpkt_get_end(ssh)) != 0) { | ||
3076 | error("%s: parse data: %s", __func__, ssh_err(r)); | 3075 | error("%s: parse data: %s", __func__, ssh_err(r)); |
3077 | ssh_packet_disconnect(ssh, "Invalid extended_data message"); | 3076 | ssh_packet_disconnect(ssh, "Invalid extended_data message"); |
3078 | } | 3077 | } |
3079 | ssh_packet_check_eom(ssh); | ||
3080 | 3078 | ||
3081 | if (data_len > c->local_window) { | 3079 | if (data_len > c->local_window) { |
3082 | logit("channel %d: rcvd too much extended_data %zu, win %u", | 3080 | logit("channel %d: rcvd too much extended_data %zu, win %u", |
@@ -3095,8 +3093,12 @@ int | |||
3095 | channel_input_ieof(int type, u_int32_t seq, struct ssh *ssh) | 3093 | channel_input_ieof(int type, u_int32_t seq, struct ssh *ssh) |
3096 | { | 3094 | { |
3097 | Channel *c = channel_from_packet_id(ssh, __func__, "ieof"); | 3095 | Channel *c = channel_from_packet_id(ssh, __func__, "ieof"); |
3096 | int r; | ||
3098 | 3097 | ||
3099 | ssh_packet_check_eom(ssh); | 3098 | if ((r = sshpkt_get_end(ssh)) != 0) { |
3099 | error("%s: parse data: %s", __func__, ssh_err(r)); | ||
3100 | ssh_packet_disconnect(ssh, "Invalid ieof message"); | ||
3101 | } | ||
3100 | 3102 | ||
3101 | if (channel_proxy_upstream(c, type, seq, ssh)) | 3103 | if (channel_proxy_upstream(c, type, seq, ssh)) |
3102 | return 0; | 3104 | return 0; |
@@ -3116,10 +3118,14 @@ int | |||
3116 | channel_input_oclose(int type, u_int32_t seq, struct ssh *ssh) | 3118 | channel_input_oclose(int type, u_int32_t seq, struct ssh *ssh) |
3117 | { | 3119 | { |
3118 | Channel *c = channel_from_packet_id(ssh, __func__, "oclose"); | 3120 | Channel *c = channel_from_packet_id(ssh, __func__, "oclose"); |
3121 | int r; | ||
3119 | 3122 | ||
3120 | if (channel_proxy_upstream(c, type, seq, ssh)) | 3123 | if (channel_proxy_upstream(c, type, seq, ssh)) |
3121 | return 0; | 3124 | return 0; |
3122 | ssh_packet_check_eom(ssh); | 3125 | if ((r = sshpkt_get_end(ssh)) != 0) { |
3126 | error("%s: parse data: %s", __func__, ssh_err(r)); | ||
3127 | ssh_packet_disconnect(ssh, "Invalid oclose message"); | ||
3128 | } | ||
3123 | chan_rcvd_oclose(ssh, c); | 3129 | chan_rcvd_oclose(ssh, c); |
3124 | return 0; | 3130 | return 0; |
3125 | } | 3131 | } |
@@ -3134,7 +3140,7 @@ channel_input_open_confirmation(int type, u_int32_t seq, struct ssh *ssh) | |||
3134 | if (channel_proxy_upstream(c, type, seq, ssh)) | 3140 | if (channel_proxy_upstream(c, type, seq, ssh)) |
3135 | return 0; | 3141 | return 0; |
3136 | if (c->type != SSH_CHANNEL_OPENING) | 3142 | if (c->type != SSH_CHANNEL_OPENING) |
3137 | packet_disconnect("Received open confirmation for " | 3143 | ssh_packet_disconnect(ssh, "Received open confirmation for " |
3138 | "non-opening channel %d.", c->self); | 3144 | "non-opening channel %d.", c->self); |
3139 | /* | 3145 | /* |
3140 | * Record the remote channel number and mark that the channel | 3146 | * Record the remote channel number and mark that the channel |
@@ -3142,11 +3148,11 @@ channel_input_open_confirmation(int type, u_int32_t seq, struct ssh *ssh) | |||
3142 | */ | 3148 | */ |
3143 | if ((r = sshpkt_get_u32(ssh, &c->remote_id)) != 0 || | 3149 | if ((r = sshpkt_get_u32(ssh, &c->remote_id)) != 0 || |
3144 | (r = sshpkt_get_u32(ssh, &remote_window)) != 0 || | 3150 | (r = sshpkt_get_u32(ssh, &remote_window)) != 0 || |
3145 | (r = sshpkt_get_u32(ssh, &remote_maxpacket)) != 0) { | 3151 | (r = sshpkt_get_u32(ssh, &remote_maxpacket)) != 0 || |
3152 | (r = sshpkt_get_end(ssh)) != 0) { | ||
3146 | error("%s: window/maxpacket: %s", __func__, ssh_err(r)); | 3153 | error("%s: window/maxpacket: %s", __func__, ssh_err(r)); |
3147 | packet_disconnect("Invalid open confirmation message"); | 3154 | ssh_packet_disconnect(ssh, "Invalid open confirmation message"); |
3148 | } | 3155 | } |
3149 | ssh_packet_check_eom(ssh); | ||
3150 | 3156 | ||
3151 | c->have_remote_id = 1; | 3157 | c->have_remote_id = 1; |
3152 | c->remote_window = remote_window; | 3158 | c->remote_window = remote_window; |
@@ -3189,19 +3195,19 @@ channel_input_open_failure(int type, u_int32_t seq, struct ssh *ssh) | |||
3189 | if (channel_proxy_upstream(c, type, seq, ssh)) | 3195 | if (channel_proxy_upstream(c, type, seq, ssh)) |
3190 | return 0; | 3196 | return 0; |
3191 | if (c->type != SSH_CHANNEL_OPENING) | 3197 | if (c->type != SSH_CHANNEL_OPENING) |
3192 | packet_disconnect("Received open failure for " | 3198 | ssh_packet_disconnect(ssh, "Received open failure for " |
3193 | "non-opening channel %d.", c->self); | 3199 | "non-opening channel %d.", c->self); |
3194 | if ((r = sshpkt_get_u32(ssh, &reason)) != 0) { | 3200 | if ((r = sshpkt_get_u32(ssh, &reason)) != 0) { |
3195 | error("%s: reason: %s", __func__, ssh_err(r)); | 3201 | error("%s: reason: %s", __func__, ssh_err(r)); |
3196 | packet_disconnect("Invalid open failure message"); | 3202 | ssh_packet_disconnect(ssh, "Invalid open failure message"); |
3197 | } | 3203 | } |
3198 | /* skip language */ | 3204 | /* skip language */ |
3199 | if ((r = sshpkt_get_cstring(ssh, &msg, NULL)) != 0 || | 3205 | if ((r = sshpkt_get_cstring(ssh, &msg, NULL)) != 0 || |
3200 | (r = sshpkt_get_string_direct(ssh, NULL, NULL)) != 0) { | 3206 | (r = sshpkt_get_string_direct(ssh, NULL, NULL)) != 0 || |
3207 | (r = sshpkt_get_end(ssh)) != 0) { | ||
3201 | error("%s: message/lang: %s", __func__, ssh_err(r)); | 3208 | error("%s: message/lang: %s", __func__, ssh_err(r)); |
3202 | packet_disconnect("Invalid open failure message"); | 3209 | ssh_packet_disconnect(ssh, "Invalid open failure message"); |
3203 | } | 3210 | } |
3204 | ssh_packet_check_eom(ssh); | ||
3205 | logit("channel %d: open failed: %s%s%s", c->self, | 3211 | logit("channel %d: open failed: %s%s%s", c->self, |
3206 | reason2txt(reason), msg ? ": ": "", msg ? msg : ""); | 3212 | reason2txt(reason), msg ? ": ": "", msg ? msg : ""); |
3207 | free(msg); | 3213 | free(msg); |
@@ -3231,11 +3237,11 @@ channel_input_window_adjust(int type, u_int32_t seq, struct ssh *ssh) | |||
3231 | 3237 | ||
3232 | if (channel_proxy_upstream(c, type, seq, ssh)) | 3238 | if (channel_proxy_upstream(c, type, seq, ssh)) |
3233 | return 0; | 3239 | return 0; |
3234 | if ((r = sshpkt_get_u32(ssh, &adjust)) != 0) { | 3240 | if ((r = sshpkt_get_u32(ssh, &adjust)) != 0 || |
3241 | (r = sshpkt_get_end(ssh)) != 0) { | ||
3235 | error("%s: adjust: %s", __func__, ssh_err(r)); | 3242 | error("%s: adjust: %s", __func__, ssh_err(r)); |
3236 | packet_disconnect("Invalid window adjust message"); | 3243 | ssh_packet_disconnect(ssh, "Invalid window adjust message"); |
3237 | } | 3244 | } |
3238 | ssh_packet_check_eom(ssh); | ||
3239 | debug2("channel %d: rcvd adjust %u", c->self, adjust); | 3245 | debug2("channel %d: rcvd adjust %u", c->self, adjust); |
3240 | if ((new_rwin = c->remote_window + adjust) < c->remote_window) { | 3246 | if ((new_rwin = c->remote_window + adjust) < c->remote_window) { |
3241 | fatal("channel %d: adjust %u overflows remote window %u", | 3247 | fatal("channel %d: adjust %u overflows remote window %u", |
@@ -3251,9 +3257,10 @@ channel_input_status_confirm(int type, u_int32_t seq, struct ssh *ssh) | |||
3251 | int id = channel_parse_id(ssh, __func__, "status confirm"); | 3257 | int id = channel_parse_id(ssh, __func__, "status confirm"); |
3252 | Channel *c; | 3258 | Channel *c; |
3253 | struct channel_confirm *cc; | 3259 | struct channel_confirm *cc; |
3260 | int r; | ||
3254 | 3261 | ||
3255 | /* Reset keepalive timeout */ | 3262 | /* Reset keepalive timeout */ |
3256 | packet_set_alive_timeouts(0); | 3263 | ssh_packet_set_alive_timeouts(ssh, 0); |
3257 | 3264 | ||
3258 | debug2("%s: type %d id %d", __func__, type, id); | 3265 | debug2("%s: type %d id %d", __func__, type, id); |
3259 | 3266 | ||
@@ -3263,7 +3270,8 @@ channel_input_status_confirm(int type, u_int32_t seq, struct ssh *ssh) | |||
3263 | } | 3270 | } |
3264 | if (channel_proxy_upstream(c, type, seq, ssh)) | 3271 | if (channel_proxy_upstream(c, type, seq, ssh)) |
3265 | return 0; | 3272 | return 0; |
3266 | ssh_packet_check_eom(ssh); | 3273 | if ((r = sshpkt_get_end(ssh)) != 0) |
3274 | ssh_packet_disconnect(ssh, "Invalid status confirm message"); | ||
3267 | if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) | 3275 | if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) |
3268 | return 0; | 3276 | return 0; |
3269 | cc->cb(ssh, type, c, cc->ctx); | 3277 | cc->cb(ssh, type, c, cc->ctx); |
@@ -3298,7 +3306,7 @@ channel_set_af(struct ssh *ssh, int af) | |||
3298 | * "127.0.0.1" / "::1" -> accepted even if gateway_ports isn't set | 3306 | * "127.0.0.1" / "::1" -> accepted even if gateway_ports isn't set |
3299 | */ | 3307 | */ |
3300 | static const char * | 3308 | static const char * |
3301 | channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, | 3309 | channel_fwd_bind_addr(struct ssh *ssh, const char *listen_addr, int *wildcardp, |
3302 | int is_client, struct ForwardOptions *fwd_opts) | 3310 | int is_client, struct ForwardOptions *fwd_opts) |
3303 | { | 3311 | { |
3304 | const char *addr = NULL; | 3312 | const char *addr = NULL; |
@@ -3321,7 +3329,8 @@ channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, | |||
3321 | if (*listen_addr != '\0' && | 3329 | if (*listen_addr != '\0' && |
3322 | strcmp(listen_addr, "0.0.0.0") != 0 && | 3330 | strcmp(listen_addr, "0.0.0.0") != 0 && |
3323 | strcmp(listen_addr, "*") != 0) { | 3331 | strcmp(listen_addr, "*") != 0) { |
3324 | packet_send_debug("Forwarding listen address " | 3332 | ssh_packet_send_debug(ssh, |
3333 | "Forwarding listen address " | ||
3325 | "\"%s\" overridden by server " | 3334 | "\"%s\" overridden by server " |
3326 | "GatewayPorts", listen_addr); | 3335 | "GatewayPorts", listen_addr); |
3327 | } | 3336 | } |
@@ -3375,7 +3384,7 @@ channel_setup_fwd_listener_tcpip(struct ssh *ssh, int type, | |||
3375 | } | 3384 | } |
3376 | 3385 | ||
3377 | /* Determine the bind address, cf. channel_fwd_bind_addr() comment */ | 3386 | /* Determine the bind address, cf. channel_fwd_bind_addr() comment */ |
3378 | addr = channel_fwd_bind_addr(fwd->listen_host, &wildcard, | 3387 | addr = channel_fwd_bind_addr(ssh, fwd->listen_host, &wildcard, |
3379 | is_client, fwd_opts); | 3388 | is_client, fwd_opts); |
3380 | debug3("%s: type %d wildcard %d addr %s", __func__, | 3389 | debug3("%s: type %d wildcard %d addr %s", __func__, |
3381 | type, wildcard, (addr == NULL) ? "NULL" : addr); | 3390 | type, wildcard, (addr == NULL) ? "NULL" : addr); |
@@ -3392,7 +3401,7 @@ channel_setup_fwd_listener_tcpip(struct ssh *ssh, int type, | |||
3392 | if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { | 3401 | if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { |
3393 | if (addr == NULL) { | 3402 | if (addr == NULL) { |
3394 | /* This really shouldn't happen */ | 3403 | /* This really shouldn't happen */ |
3395 | packet_disconnect("getaddrinfo: fatal error: %s", | 3404 | ssh_packet_disconnect(ssh, "getaddrinfo: fatal error: %s", |
3396 | ssh_gai_strerror(r)); | 3405 | ssh_gai_strerror(r)); |
3397 | } else { | 3406 | } else { |
3398 | error("%s: getaddrinfo(%.64s): %s", __func__, addr, | 3407 | error("%s: getaddrinfo(%.64s): %s", __func__, addr, |
@@ -3641,7 +3650,7 @@ channel_cancel_lport_listener_tcpip(struct ssh *ssh, | |||
3641 | { | 3650 | { |
3642 | u_int i; | 3651 | u_int i; |
3643 | int found = 0; | 3652 | int found = 0; |
3644 | const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, fwd_opts); | 3653 | const char *addr = channel_fwd_bind_addr(ssh, lhost, NULL, 1, fwd_opts); |
3645 | 3654 | ||
3646 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { | 3655 | for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
3647 | Channel *c = ssh->chanctxt->channels[i]; | 3656 | Channel *c = ssh->chanctxt->channels[i]; |
@@ -3793,7 +3802,7 @@ channel_setup_remote_fwd_listener(struct ssh *ssh, struct Forward *fwd, | |||
3793 | int *allocated_listen_port, struct ForwardOptions *fwd_opts) | 3802 | int *allocated_listen_port, struct ForwardOptions *fwd_opts) |
3794 | { | 3803 | { |
3795 | if (!check_rfwd_permission(ssh, fwd)) { | 3804 | if (!check_rfwd_permission(ssh, fwd)) { |
3796 | packet_send_debug("port forwarding refused"); | 3805 | ssh_packet_send_debug(ssh, "port forwarding refused"); |
3797 | return 0; | 3806 | return 0; |
3798 | } | 3807 | } |
3799 | if (fwd->listen_path != NULL) { | 3808 | if (fwd->listen_path != NULL) { |