/* $Id: ssh_v1_iactive_server.c,v 1.2 2001/02/11 03:35:19 tls Exp $ */ /* * Copyright 1999 RedBack Networks, Incorporated. * All rights reserved. * * This software is not in the public domain. It is distributed * under the terms of the license in the file LICENSE in the * same directory as this file. If you have received a copy of this * software without the LICENSE file (which means that whoever gave * you this software violated its license) you may obtain a copy from * http://www.panix.com/~tls/LICENSE.txt */ /* * Copyright (c) 2000 Andrew Brown and Eric Haszlakiewicz. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The names of the authors may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "options.h" #include "sshd.h" #include "ssh_buffer.h" #include "ssh_channel.h" #include "ssh_util.h" #include "ssh_v1_messages.h" #include "ssh_v1_proto.h" #include "ssh_transport.h" #include "ssh_types.h" /* * doInteractive: Interactive session state. * * Returns: * RET_OK Normal processing, continue as usual * RET_FAIL Client sent something bad, we've sent a disconnect * message, kill childen and exit. * RET_SKIP_STATE Client went away, cleanup and exit. * RET_FATAL Something is really screwy, exit right away. * * Assume: buf is discarded after we return. * */ int ssh_v1_iactive_server(ssh_context_t * context, struct ssh_buf * buf, size_t size, int msg_type) { struct ssh_event ev; ev.event_type = SSH_EVENT_NONE; switch (msg_type) { case SSH_V1_MSG_PORT_OPEN: case SSH_V1_MSG_CHANNEL_OPEN_CONFIRMATION: case SSH_V1_MSG_CHANNEL_OPEN_FAILURE: case SSH_V1_MSG_CHANNEL_DATA: case SSH_V1_MSG_CHANNEL_CLOSE: case SSH_V1_MSG_CHANNEL_CLOSE_CONFIRMATION: /* unimplemented. */ EVT_V1_DEBUG(ev, context, "Unimplemented."); EVT_SEND(&ev, context); EVT_V1_FAILURE(ev); EVT_SEND(&ev, context); break; case SSH_V1_CMSG_STDIN_DATA: { u_int8_t *indata; u_int32_t dlen, wlen; indata = NULL; buf_get_binstr(buf, &indata, &dlen); /* * If the child is gone we will have already sent its * exitstatus from the SIGCHLD handler. If the child exit * manages to sneak in between this check and the write * we will get a SIGPIPE. That's OK, we just need a * handler that ignores SIGPIPE or optionally logs it. */ if (context->v1_ctx.child_gone == 0) { wlen = write(context->channels[0].fd_normal, indata, dlen); if (wlen != dlen) { SSH_DLOG(3, ("write to child failed: %d/%d errno %d\n", wlen, dlen, errno)); EVT_V1_FAILURE(ev); EVT_SEND(&ev, context); } } free(indata); /* XXX inefficient */ break; } case SSH_V1_CMSG_EOF: /* * All done with input. Closing stdin should cause * the program to exit. */ SSH_DLOG(4, ("Client sent EOF, closing child stdin.\n")); /* * We MUST use shutdown here because the sendThread has * a copy of the file descriptor so our calling close is * not sufficient to cause the child to get EOF. close * works on per-process file descriptors, while shutdown * acts on the socket which is shared. */ shutdown(context->channels[0].fd_normal, SHUT_WR); context->channels[0].fd_normal = -1; break; case SSH_V1_CMSG_WINDOW_SIZE: { u_int32_t y_row, x_col, x_pix, y_pix; if (buf_get_int32(buf, &y_row) || buf_get_int32(buf, &x_col) || buf_get_int32(buf, &x_pix) || buf_get_int32(buf, &y_pix)) { EVT_V1_DISCONNECT(ev, context, "Short packet"); EVT_SEND(&ev, context); return (RET_FAIL); } context->win.ws_row = y_row; context->win.ws_col = x_col; context->win.ws_xpixel = x_pix; context->win.ws_ypixel = y_pix; if (ssh_sys_set_tty_size(find_channel(context, 0)->fd_normal, &context->win) == -1) { EVT_V1_DISCONNECT(ev, context, "Window change failed"); EVT_SEND(&ev, context); return (RET_FAIL); } break; } default: SSH_DLOG(2, ("Client sent unknown packet type: %d\n", msg_type)); EVT_V1_DISCONNECT(ev, context, "Unkown packet type"); EVT_SEND(&ev, context); return (RET_FAIL); break; } return (RET_OK); } int ssh_v1_exiting_server(ssh_context_t *context, struct ssh_buf *buf, size_t size, int msg_type) { static int ntries = 0; struct ssh_event ev; /* * Wait for EXIT_CONFIRMATION. There might be other packets * so just keep reading until read_packet returns an error. */ if (msg_type == SSH_V1_CMSG_EXIT_CONFIRMATION) { SSH_DLOG(3, ("Received EXIT_CONFIRMATION\n")); return (RET_NEXT_STATE); } else { /* This is likely to be just data still in the pipe */ SSH_DLOG(3, ("Weird exit confirmation: %d\n", msg_type)); ntries++; if (ntries > 50) { SSH_DLOG(1, ("Too many non-EXIT_CONFIRMATION packets")); EVT_V1_DISCONNECT(ev, context, "Expected EXIT_CONFIRMATION"); EVT_SEND(&ev, context); return (RET_FAIL); } return (RET_OK); } }