summaryrefslogtreecommitdiff
path: root/nchan.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2017-09-12 06:32:07 +0000
committerDamien Miller <djm@mindrot.org>2017-09-12 17:37:02 +1000
commitdbee4119b502e3f8b6cd3282c69c537fd01d8e16 (patch)
treeb8a3263a79e0920e8d08f188654f1ccb7c254406 /nchan.c
parentabd59663df37a42152e37980113ccaa405b9a282 (diff)
upstream commit
refactor channels.c Move static state to a "struct ssh_channels" that is allocated at runtime and tracked as a member of struct ssh. Explicitly pass "struct ssh" to all channels functions. Replace use of the legacy packet APIs in channels.c. Rework sshd_config PermitOpen handling: previously the configuration parser would call directly into the channels layer. After the refactor this is not possible, as the channels structures are allocated at connection time and aren't available when the configuration is parsed. The server config parser now tracks PermitOpen itself and explicitly configures the channels code later. ok markus@ Upstream-ID: 11828f161656b965cc306576422613614bea2d8f
Diffstat (limited to 'nchan.c')
-rw-r--r--nchan.c114
1 files changed, 62 insertions, 52 deletions
diff --git a/nchan.c b/nchan.c
index 36da8904a..74c855c90 100644
--- a/nchan.c
+++ b/nchan.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: nchan.c,v 1.65 2017/04/30 23:28:42 djm Exp $ */ 1/* $OpenBSD: nchan.c,v 1.66 2017/09/12 06:32:07 djm Exp $ */
2/* 2/*
3 * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. 3 * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
4 * 4 *
@@ -34,7 +34,8 @@
34 34
35#include "openbsd-compat/sys-queue.h" 35#include "openbsd-compat/sys-queue.h"
36#include "ssh2.h" 36#include "ssh2.h"
37#include "buffer.h" 37#include "sshbuf.h"
38#include "ssherr.h"
38#include "packet.h" 39#include "packet.h"
39#include "channels.h" 40#include "channels.h"
40#include "compat.h" 41#include "compat.h"
@@ -73,15 +74,15 @@
73/* 74/*
74 * ACTIONS: should never update the channel states 75 * ACTIONS: should never update the channel states
75 */ 76 */
76static void chan_send_eof2(Channel *); 77static void chan_send_eof2(struct ssh *, Channel *);
77static void chan_send_eow2(Channel *); 78static void chan_send_eow2(struct ssh *, Channel *);
78 79
79/* helper */ 80/* helper */
80static void chan_shutdown_write(Channel *); 81static void chan_shutdown_write(struct ssh *, Channel *);
81static void chan_shutdown_read(Channel *); 82static void chan_shutdown_read(struct ssh *, Channel *);
82 83
83static char *ostates[] = { "open", "drain", "wait_ieof", "closed" }; 84static const char *ostates[] = { "open", "drain", "wait_ieof", "closed" };
84static char *istates[] = { "open", "drain", "wait_oclose", "closed" }; 85static const char *istates[] = { "open", "drain", "wait_oclose", "closed" };
85 86
86static void 87static void
87chan_set_istate(Channel *c, u_int next) 88chan_set_istate(Channel *c, u_int next)
@@ -104,12 +105,12 @@ chan_set_ostate(Channel *c, u_int next)
104} 105}
105 106
106void 107void
107chan_read_failed(Channel *c) 108chan_read_failed(struct ssh *ssh, Channel *c)
108{ 109{
109 debug2("channel %d: read failed", c->self); 110 debug2("channel %d: read failed", c->self);
110 switch (c->istate) { 111 switch (c->istate) {
111 case CHAN_INPUT_OPEN: 112 case CHAN_INPUT_OPEN:
112 chan_shutdown_read(c); 113 chan_shutdown_read(ssh, c);
113 chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN); 114 chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN);
114 break; 115 break;
115 default: 116 default:
@@ -120,10 +121,10 @@ chan_read_failed(Channel *c)
120} 121}
121 122
122void 123void
123chan_ibuf_empty(Channel *c) 124chan_ibuf_empty(struct ssh *ssh, Channel *c)
124{ 125{
125 debug2("channel %d: ibuf empty", c->self); 126 debug2("channel %d: ibuf empty", c->self);
126 if (buffer_len(&c->input)) { 127 if (sshbuf_len(c->input)) {
127 error("channel %d: chan_ibuf_empty for non empty buffer", 128 error("channel %d: chan_ibuf_empty for non empty buffer",
128 c->self); 129 c->self);
129 return; 130 return;
@@ -131,7 +132,7 @@ chan_ibuf_empty(Channel *c)
131 switch (c->istate) { 132 switch (c->istate) {
132 case CHAN_INPUT_WAIT_DRAIN: 133 case CHAN_INPUT_WAIT_DRAIN:
133 if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL))) 134 if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL)))
134 chan_send_eof2(c); 135 chan_send_eof2(ssh, c);
135 chan_set_istate(c, CHAN_INPUT_CLOSED); 136 chan_set_istate(c, CHAN_INPUT_CLOSED);
136 break; 137 break;
137 default: 138 default:
@@ -142,17 +143,17 @@ chan_ibuf_empty(Channel *c)
142} 143}
143 144
144void 145void
145chan_obuf_empty(Channel *c) 146chan_obuf_empty(struct ssh *ssh, Channel *c)
146{ 147{
147 debug2("channel %d: obuf empty", c->self); 148 debug2("channel %d: obuf empty", c->self);
148 if (buffer_len(&c->output)) { 149 if (sshbuf_len(c->output)) {
149 error("channel %d: chan_obuf_empty for non empty buffer", 150 error("channel %d: chan_obuf_empty for non empty buffer",
150 c->self); 151 c->self);
151 return; 152 return;
152 } 153 }
153 switch (c->ostate) { 154 switch (c->ostate) {
154 case CHAN_OUTPUT_WAIT_DRAIN: 155 case CHAN_OUTPUT_WAIT_DRAIN:
155 chan_shutdown_write(c); 156 chan_shutdown_write(ssh, c);
156 chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 157 chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
157 break; 158 break;
158 default: 159 default:
@@ -163,26 +164,29 @@ chan_obuf_empty(Channel *c)
163} 164}
164 165
165void 166void
166chan_rcvd_eow(Channel *c) 167chan_rcvd_eow(struct ssh *ssh, Channel *c)
167{ 168{
168 debug2("channel %d: rcvd eow", c->self); 169 debug2("channel %d: rcvd eow", c->self);
169 switch (c->istate) { 170 switch (c->istate) {
170 case CHAN_INPUT_OPEN: 171 case CHAN_INPUT_OPEN:
171 chan_shutdown_read(c); 172 chan_shutdown_read(ssh, c);
172 chan_set_istate(c, CHAN_INPUT_CLOSED); 173 chan_set_istate(c, CHAN_INPUT_CLOSED);
173 break; 174 break;
174 } 175 }
175} 176}
176 177
177static void 178static void
178chan_send_eof2(Channel *c) 179chan_send_eof2(struct ssh *ssh, Channel *c)
179{ 180{
181 int r;
182
180 debug2("channel %d: send eof", c->self); 183 debug2("channel %d: send eof", c->self);
181 switch (c->istate) { 184 switch (c->istate) {
182 case CHAN_INPUT_WAIT_DRAIN: 185 case CHAN_INPUT_WAIT_DRAIN:
183 packet_start(SSH2_MSG_CHANNEL_EOF); 186 if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EOF)) != 0 ||
184 packet_put_int(c->remote_id); 187 (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
185 packet_send(); 188 (r = sshpkt_send(ssh)) != 0)
189 fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r));
186 c->flags |= CHAN_EOF_SENT; 190 c->flags |= CHAN_EOF_SENT;
187 break; 191 break;
188 default: 192 default:
@@ -193,8 +197,10 @@ chan_send_eof2(Channel *c)
193} 197}
194 198
195static void 199static void
196chan_send_close2(Channel *c) 200chan_send_close2(struct ssh *ssh, Channel *c)
197{ 201{
202 int r;
203
198 debug2("channel %d: send close", c->self); 204 debug2("channel %d: send close", c->self);
199 if (c->ostate != CHAN_OUTPUT_CLOSED || 205 if (c->ostate != CHAN_OUTPUT_CLOSED ||
200 c->istate != CHAN_INPUT_CLOSED) { 206 c->istate != CHAN_INPUT_CLOSED) {
@@ -203,16 +209,19 @@ chan_send_close2(Channel *c)
203 } else if (c->flags & CHAN_CLOSE_SENT) { 209 } else if (c->flags & CHAN_CLOSE_SENT) {
204 error("channel %d: already sent close", c->self); 210 error("channel %d: already sent close", c->self);
205 } else { 211 } else {
206 packet_start(SSH2_MSG_CHANNEL_CLOSE); 212 if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_CLOSE)) != 0 ||
207 packet_put_int(c->remote_id); 213 (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
208 packet_send(); 214 (r = sshpkt_send(ssh)) != 0)
215 fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r));
209 c->flags |= CHAN_CLOSE_SENT; 216 c->flags |= CHAN_CLOSE_SENT;
210 } 217 }
211} 218}
212 219
213static void 220static void
214chan_send_eow2(Channel *c) 221chan_send_eow2(struct ssh *ssh, Channel *c)
215{ 222{
223 int r;
224
216 debug2("channel %d: send eow", c->self); 225 debug2("channel %d: send eow", c->self);
217 if (c->ostate == CHAN_OUTPUT_CLOSED) { 226 if (c->ostate == CHAN_OUTPUT_CLOSED) {
218 error("channel %d: must not sent eow on closed output", 227 error("channel %d: must not sent eow on closed output",
@@ -221,30 +230,31 @@ chan_send_eow2(Channel *c)
221 } 230 }
222 if (!(datafellows & SSH_NEW_OPENSSH)) 231 if (!(datafellows & SSH_NEW_OPENSSH))
223 return; 232 return;
224 packet_start(SSH2_MSG_CHANNEL_REQUEST); 233 if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 ||
225 packet_put_int(c->remote_id); 234 (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
226 packet_put_cstring("eow@openssh.com"); 235 (r = sshpkt_put_cstring(ssh, "eow@openssh.com")) != 0 ||
227 packet_put_char(0); 236 (r = sshpkt_put_u8(ssh, 0)) != 0 ||
228 packet_send(); 237 (r = sshpkt_send(ssh)) != 0)
238 fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r));
229} 239}
230 240
231/* shared */ 241/* shared */
232 242
233void 243void
234chan_rcvd_ieof(Channel *c) 244chan_rcvd_ieof(struct ssh *ssh, Channel *c)
235{ 245{
236 debug2("channel %d: rcvd eof", c->self); 246 debug2("channel %d: rcvd eof", c->self);
237 c->flags |= CHAN_EOF_RCVD; 247 c->flags |= CHAN_EOF_RCVD;
238 if (c->ostate == CHAN_OUTPUT_OPEN) 248 if (c->ostate == CHAN_OUTPUT_OPEN)
239 chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 249 chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
240 if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN && 250 if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
241 buffer_len(&c->output) == 0 && 251 sshbuf_len(c->output) == 0 &&
242 !CHANNEL_EFD_OUTPUT_ACTIVE(c)) 252 !CHANNEL_EFD_OUTPUT_ACTIVE(c))
243 chan_obuf_empty(c); 253 chan_obuf_empty(ssh, c);
244} 254}
245 255
246void 256void
247chan_rcvd_oclose(Channel *c) 257chan_rcvd_oclose(struct ssh *ssh, Channel *c)
248{ 258{
249 debug2("channel %d: rcvd close", c->self); 259 debug2("channel %d: rcvd close", c->self);
250 if (!(c->flags & CHAN_LOCAL)) { 260 if (!(c->flags & CHAN_LOCAL)) {
@@ -270,27 +280,27 @@ chan_rcvd_oclose(Channel *c)
270 } 280 }
271 switch (c->istate) { 281 switch (c->istate) {
272 case CHAN_INPUT_OPEN: 282 case CHAN_INPUT_OPEN:
273 chan_shutdown_read(c); 283 chan_shutdown_read(ssh, c);
274 chan_set_istate(c, CHAN_INPUT_CLOSED); 284 chan_set_istate(c, CHAN_INPUT_CLOSED);
275 break; 285 break;
276 case CHAN_INPUT_WAIT_DRAIN: 286 case CHAN_INPUT_WAIT_DRAIN:
277 if (!(c->flags & CHAN_LOCAL)) 287 if (!(c->flags & CHAN_LOCAL))
278 chan_send_eof2(c); 288 chan_send_eof2(ssh, c);
279 chan_set_istate(c, CHAN_INPUT_CLOSED); 289 chan_set_istate(c, CHAN_INPUT_CLOSED);
280 break; 290 break;
281 } 291 }
282} 292}
283 293
284void 294void
285chan_write_failed(Channel *c) 295chan_write_failed(struct ssh *ssh, Channel *c)
286{ 296{
287 debug2("channel %d: write failed", c->self); 297 debug2("channel %d: write failed", c->self);
288 switch (c->ostate) { 298 switch (c->ostate) {
289 case CHAN_OUTPUT_OPEN: 299 case CHAN_OUTPUT_OPEN:
290 case CHAN_OUTPUT_WAIT_DRAIN: 300 case CHAN_OUTPUT_WAIT_DRAIN:
291 chan_shutdown_write(c); 301 chan_shutdown_write(ssh, c);
292 if (strcmp(c->ctype, "session") == 0) 302 if (strcmp(c->ctype, "session") == 0)
293 chan_send_eow2(c); 303 chan_send_eow2(ssh, c);
294 chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 304 chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
295 break; 305 break;
296 default: 306 default:
@@ -301,13 +311,13 @@ chan_write_failed(Channel *c)
301} 311}
302 312
303void 313void
304chan_mark_dead(Channel *c) 314chan_mark_dead(struct ssh *ssh, Channel *c)
305{ 315{
306 c->type = SSH_CHANNEL_ZOMBIE; 316 c->type = SSH_CHANNEL_ZOMBIE;
307} 317}
308 318
309int 319int
310chan_is_dead(Channel *c, int do_send) 320chan_is_dead(struct ssh *ssh, Channel *c, int do_send)
311{ 321{
312 if (c->type == SSH_CHANNEL_ZOMBIE) { 322 if (c->type == SSH_CHANNEL_ZOMBIE) {
313 debug2("channel %d: zombie", c->self); 323 debug2("channel %d: zombie", c->self);
@@ -318,9 +328,9 @@ chan_is_dead(Channel *c, int do_send)
318 if ((datafellows & SSH_BUG_EXTEOF) && 328 if ((datafellows & SSH_BUG_EXTEOF) &&
319 c->extended_usage == CHAN_EXTENDED_WRITE && 329 c->extended_usage == CHAN_EXTENDED_WRITE &&
320 c->efd != -1 && 330 c->efd != -1 &&
321 buffer_len(&c->extended) > 0) { 331 sshbuf_len(c->extended) > 0) {
322 debug2("channel %d: active efd: %d len %d", 332 debug2("channel %d: active efd: %d len %zu",
323 c->self, c->efd, buffer_len(&c->extended)); 333 c->self, c->efd, sshbuf_len(c->extended));
324 return 0; 334 return 0;
325 } 335 }
326 if (c->flags & CHAN_LOCAL) { 336 if (c->flags & CHAN_LOCAL) {
@@ -329,7 +339,7 @@ chan_is_dead(Channel *c, int do_send)
329 } 339 }
330 if (!(c->flags & CHAN_CLOSE_SENT)) { 340 if (!(c->flags & CHAN_CLOSE_SENT)) {
331 if (do_send) { 341 if (do_send) {
332 chan_send_close2(c); 342 chan_send_close2(ssh, c);
333 } else { 343 } else {
334 /* channel would be dead if we sent a close */ 344 /* channel would be dead if we sent a close */
335 if (c->flags & CHAN_CLOSE_RCVD) { 345 if (c->flags & CHAN_CLOSE_RCVD) {
@@ -349,9 +359,9 @@ chan_is_dead(Channel *c, int do_send)
349 359
350/* helper */ 360/* helper */
351static void 361static void
352chan_shutdown_write(Channel *c) 362chan_shutdown_write(struct ssh *ssh, Channel *c)
353{ 363{
354 buffer_clear(&c->output); 364 sshbuf_reset(c->output);
355 if (c->type == SSH_CHANNEL_LARVAL) 365 if (c->type == SSH_CHANNEL_LARVAL)
356 return; 366 return;
357 /* shutdown failure is allowed if write failed already */ 367 /* shutdown failure is allowed if write failed already */
@@ -362,7 +372,7 @@ chan_shutdown_write(Channel *c)
362 "shutdown() failed for fd %d: %.100s", 372 "shutdown() failed for fd %d: %.100s",
363 c->self, c->sock, strerror(errno)); 373 c->self, c->sock, strerror(errno));
364 } else { 374 } else {
365 if (channel_close_fd(&c->wfd) < 0) 375 if (channel_close_fd(ssh, &c->wfd) < 0)
366 logit("channel %d: chan_shutdown_write: " 376 logit("channel %d: chan_shutdown_write: "
367 "close() failed for fd %d: %.100s", 377 "close() failed for fd %d: %.100s",
368 c->self, c->wfd, strerror(errno)); 378 c->self, c->wfd, strerror(errno));
@@ -370,7 +380,7 @@ chan_shutdown_write(Channel *c)
370} 380}
371 381
372static void 382static void
373chan_shutdown_read(Channel *c) 383chan_shutdown_read(struct ssh *ssh, Channel *c)
374{ 384{
375 if (c->type == SSH_CHANNEL_LARVAL) 385 if (c->type == SSH_CHANNEL_LARVAL)
376 return; 386 return;
@@ -388,7 +398,7 @@ chan_shutdown_read(Channel *c)
388 c->self, c->sock, c->istate, c->ostate, 398 c->self, c->sock, c->istate, c->ostate,
389 strerror(errno)); 399 strerror(errno));
390 } else { 400 } else {
391 if (channel_close_fd(&c->rfd) < 0) 401 if (channel_close_fd(ssh, &c->rfd) < 0)
392 logit("channel %d: chan_shutdown_read: " 402 logit("channel %d: chan_shutdown_read: "
393 "close() failed for fd %d: %.100s", 403 "close() failed for fd %d: %.100s",
394 c->self, c->rfd, strerror(errno)); 404 c->self, c->rfd, strerror(errno));