/* $Id: ssh_channel.c,v 1.6 2001/02/11 03:35:11 tls Exp $ */ /* * Copyright (c) 2000 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 name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "sshd.h" #include "ssh_channel.h" #include "ssh_util.h" void channel_init(ssh_context_t * context) { int i; memset(context->channels, 0, sizeof(context->channels)); for (i = 0; i < MAX_CHANNEL; i++) { context->channels[i].fd_normal = -1; context->channels[i].fd_ext_stderr = -1; } return; } int create_channel(ssh_context_t * context, int channel_id, int remote_id, int window_size, int max_packet_size) { struct channel_info *chan; if (channel_id > MAX_CHANNEL) { SSH_ERROR("Channel id out of range %d > %d", channel_id, MAX_CHANNEL); return RET_FATAL; } chan = &context->channels[channel_id]; if (chan->used) { SSH_DLOG(2, ("Failed: channel exists. %d\n", channel_id)); return RET_FAIL; } chan->used = 1; chan->remote_id = remote_id; chan->fd_normal = -1; chan->fd_ext_stderr = -1; chan->is_closing = 0; chan->window_size = window_size; chan->max_packet_size = max_packet_size; return (RET_OK); } int init_fdi(ssh_context_t *context, ssh_fdinfo_t *fdi, int channel_id, int fd_type, int fd, u_int8_t msg_type) { memset(fdi, 0, sizeof(ssh_fdinfo_t)); /* This is more like channel type instead of fd_type */ switch(fd_type) { case SSH_FD_STDDATA: case SSH_FD_STDINDATA: /* * V1 STDIN/OUT/ERR data. Need room for * type + binstr length */ fdi->header_size = 1 + 4; break; /* XXX Add other types here. */ default: fdi->header_size = 0; break; } fdi->fd_type = fd_type; fdi->fd = fd; fdi->p_chan = find_channel(context, 0); fdi->xmitbuf = malloc(fdi->p_chan->max_packet_size); fdi->readbuf = fdi->xmitbuf + fdi->header_size; fdi->max_read_size = fdi->p_chan->max_packet_size - fdi->header_size; if (fdi->xmitbuf == NULL) { SSH_DLOG(1, ("Unable to allocate %d bytes for readbuf", fdi->p_chan->max_packet_size)); return (RET_FAIL); } switch(fd_type) { case SSH_FD_STDDATA: case SSH_FD_STDINDATA: fdi->xmitbuf[0] = msg_type; break; default: break; } return (RET_OK); } /* * Attach a FD to a channel. */ int chan_attach_fd(ssh_context_t * context, int fd, int type, int channel_id) { if (channel_id > MAX_CHANNEL) { SSH_ERROR("Channel id out of range %d > %d", channel_id, MAX_CHANNEL); return RET_FATAL; } if (!context->channels[channel_id].used) { SSH_ERROR("Channel not allocated. %d\n", channel_id); return RET_FATAL; } switch (type) { case FDTYPE_NORMAL: if (context->channels[channel_id].fd_normal >= 0) close(context->channels[channel_id].fd_normal); context->channels[channel_id].fd_normal = fd; break; case FDTYPE_EXT_STDERR: if (context->channels[channel_id].fd_ext_stderr >= 0) close(context->channels[channel_id].fd_ext_stderr); context->channels[channel_id].fd_ext_stderr = fd; break; } return (RET_OK); } /* * cleanup_channels: * Do any cleanup required on all channels. */ void cleanup_channels(ssh_context_t * context) { int i; for (i = 0; i < MAX_CHANNEL; i++) { /* Make sure it's been created */ if (!context->channels[i].used) continue; /*XAX free buffers in the fdinfo array?*/ if (context->channels[i].fd_normal) close(context->channels[i].fd_normal); if (context->channels[i].fd_ext_stderr) close(context->channels[i].fd_ext_stderr); } }