1 /* 2 * Copyright (c) 1999 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 * 3. All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by Markus Friedl. 15 * 4. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "includes.h" 31 RCSID("$Id: nchan.c,v 1.17 2000/05/08 17:44:54 markus Exp $"); 32 33 #include "ssh.h" 34 35 #include "buffer.h" 36 #include "packet.h" 37 #include "channels.h" 38 #include "nchan.h" 39 40 #include "ssh2.h" 41 #include "compat.h" 42 43 /* functions manipulating channel states */ 44 /* 45 * EVENTS update channel input/output states execute ACTIONS 46 */ 47 /* events concerning the INPUT from socket for channel (istate) */ 48 chan_event_fn *chan_rcvd_oclose = NULL; 49 chan_event_fn *chan_read_failed = NULL; 50 chan_event_fn *chan_ibuf_empty = NULL; 51 /* events concerning the OUTPUT from channel for socket (ostate) */ 52 chan_event_fn *chan_rcvd_ieof = NULL; 53 chan_event_fn *chan_write_failed = NULL; 54 chan_event_fn *chan_obuf_empty = NULL; 55 /* 56 * ACTIONS: should never update the channel states 57 */ 58 static void chan_send_ieof1(Channel *c); 59 static void chan_send_oclose1(Channel *c); 60 static void chan_send_close2(Channel *c); 61 static void chan_send_eof2(Channel *c); 62 63 /* channel cleanup */ 64 chan_event_fn *chan_delete_if_full_closed = NULL; 65 66 /* helper */ 67 static void chan_shutdown_write(Channel *c); 68 static void chan_shutdown_read(Channel *c); 69 70 /* 71 * SSH1 specific implementation of event functions 72 */ 73 74 static void 75 chan_rcvd_oclose1(Channel *c) 76 { 77 debug("channel %d: rcvd oclose", c->self); 78 switch (c->istate) { 79 case CHAN_INPUT_WAIT_OCLOSE: 80 debug("channel %d: input wait_oclose -> closed", c->self); 81 c->istate = CHAN_INPUT_CLOSED; 82 break; 83 case CHAN_INPUT_OPEN: 84 debug("channel %d: input open -> closed", c->self); 85 chan_shutdown_read(c); 86 chan_send_ieof1(c); 87 c->istate = CHAN_INPUT_CLOSED; 88 break; 89 case CHAN_INPUT_WAIT_DRAIN: 90 /* both local read_failed and remote write_failed */ 91 log("channel %d: input drain -> closed", c->self); 92 chan_send_ieof1(c); 93 c->istate = CHAN_INPUT_CLOSED; 94 break; 95 default: 96 error("channel %d: protocol error: chan_rcvd_oclose for istate %d", 97 c->self, c->istate); 98 return; 99 } 100 } 101 static void 102 chan_read_failed_12(Channel *c) 103 { 104 debug("channel %d: read failed", c->self); 105 switch (c->istate) { 106 case CHAN_INPUT_OPEN: 107 debug("channel %d: input open -> drain", c->self); 108 chan_shutdown_read(c); 109 c->istate = CHAN_INPUT_WAIT_DRAIN; 110 if (buffer_len(&c->input) == 0) { 111 debug("channel %d: input: no drain shortcut", c->self); 112 chan_ibuf_empty(c); 113 } 114 break; 115 default: 116 error("channel %d: internal error: we do not read, but chan_read_failed for istate %d", 117 c->self, c->istate); 118 break; 119 } 120 } 121 static void 122 chan_ibuf_empty1(Channel *c) 123 { 124 debug("channel %d: ibuf empty", c->self); 125 if (buffer_len(&c->input)) { 126 error("channel %d: internal error: chan_ibuf_empty for non empty buffer", 127 c->self); 128 return; 129 } 130 switch (c->istate) { 131 case CHAN_INPUT_WAIT_DRAIN: 132 debug("channel %d: input drain -> wait_oclose", c->self); 133 chan_send_ieof1(c); 134 c->istate = CHAN_INPUT_WAIT_OCLOSE; 135 break; 136 default: 137 error("channel %d: internal error: chan_ibuf_empty for istate %d", 138 c->self, c->istate); 139 break; 140 } 141 } 142 static void 143 chan_rcvd_ieof1(Channel *c) 144 { 145 debug("channel %d: rcvd ieof", c->self); 146 if (c->type != SSH_CHANNEL_OPEN) { 147 debug("channel %d: non-open", c->self); 148 if (c->istate == CHAN_INPUT_OPEN) { 149 debug("channel %d: non-open: input open -> wait_oclose", c->self); 150 chan_shutdown_read(c); 151 chan_send_ieof1(c); 152 c->istate = CHAN_INPUT_WAIT_OCLOSE; 153 } else { 154 error("channel %d: istate %d != open", c->self, c->istate); 155 } 156 if (c->ostate == CHAN_OUTPUT_OPEN) { 157 debug("channel %d: non-open: output open -> closed", c->self); 158 chan_send_oclose1(c); 159 c->ostate = CHAN_OUTPUT_CLOSED; 160 } else { 161 error("channel %d: ostate %d != open", c->self, c->ostate); 162 } 163 return; 164 } 165 switch (c->ostate) { 166 case CHAN_OUTPUT_OPEN: 167 debug("channel %d: output open -> drain", c->self); 168 c->ostate = CHAN_OUTPUT_WAIT_DRAIN; 169 break; 170 case CHAN_OUTPUT_WAIT_IEOF: 171 debug("channel %d: output wait_ieof -> closed", c->self); 172 c->ostate = CHAN_OUTPUT_CLOSED; 173 break; 174 default: 175 error("channel %d: protocol error: chan_rcvd_ieof for ostate %d", 176 c->self, c->ostate); 177 break; 178 } 179 } 180 static void 181 chan_write_failed1(Channel *c) 182 { 183 debug("channel %d: write failed", c->self); 184 switch (c->ostate) { 185 case CHAN_OUTPUT_OPEN: 186 debug("channel %d: output open -> wait_ieof", c->self); 187 chan_send_oclose1(c); 188 c->ostate = CHAN_OUTPUT_WAIT_IEOF; 189 break; 190 case CHAN_OUTPUT_WAIT_DRAIN: 191 debug("channel %d: output wait_drain -> closed", c->self); 192 chan_send_oclose1(c); 193 c->ostate = CHAN_OUTPUT_CLOSED; 194 break; 195 default: 196 error("channel %d: internal error: chan_write_failed for ostate %d", 197 c->self, c->ostate); 198 break; 199 } 200 } 201 static void 202 chan_obuf_empty1(Channel *c) 203 { 204 debug("channel %d: obuf empty", c->self); 205 if (buffer_len(&c->output)) { 206 error("channel %d: internal error: chan_obuf_empty for non empty buffer", 207 c->self); 208 return; 209 } 210 switch (c->ostate) { 211 case CHAN_OUTPUT_WAIT_DRAIN: 212 debug("channel %d: output drain -> closed", c->self); 213 chan_send_oclose1(c); 214 c->ostate = CHAN_OUTPUT_CLOSED; 215 break; 216 default: 217 error("channel %d: internal error: chan_obuf_empty for ostate %d", 218 c->self, c->ostate); 219 break; 220 } 221 } 222 static void 223 chan_send_ieof1(Channel *c) 224 { 225 debug("channel %d: send ieof", c->self); 226 switch (c->istate) { 227 case CHAN_INPUT_OPEN: 228 case CHAN_INPUT_WAIT_DRAIN: 229 packet_start(SSH_MSG_CHANNEL_INPUT_EOF); 230 packet_put_int(c->remote_id); 231 packet_send(); 232 break; 233 default: 234 error("channel %d: internal error: cannot send ieof for istate %d", 235 c->self, c->istate); 236 break; 237 } 238 } 239 static void 240 chan_send_oclose1(Channel *c) 241 { 242 debug("channel %d: send oclose", c->self); 243 switch (c->ostate) { 244 case CHAN_OUTPUT_OPEN: 245 case CHAN_OUTPUT_WAIT_DRAIN: 246 chan_shutdown_write(c); 247 buffer_consume(&c->output, buffer_len(&c->output)); 248 packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE); 249 packet_put_int(c->remote_id); 250 packet_send(); 251 break; 252 default: 253 error("channel %d: internal error: cannot send oclose for ostate %d", 254 c->self, c->ostate); 255 break; 256 } 257 } 258 static void 259 chan_delete_if_full_closed1(Channel *c) 260 { 261 if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { 262 debug("channel %d: full closed", c->self); 263 channel_free(c->self); 264 } 265 } 266 267 /* 268 * the same for SSH2 269 */ 270 static void 271 chan_rcvd_oclose2(Channel *c) 272 { 273 debug("channel %d: rcvd close", c->self); 274 if (c->flags & CHAN_CLOSE_RCVD) 275 error("channel %d: protocol error: close rcvd twice", c->self); 276 c->flags |= CHAN_CLOSE_RCVD; 277 if (c->type == SSH_CHANNEL_LARVAL) { 278 /* tear down larval channels immediately */ 279 c->ostate = CHAN_OUTPUT_CLOSED; 280 c->istate = CHAN_INPUT_CLOSED; 281 return; 282 } 283 switch (c->ostate) { 284 case CHAN_OUTPUT_OPEN: 285 /* wait until a data from the channel is consumed if a CLOSE is received */ 286 debug("channel %d: output open -> drain", c->self); 287 c->ostate = CHAN_OUTPUT_WAIT_DRAIN; 288 break; 289 } 290 switch (c->istate) { 291 case CHAN_INPUT_OPEN: 292 debug("channel %d: input open -> closed", c->self); 293 chan_shutdown_read(c); 294 break; 295 case CHAN_INPUT_WAIT_DRAIN: 296 debug("channel %d: input drain -> closed", c->self); 297 chan_send_eof2(c); 298 break; 299 } 300 c->istate = CHAN_INPUT_CLOSED; 301 } 302 static void 303 chan_ibuf_empty2(Channel *c) 304 { 305 debug("channel %d: ibuf empty", c->self); 306 if (buffer_len(&c->input)) { 307 error("channel %d: internal error: chan_ibuf_empty for non empty buffer", 308 c->self); 309 return; 310 } 311 switch (c->istate) { 312 case CHAN_INPUT_WAIT_DRAIN: 313 debug("channel %d: input drain -> closed", c->self); 314 if (!(c->flags & CHAN_CLOSE_SENT)) 315 chan_send_eof2(c); 316 c->istate = CHAN_INPUT_CLOSED; 317 break; 318 default: 319 error("channel %d: internal error: chan_ibuf_empty for istate %d", 320 c->self, c->istate); 321 break; 322 } 323 } 324 static void 325 chan_rcvd_ieof2(Channel *c) 326 { 327 debug("channel %d: rcvd eof", c->self); 328 if (c->ostate == CHAN_OUTPUT_OPEN) { 329 debug("channel %d: output open -> drain", c->self); 330 c->ostate = CHAN_OUTPUT_WAIT_DRAIN; 331 } 332 } 333 static void 334 chan_write_failed2(Channel *c) 335 { 336 debug("channel %d: write failed", c->self); 337 switch (c->ostate) { 338 case CHAN_OUTPUT_OPEN: 339 debug("channel %d: output open -> closed", c->self); 340 chan_shutdown_write(c); /* ?? */ 341 c->ostate = CHAN_OUTPUT_CLOSED; 342 break; 343 case CHAN_OUTPUT_WAIT_DRAIN: 344 debug("channel %d: output drain -> closed", c->self); 345 chan_shutdown_write(c); 346 c->ostate = CHAN_OUTPUT_CLOSED; 347 break; 348 default: 349 error("channel %d: internal error: chan_write_failed for ostate %d", 350 c->self, c->ostate); 351 break; 352 } 353 } 354 static void 355 chan_obuf_empty2(Channel *c) 356 { 357 debug("channel %d: obuf empty", c->self); 358 if (buffer_len(&c->output)) { 359 error("internal error: chan_obuf_empty %d for non empty buffer", 360 c->self); 361 return; 362 } 363 switch (c->ostate) { 364 case CHAN_OUTPUT_WAIT_DRAIN: 365 debug("channel %d: output drain -> closed", c->self); 366 chan_shutdown_write(c); 367 c->ostate = CHAN_OUTPUT_CLOSED; 368 break; 369 default: 370 error("channel %d: internal error: chan_obuf_empty for ostate %d", 371 c->self, c->ostate); 372 break; 373 } 374 } 375 static void 376 chan_send_eof2(Channel *c) 377 { 378 debug("channel %d: send eof", c->self); 379 switch (c->istate) { 380 case CHAN_INPUT_WAIT_DRAIN: 381 packet_start(SSH2_MSG_CHANNEL_EOF); 382 packet_put_int(c->remote_id); 383 packet_send(); 384 break; 385 default: 386 error("channel %d: internal error: cannot send eof for istate %d", 387 c->self, c->istate); 388 break; 389 } 390 } 391 static void 392 chan_send_close2(Channel *c) 393 { 394 debug("channel %d: send close", c->self); 395 if (c->ostate != CHAN_OUTPUT_CLOSED || 396 c->istate != CHAN_INPUT_CLOSED) { 397 error("channel %d: internal error: cannot send close for istate/ostate %d/%d", 398 c->self, c->istate, c->ostate); 399 } else if (c->flags & CHAN_CLOSE_SENT) { 400 error("channel %d: internal error: already sent close", c->self); 401 } else { 402 packet_start(SSH2_MSG_CHANNEL_CLOSE); 403 packet_put_int(c->remote_id); 404 packet_send(); 405 c->flags |= CHAN_CLOSE_SENT; 406 } 407 } 408 static void 409 chan_delete_if_full_closed2(Channel *c) 410 { 411 if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { 412 if (!(c->flags & CHAN_CLOSE_SENT)) { 413 chan_send_close2(c); 414 } 415 if ((c->flags & CHAN_CLOSE_SENT) && 416 (c->flags & CHAN_CLOSE_RCVD)) { 417 debug("channel %d: full closed2", c->self); 418 channel_free(c->self); 419 } 420 } 421 } 422 423 /* shared */ 424 void 425 chan_init_iostates(Channel *c) 426 { 427 c->ostate = CHAN_OUTPUT_OPEN; 428 c->istate = CHAN_INPUT_OPEN; 429 c->flags = 0; 430 } 431 432 /* init */ 433 void 434 chan_init(void) 435 { 436 if (compat20) { 437 chan_rcvd_oclose = chan_rcvd_oclose2; 438 chan_read_failed = chan_read_failed_12; 439 chan_ibuf_empty = chan_ibuf_empty2; 440 441 chan_rcvd_ieof = chan_rcvd_ieof2; 442 chan_write_failed = chan_write_failed2; 443 chan_obuf_empty = chan_obuf_empty2; 444 445 chan_delete_if_full_closed = chan_delete_if_full_closed2; 446 } else { 447 chan_rcvd_oclose = chan_rcvd_oclose1; 448 chan_read_failed = chan_read_failed_12; 449 chan_ibuf_empty = chan_ibuf_empty1; 450 451 chan_rcvd_ieof = chan_rcvd_ieof1; 452 chan_write_failed = chan_write_failed1; 453 chan_obuf_empty = chan_obuf_empty1; 454 455 chan_delete_if_full_closed = chan_delete_if_full_closed1; 456 } 457 } 458 459 /* helper */ 460 static void 461 chan_shutdown_write(Channel *c) 462 { 463 buffer_consume(&c->output, buffer_len(&c->output)); 464 if (compat20 && c->type == SSH_CHANNEL_LARVAL) 465 return; 466 /* shutdown failure is allowed if write failed already */ 467 debug("channel %d: close_write", c->self); 468 if (c->sock != -1) { 469 if (shutdown(c->sock, SHUT_WR) < 0) 470 debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s", 471 c->self, c->sock, strerror(errno)); 472 } else { 473 if (close(c->wfd) < 0) 474 log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s", 475 c->self, c->wfd, strerror(errno)); 476 c->wfd = -1; 477 } 478 } 479 static void 480 chan_shutdown_read(Channel *c) 481 { 482 if (compat20 && c->type == SSH_CHANNEL_LARVAL) 483 return; 484 debug("channel %d: close_read", c->self); 485 if (c->sock != -1) { 486 if (shutdown(c->sock, SHUT_RD) < 0) 487 error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s", 488 c->self, c->sock, c->istate, c->ostate, strerror(errno)); 489 } else { 490 if (close(c->rfd) < 0) 491 log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s", 492 c->self, c->rfd, strerror(errno)); 493 c->rfd = -1; 494 } 495 } 496