nchan.c revision 1.32
1/* 2 * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25#include "includes.h" 26RCSID("$OpenBSD: nchan.c,v 1.32 2001/10/10 22:18:47 markus Exp $"); 27 28#include "ssh1.h" 29#include "ssh2.h" 30#include "buffer.h" 31#include "packet.h" 32#include "channels.h" 33#include "compat.h" 34#include "log.h" 35 36/* 37 * SSH Protocol 1.5 aka New Channel Protocol 38 * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored. 39 * Written by Markus Friedl in October 1999 40 * 41 * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the 42 * tear down of channels: 43 * 44 * 1.3: strict request-ack-protocol: 45 * CLOSE -> 46 * <- CLOSE_CONFIRM 47 * 48 * 1.5: uses variations of: 49 * IEOF -> 50 * <- OCLOSE 51 * <- IEOF 52 * OCLOSE -> 53 * i.e. both sides have to close the channel 54 * 55 * 2.0: the EOF messages are optional 56 * 57 * See the debugging output from 'ssh -v' and 'sshd -d' of 58 * ssh-1.2.27 as an example. 59 * 60 */ 61 62/* functions manipulating channel states */ 63/* 64 * EVENTS update channel input/output states execute ACTIONS 65 */ 66/* events concerning the INPUT from socket for channel (istate) */ 67chan_event_fn *chan_rcvd_oclose = NULL; 68chan_event_fn *chan_read_failed = NULL; 69chan_event_fn *chan_ibuf_empty = NULL; 70/* events concerning the OUTPUT from channel for socket (ostate) */ 71chan_event_fn *chan_rcvd_ieof = NULL; 72chan_event_fn *chan_write_failed = NULL; 73chan_event_fn *chan_obuf_empty = NULL; 74/* 75 * ACTIONS: should never update the channel states 76 */ 77static void chan_send_ieof1(Channel *); 78static void chan_send_oclose1(Channel *); 79static void chan_send_close2(Channel *); 80static void chan_send_eof2(Channel *); 81 82/* helper */ 83static void chan_shutdown_write(Channel *); 84static void chan_shutdown_read(Channel *); 85 86/* 87 * SSH1 specific implementation of event functions 88 */ 89 90static void 91chan_rcvd_oclose1(Channel *c) 92{ 93 debug("channel %d: rcvd oclose", c->self); 94 switch (c->istate) { 95 case CHAN_INPUT_WAIT_OCLOSE: 96 debug("channel %d: input wait_oclose -> closed", c->self); 97 c->istate = CHAN_INPUT_CLOSED; 98 break; 99 case CHAN_INPUT_OPEN: 100 debug("channel %d: input open -> closed", c->self); 101 chan_shutdown_read(c); 102 chan_send_ieof1(c); 103 c->istate = CHAN_INPUT_CLOSED; 104 break; 105 case CHAN_INPUT_WAIT_DRAIN: 106 /* both local read_failed and remote write_failed */ 107 log("channel %d: input drain -> closed", c->self); 108 chan_send_ieof1(c); 109 c->istate = CHAN_INPUT_CLOSED; 110 break; 111 default: 112 error("channel %d: protocol error: rcvd_oclose for istate %d", 113 c->self, c->istate); 114 return; 115 } 116} 117static void 118chan_read_failed_12(Channel *c) 119{ 120 debug("channel %d: read failed", c->self); 121 switch (c->istate) { 122 case CHAN_INPUT_OPEN: 123 debug("channel %d: input open -> drain", c->self); 124 chan_shutdown_read(c); 125 c->istate = CHAN_INPUT_WAIT_DRAIN; 126#if 0 127 if (buffer_len(&c->input) == 0) { 128 debug("channel %d: input: no drain shortcut", c->self); 129 chan_ibuf_empty(c); 130 } 131#endif 132 break; 133 default: 134 error("channel %d: chan_read_failed for istate %d", 135 c->self, c->istate); 136 break; 137 } 138} 139static void 140chan_ibuf_empty1(Channel *c) 141{ 142 debug("channel %d: ibuf empty", c->self); 143 if (buffer_len(&c->input)) { 144 error("channel %d: chan_ibuf_empty for non empty buffer", 145 c->self); 146 return; 147 } 148 switch (c->istate) { 149 case CHAN_INPUT_WAIT_DRAIN: 150 debug("channel %d: input drain -> wait_oclose", c->self); 151 chan_send_ieof1(c); 152 c->istate = CHAN_INPUT_WAIT_OCLOSE; 153 break; 154 default: 155 error("channel %d: chan_ibuf_empty for istate %d", 156 c->self, c->istate); 157 break; 158 } 159} 160static void 161chan_rcvd_ieof1(Channel *c) 162{ 163 debug("channel %d: rcvd ieof", c->self); 164 if (c->type != SSH_CHANNEL_OPEN) { 165 debug("channel %d: non-open", c->self); 166 if (c->istate == CHAN_INPUT_OPEN) { 167 debug("channel %d: non-open: input open -> wait_oclose", 168 c->self); 169 chan_shutdown_read(c); 170 chan_send_ieof1(c); 171 c->istate = CHAN_INPUT_WAIT_OCLOSE; 172 } else { 173 error("channel %d: non-open: istate %d != open", 174 c->self, c->istate); 175 } 176 if (c->ostate == CHAN_OUTPUT_OPEN) { 177 debug("channel %d: non-open: output open -> closed", 178 c->self); 179 chan_send_oclose1(c); 180 c->ostate = CHAN_OUTPUT_CLOSED; 181 } else { 182 error("channel %d: non-open: ostate %d != open", 183 c->self, c->ostate); 184 } 185 return; 186 } 187 switch (c->ostate) { 188 case CHAN_OUTPUT_OPEN: 189 debug("channel %d: output open -> drain", c->self); 190 c->ostate = CHAN_OUTPUT_WAIT_DRAIN; 191 break; 192 case CHAN_OUTPUT_WAIT_IEOF: 193 debug("channel %d: output wait_ieof -> closed", c->self); 194 c->ostate = CHAN_OUTPUT_CLOSED; 195 break; 196 default: 197 error("channel %d: protocol error: rcvd_ieof for ostate %d", 198 c->self, c->ostate); 199 break; 200 } 201} 202static void 203chan_write_failed1(Channel *c) 204{ 205 debug("channel %d: write failed", c->self); 206 switch (c->ostate) { 207 case CHAN_OUTPUT_OPEN: 208 debug("channel %d: output open -> wait_ieof", c->self); 209 chan_send_oclose1(c); 210 c->ostate = CHAN_OUTPUT_WAIT_IEOF; 211 break; 212 case CHAN_OUTPUT_WAIT_DRAIN: 213 debug("channel %d: output wait_drain -> closed", c->self); 214 chan_send_oclose1(c); 215 c->ostate = CHAN_OUTPUT_CLOSED; 216 break; 217 default: 218 error("channel %d: chan_write_failed for ostate %d", 219 c->self, c->ostate); 220 break; 221 } 222} 223static void 224chan_obuf_empty1(Channel *c) 225{ 226 debug("channel %d: obuf empty", c->self); 227 if (buffer_len(&c->output)) { 228 error("channel %d: chan_obuf_empty for non empty buffer", 229 c->self); 230 return; 231 } 232 switch (c->ostate) { 233 case CHAN_OUTPUT_WAIT_DRAIN: 234 debug("channel %d: output drain -> closed", c->self); 235 chan_send_oclose1(c); 236 c->ostate = CHAN_OUTPUT_CLOSED; 237 break; 238 default: 239 error("channel %d: internal error: obuf_empty for ostate %d", 240 c->self, c->ostate); 241 break; 242 } 243} 244static void 245chan_send_ieof1(Channel *c) 246{ 247 debug("channel %d: send ieof", c->self); 248 switch (c->istate) { 249 case CHAN_INPUT_OPEN: 250 case CHAN_INPUT_WAIT_DRAIN: 251 packet_start(SSH_MSG_CHANNEL_INPUT_EOF); 252 packet_put_int(c->remote_id); 253 packet_send(); 254 break; 255 default: 256 error("channel %d: cannot send ieof for istate %d", 257 c->self, c->istate); 258 break; 259 } 260} 261static void 262chan_send_oclose1(Channel *c) 263{ 264 debug("channel %d: send oclose", c->self); 265 switch (c->ostate) { 266 case CHAN_OUTPUT_OPEN: 267 case CHAN_OUTPUT_WAIT_DRAIN: 268 chan_shutdown_write(c); 269 buffer_consume(&c->output, buffer_len(&c->output)); 270 packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE); 271 packet_put_int(c->remote_id); 272 packet_send(); 273 break; 274 default: 275 error("channel %d: cannot send oclose for ostate %d", 276 c->self, c->ostate); 277 break; 278 } 279} 280 281/* 282 * the same for SSH2 283 */ 284static void 285chan_rcvd_oclose2(Channel *c) 286{ 287 debug("channel %d: rcvd close", c->self); 288 if (c->flags & CHAN_CLOSE_RCVD) 289 error("channel %d: protocol error: close rcvd twice", c->self); 290 c->flags |= CHAN_CLOSE_RCVD; 291 if (c->type == SSH_CHANNEL_LARVAL) { 292 /* tear down larval channels immediately */ 293 c->ostate = CHAN_OUTPUT_CLOSED; 294 c->istate = CHAN_INPUT_CLOSED; 295 return; 296 } 297 switch (c->ostate) { 298 case CHAN_OUTPUT_OPEN: 299 /* 300 * wait until a data from the channel is consumed if a CLOSE 301 * is received 302 */ 303 debug("channel %d: output open -> drain", c->self); 304 c->ostate = CHAN_OUTPUT_WAIT_DRAIN; 305 break; 306 } 307 switch (c->istate) { 308 case CHAN_INPUT_OPEN: 309 debug("channel %d: input open -> closed", c->self); 310 chan_shutdown_read(c); 311 break; 312 case CHAN_INPUT_WAIT_DRAIN: 313 debug("channel %d: input drain -> closed", c->self); 314 chan_send_eof2(c); 315 break; 316 } 317 c->istate = CHAN_INPUT_CLOSED; 318} 319static void 320chan_ibuf_empty2(Channel *c) 321{ 322 debug("channel %d: ibuf empty", c->self); 323 if (buffer_len(&c->input)) { 324 error("channel %d: chan_ibuf_empty for non empty buffer", 325 c->self); 326 return; 327 } 328 switch (c->istate) { 329 case CHAN_INPUT_WAIT_DRAIN: 330 debug("channel %d: input drain -> closed", c->self); 331 if (!(c->flags & CHAN_CLOSE_SENT)) 332 chan_send_eof2(c); 333 c->istate = CHAN_INPUT_CLOSED; 334 break; 335 default: 336 error("channel %d: chan_ibuf_empty for istate %d", 337 c->self, c->istate); 338 break; 339 } 340} 341static void 342chan_rcvd_ieof2(Channel *c) 343{ 344 debug("channel %d: rcvd eof", c->self); 345 if (c->ostate == CHAN_OUTPUT_OPEN) { 346 debug("channel %d: output open -> drain", c->self); 347 c->ostate = CHAN_OUTPUT_WAIT_DRAIN; 348 } 349} 350static void 351chan_write_failed2(Channel *c) 352{ 353 debug("channel %d: write failed", c->self); 354 switch (c->ostate) { 355 case CHAN_OUTPUT_OPEN: 356 debug("channel %d: output open -> closed", c->self); 357 chan_shutdown_write(c); /* ?? */ 358 c->ostate = CHAN_OUTPUT_CLOSED; 359 break; 360 case CHAN_OUTPUT_WAIT_DRAIN: 361 debug("channel %d: output drain -> closed", c->self); 362 chan_shutdown_write(c); 363 c->ostate = CHAN_OUTPUT_CLOSED; 364 break; 365 default: 366 error("channel %d: chan_write_failed for ostate %d", 367 c->self, c->ostate); 368 break; 369 } 370} 371static void 372chan_obuf_empty2(Channel *c) 373{ 374 debug("channel %d: obuf empty", c->self); 375 if (buffer_len(&c->output)) { 376 error("channel %d: chan_obuf_empty for non empty buffer", 377 c->self); 378 return; 379 } 380 switch (c->ostate) { 381 case CHAN_OUTPUT_WAIT_DRAIN: 382 debug("channel %d: output drain -> closed", c->self); 383 chan_shutdown_write(c); 384 c->ostate = CHAN_OUTPUT_CLOSED; 385 break; 386 default: 387 error("channel %d: chan_obuf_empty for ostate %d", 388 c->self, c->ostate); 389 break; 390 } 391} 392static void 393chan_send_eof2(Channel *c) 394{ 395 debug("channel %d: send eof", c->self); 396 switch (c->istate) { 397 case CHAN_INPUT_WAIT_DRAIN: 398 packet_start(SSH2_MSG_CHANNEL_EOF); 399 packet_put_int(c->remote_id); 400 packet_send(); 401 break; 402 default: 403 error("channel %d: cannot send eof for istate %d", 404 c->self, c->istate); 405 break; 406 } 407} 408static void 409chan_send_close2(Channel *c) 410{ 411 debug("channel %d: send close", c->self); 412 if (c->ostate != CHAN_OUTPUT_CLOSED || 413 c->istate != CHAN_INPUT_CLOSED) { 414 error("channel %d: cannot send close for istate/ostate %d/%d", 415 c->self, c->istate, c->ostate); 416 } else if (c->flags & CHAN_CLOSE_SENT) { 417 error("channel %d: already sent close", c->self); 418 } else { 419 packet_start(SSH2_MSG_CHANNEL_CLOSE); 420 packet_put_int(c->remote_id); 421 packet_send(); 422 c->flags |= CHAN_CLOSE_SENT; 423 } 424} 425 426/* shared */ 427 428void 429chan_mark_dead(Channel *c) 430{ 431 c->type = SSH_CHANNEL_ZOMBIE; 432} 433 434int 435chan_is_dead(Channel *c, int send) 436{ 437 if (c->type == SSH_CHANNEL_ZOMBIE) { 438 debug("channel %d: zombie", c->self); 439 return 1; 440 } 441 if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED) 442 return 0; 443 if (!compat20) { 444 debug("channel %d: is dead", c->self); 445 return 1; 446 } 447 /* 448 * we have to delay the close message if the efd (for stderr) is 449 * still active 450 */ 451 if (((c->extended_usage != CHAN_EXTENDED_IGNORE) && 452 buffer_len(&c->extended) > 0) 453#if 0 454 || ((c->extended_usage == CHAN_EXTENDED_READ) && 455 c->efd != -1) 456#endif 457 ) { 458 debug2("channel %d: active efd: %d len %d type %s", 459 c->self, c->efd, buffer_len(&c->extended), 460 c->extended_usage==CHAN_EXTENDED_READ ? 461 "read": "write"); 462 } else { 463 if (!(c->flags & CHAN_CLOSE_SENT)) { 464 if (send) { 465 chan_send_close2(c); 466 } else { 467 /* channel would be dead if we sent a close */ 468 if (c->flags & CHAN_CLOSE_RCVD) { 469 debug("channel %d: almost dead", 470 c->self); 471 return 1; 472 } 473 } 474 } 475 if ((c->flags & CHAN_CLOSE_SENT) && 476 (c->flags & CHAN_CLOSE_RCVD)) { 477 debug("channel %d: is dead", c->self); 478 return 1; 479 } 480 } 481 return 0; 482} 483 484void 485chan_init_iostates(Channel *c) 486{ 487 c->ostate = CHAN_OUTPUT_OPEN; 488 c->istate = CHAN_INPUT_OPEN; 489 c->flags = 0; 490} 491 492/* init */ 493void 494chan_init(void) 495{ 496 if (compat20) { 497 chan_rcvd_oclose = chan_rcvd_oclose2; 498 chan_read_failed = chan_read_failed_12; 499 chan_ibuf_empty = chan_ibuf_empty2; 500 501 chan_rcvd_ieof = chan_rcvd_ieof2; 502 chan_write_failed = chan_write_failed2; 503 chan_obuf_empty = chan_obuf_empty2; 504 } else { 505 chan_rcvd_oclose = chan_rcvd_oclose1; 506 chan_read_failed = chan_read_failed_12; 507 chan_ibuf_empty = chan_ibuf_empty1; 508 509 chan_rcvd_ieof = chan_rcvd_ieof1; 510 chan_write_failed = chan_write_failed1; 511 chan_obuf_empty = chan_obuf_empty1; 512 } 513} 514 515/* helper */ 516static void 517chan_shutdown_write(Channel *c) 518{ 519 buffer_consume(&c->output, buffer_len(&c->output)); 520 if (compat20 && c->type == SSH_CHANNEL_LARVAL) 521 return; 522 /* shutdown failure is allowed if write failed already */ 523 debug("channel %d: close_write", c->self); 524 if (c->sock != -1) { 525 if (shutdown(c->sock, SHUT_WR) < 0) 526 debug("channel %d: chan_shutdown_write: " 527 "shutdown() failed for fd%d: %.100s", 528 c->self, c->sock, strerror(errno)); 529 } else { 530 if (channel_close_fd(&c->wfd) < 0) 531 log("channel %d: chan_shutdown_write: " 532 "close() failed for fd%d: %.100s", 533 c->self, c->wfd, strerror(errno)); 534 } 535} 536static void 537chan_shutdown_read(Channel *c) 538{ 539 if (compat20 && c->type == SSH_CHANNEL_LARVAL) 540 return; 541 debug("channel %d: close_read", c->self); 542 if (c->sock != -1) { 543 if (shutdown(c->sock, SHUT_RD) < 0) 544 error("channel %d: chan_shutdown_read: " 545 "shutdown() failed for fd%d [i%d o%d]: %.100s", 546 c->self, c->sock, c->istate, c->ostate, 547 strerror(errno)); 548 } else { 549 if (channel_close_fd(&c->rfd) < 0) 550 log("channel %d: chan_shutdown_read: " 551 "close() failed for fd%d: %.100s", 552 c->self, c->rfd, strerror(errno)); 553 } 554} 555