[BACK]Return to channel-input.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/channel-input.c, Revision 1.1

1.1     ! markus      1: /*
        !             2:  * Author: Tatu Ylonen <ylo@cs.hut.fi>
        !             3:  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
        !             4:  *                    All rights reserved
        !             5:  *
        !             6:  * As far as I am concerned, the code I have written for this software
        !             7:  * can be used freely for any purpose.  Any derived versions of this
        !             8:  * software must be clearly marked as such, and if the derived work is
        !             9:  * incompatible with the protocol description in the RFC file, it must be
        !            10:  * called by a name other than "ssh" or "Secure Shell".
        !            11:  *
        !            12:  *
        !            13:  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
        !            14:  *
        !            15:  * Redistribution and use in source and binary forms, with or without
        !            16:  * modification, are permitted provided that the following conditions
        !            17:  * are met:
        !            18:  * 1. Redistributions of source code must retain the above copyright
        !            19:  *    notice, this list of conditions and the following disclaimer.
        !            20:  * 2. Redistributions in binary form must reproduce the above copyright
        !            21:  *    notice, this list of conditions and the following disclaimer in the
        !            22:  *    documentation and/or other materials provided with the distribution.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            25:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            26:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            27:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            28:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            29:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            30:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            31:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            32:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            33:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            34:  */
        !            35:
        !            36: #include "includes.h"
        !            37: RCSID("$OpenBSD: channels.c,v 1.119 2001/05/28 23:25:24 markus Exp $");
        !            38:
        !            39: #include "ssh1.h"
        !            40: #include "ssh2.h"
        !            41: #include "packet.h"
        !            42: #include "xmalloc.h"
        !            43: #include "log.h"
        !            44: #include "channel.h"
        !            45: #include "compat.h"
        !            46:
        !            47:
        !            48: void
        !            49: channel_input_data(int type, int plen, void *ctxt)
        !            50: {
        !            51:        int id;
        !            52:        char *data;
        !            53:        u_int data_len;
        !            54:        Channel *c;
        !            55:
        !            56:        /* Get the channel number and verify it. */
        !            57:        id = packet_get_int();
        !            58:        c = channel_lookup(id);
        !            59:        if (c == NULL)
        !            60:                packet_disconnect("Received data for nonexistent channel %d.", id);
        !            61:
        !            62:        /* Ignore any data for non-open channels (might happen on close) */
        !            63:        if (c->type != SSH_CHANNEL_OPEN &&
        !            64:            c->type != SSH_CHANNEL_X11_OPEN)
        !            65:                return;
        !            66:
        !            67:        /* same for protocol 1.5 if output end is no longer open */
        !            68:        if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN)
        !            69:                return;
        !            70:
        !            71:        /* Get the data. */
        !            72:        data = packet_get_string(&data_len);
        !            73:        packet_done();
        !            74:
        !            75:        if (compat20){
        !            76:                if (data_len > c->local_maxpacket) {
        !            77:                        log("channel %d: rcvd big packet %d, maxpack %d",
        !            78:                            c->self, data_len, c->local_maxpacket);
        !            79:                }
        !            80:                if (data_len > c->local_window) {
        !            81:                        log("channel %d: rcvd too much data %d, win %d",
        !            82:                            c->self, data_len, c->local_window);
        !            83:                        xfree(data);
        !            84:                        return;
        !            85:                }
        !            86:                c->local_window -= data_len;
        !            87:        }else{
        !            88:                packet_integrity_check(plen, 4 + 4 + data_len, type);
        !            89:        }
        !            90:        buffer_append(&c->output, data, data_len);
        !            91:        xfree(data);
        !            92: }
        !            93:
        !            94: void
        !            95: channel_input_extended_data(int type, int plen, void *ctxt)
        !            96: {
        !            97:        int id;
        !            98:        int tcode;
        !            99:        char *data;
        !           100:        u_int data_len;
        !           101:        Channel *c;
        !           102:
        !           103:        /* Get the channel number and verify it. */
        !           104:        id = packet_get_int();
        !           105:        c = channel_lookup(id);
        !           106:
        !           107:        if (c == NULL)
        !           108:                packet_disconnect("Received extended_data for bad channel %d.", id);
        !           109:        if (c->type != SSH_CHANNEL_OPEN) {
        !           110:                log("channel %d: ext data for non open", id);
        !           111:                return;
        !           112:        }
        !           113:        tcode = packet_get_int();
        !           114:        if (c->efd == -1 ||
        !           115:            c->extended_usage != CHAN_EXTENDED_WRITE ||
        !           116:            tcode != SSH2_EXTENDED_DATA_STDERR) {
        !           117:                log("channel %d: bad ext data", c->self);
        !           118:                return;
        !           119:        }
        !           120:        data = packet_get_string(&data_len);
        !           121:        packet_done();
        !           122:        if (data_len > c->local_window) {
        !           123:                log("channel %d: rcvd too much extended_data %d, win %d",
        !           124:                    c->self, data_len, c->local_window);
        !           125:                xfree(data);
        !           126:                return;
        !           127:        }
        !           128:        debug2("channel %d: rcvd ext data %d", c->self, data_len);
        !           129:        c->local_window -= data_len;
        !           130:        buffer_append(&c->extended, data, data_len);
        !           131:        xfree(data);
        !           132: }
        !           133:
        !           134: void
        !           135: channel_input_ieof(int type, int plen, void *ctxt)
        !           136: {
        !           137:        int id;
        !           138:        Channel *c;
        !           139:
        !           140:        packet_integrity_check(plen, 4, type);
        !           141:
        !           142:        id = packet_get_int();
        !           143:        c = channel_lookup(id);
        !           144:        if (c == NULL)
        !           145:                packet_disconnect("Received ieof for nonexistent channel %d.", id);
        !           146:        chan_rcvd_ieof(c);
        !           147: }
        !           148:
        !           149: void
        !           150: channel_input_close(int type, int plen, void *ctxt)
        !           151: {
        !           152:        int id;
        !           153:        Channel *c;
        !           154:
        !           155:        packet_integrity_check(plen, 4, type);
        !           156:
        !           157:        id = packet_get_int();
        !           158:        c = channel_lookup(id);
        !           159:        if (c == NULL)
        !           160:                packet_disconnect("Received close for nonexistent channel %d.", id);
        !           161:
        !           162:        /*
        !           163:         * Send a confirmation that we have closed the channel and no more
        !           164:         * data is coming for it.
        !           165:         */
        !           166:        packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
        !           167:        packet_put_int(c->remote_id);
        !           168:        packet_send();
        !           169:
        !           170:        /*
        !           171:         * If the channel is in closed state, we have sent a close request,
        !           172:         * and the other side will eventually respond with a confirmation.
        !           173:         * Thus, we cannot free the channel here, because then there would be
        !           174:         * no-one to receive the confirmation.  The channel gets freed when
        !           175:         * the confirmation arrives.
        !           176:         */
        !           177:        if (c->type != SSH_CHANNEL_CLOSED) {
        !           178:                /*
        !           179:                 * Not a closed channel - mark it as draining, which will
        !           180:                 * cause it to be freed later.
        !           181:                 */
        !           182:                buffer_consume(&c->input, buffer_len(&c->input));
        !           183:                c->type = SSH_CHANNEL_OUTPUT_DRAINING;
        !           184:        }
        !           185: }
        !           186:
        !           187: /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
        !           188: void
        !           189: channel_input_oclose(int type, int plen, void *ctxt)
        !           190: {
        !           191:        int id = packet_get_int();
        !           192:        Channel *c = channel_lookup(id);
        !           193:        packet_integrity_check(plen, 4, type);
        !           194:        if (c == NULL)
        !           195:                packet_disconnect("Received oclose for nonexistent channel %d.", id);
        !           196:        chan_rcvd_oclose(c);
        !           197: }
        !           198:
        !           199: void
        !           200: channel_input_close_confirmation(int type, int plen, void *ctxt)
        !           201: {
        !           202:        int id = packet_get_int();
        !           203:        Channel *c = channel_lookup(id);
        !           204:
        !           205:        packet_done();
        !           206:        if (c == NULL)
        !           207:                packet_disconnect("Received close confirmation for "
        !           208:                    "out-of-range channel %d.", id);
        !           209:        if (c->type != SSH_CHANNEL_CLOSED)
        !           210:                packet_disconnect("Received close confirmation for "
        !           211:                    "non-closed channel %d (type %d).", id, c->type);
        !           212:        channel_free(c);
        !           213: }
        !           214:
        !           215: void
        !           216: channel_input_open_confirmation(int type, int plen, void *ctxt)
        !           217: {
        !           218:        int id, remote_id;
        !           219:        Channel *c;
        !           220:
        !           221:        if (!compat20)
        !           222:                packet_integrity_check(plen, 4 + 4, type);
        !           223:
        !           224:        id = packet_get_int();
        !           225:        c = channel_lookup(id);
        !           226:
        !           227:        if (c==NULL || c->type != SSH_CHANNEL_OPENING)
        !           228:                packet_disconnect("Received open confirmation for "
        !           229:                    "non-opening channel %d.", id);
        !           230:        remote_id = packet_get_int();
        !           231:        /* Record the remote channel number and mark that the channel is now open. */
        !           232:        c->remote_id = remote_id;
        !           233:        c->type = SSH_CHANNEL_OPEN;
        !           234:
        !           235:        if (compat20) {
        !           236:                c->remote_window = packet_get_int();
        !           237:                c->remote_maxpacket = packet_get_int();
        !           238:                packet_done();
        !           239:                if (c->cb_fn != NULL && c->cb_event == type) {
        !           240:                        debug2("callback start");
        !           241:                        c->cb_fn(c->self, c->cb_arg);
        !           242:                        debug2("callback done");
        !           243:                }
        !           244:                debug("channel %d: open confirm rwindow %d rmax %d", c->self,
        !           245:                    c->remote_window, c->remote_maxpacket);
        !           246:        }
        !           247: }
        !           248:
        !           249: char *
        !           250: reason2txt(int reason)
        !           251: {
        !           252:        switch(reason) {
        !           253:        case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED:
        !           254:                return "administratively prohibited";
        !           255:        case SSH2_OPEN_CONNECT_FAILED:
        !           256:                return "connect failed";
        !           257:        case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE:
        !           258:                return "unknown channel type";
        !           259:        case SSH2_OPEN_RESOURCE_SHORTAGE:
        !           260:                return "resource shortage";
        !           261:        }
        !           262:        return "unknown reason";
        !           263: }
        !           264:
        !           265: void
        !           266: channel_input_open_failure(int type, int plen, void *ctxt)
        !           267: {
        !           268:        int id, reason;
        !           269:        char *msg = NULL, *lang = NULL;
        !           270:        Channel *c;
        !           271:
        !           272:        if (!compat20)
        !           273:                packet_integrity_check(plen, 4, type);
        !           274:
        !           275:        id = packet_get_int();
        !           276:        c = channel_lookup(id);
        !           277:
        !           278:        if (c==NULL || c->type != SSH_CHANNEL_OPENING)
        !           279:                packet_disconnect("Received open failure for "
        !           280:                    "non-opening channel %d.", id);
        !           281:        if (compat20) {
        !           282:                reason = packet_get_int();
        !           283:                if (!(datafellows & SSH_BUG_OPENFAILURE)) {
        !           284:                        msg  = packet_get_string(NULL);
        !           285:                        lang = packet_get_string(NULL);
        !           286:                }
        !           287:                packet_done();
        !           288:                log("channel %d: open failed: %s%s%s", id,
        !           289:                    reason2txt(reason), msg ? ": ": "", msg ? msg : "");
        !           290:                if (msg != NULL)
        !           291:                        xfree(msg);
        !           292:                if (lang != NULL)
        !           293:                        xfree(lang);
        !           294:        }
        !           295:        /* Free the channel.  This will also close the socket. */
        !           296:        channel_free(c);
        !           297: }
        !           298:
        !           299: void
        !           300: channel_input_channel_request(int type, int plen, void *ctxt)
        !           301: {
        !           302:        int id;
        !           303:        Channel *c;
        !           304:
        !           305:        id = packet_get_int();
        !           306:        c = channel_lookup(id);
        !           307:
        !           308:        if (c == NULL ||
        !           309:            (c->type != SSH_CHANNEL_OPEN && c->type != SSH_CHANNEL_LARVAL))
        !           310:                packet_disconnect("Received request for "
        !           311:                    "non-open channel %d.", id);
        !           312:        if (c->cb_fn != NULL && c->cb_event == type) {
        !           313:                debug2("callback start");
        !           314:                c->cb_fn(c->self, c->cb_arg);
        !           315:                debug2("callback done");
        !           316:        } else {
        !           317:                char *service = packet_get_string(NULL);
        !           318:                debug("channel %d: rcvd request for %s", c->self, service);
        !           319:                debug("cb_fn %p cb_event %d", c->cb_fn , c->cb_event);
        !           320:                xfree(service);
        !           321:        }
        !           322: }
        !           323:
        !           324: void
        !           325: channel_input_window_adjust(int type, int plen, void *ctxt)
        !           326: {
        !           327:        Channel *c;
        !           328:        int id, adjust;
        !           329:
        !           330:        if (!compat20)
        !           331:                return;
        !           332:
        !           333:        /* Get the channel number and verify it. */
        !           334:        id = packet_get_int();
        !           335:        c = channel_lookup(id);
        !           336:
        !           337:        if (c == NULL || c->type != SSH_CHANNEL_OPEN) {
        !           338:                log("Received window adjust for "
        !           339:                    "non-open channel %d.", id);
        !           340:                return;
        !           341:        }
        !           342:        adjust = packet_get_int();
        !           343:        packet_done();
        !           344:        debug2("channel %d: rcvd adjust %d", id, adjust);
        !           345:        c->remote_window += adjust;
        !           346: }
        !           347:
        !           348: void
        !           349: channel_input_port_open(int type, int plen, void *ctxt)
        !           350: {
        !           351:        Channel *c = NULL;
        !           352:        u_short host_port;
        !           353:        char *host, *originator_string;
        !           354:        int remote_id, sock = -1;
        !           355:
        !           356:        remote_id = packet_get_int();
        !           357:        host = packet_get_string(NULL);
        !           358:        host_port = packet_get_int();
        !           359:
        !           360:        if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
        !           361:                originator_string = packet_get_string(NULL);
        !           362:        } else {
        !           363:                originator_string = xstrdup("unknown (remote did not supply name)");
        !           364:        }
        !           365:        packet_done();
        !           366:        sock = channel_connect_to(host, host_port);
        !           367:        if (sock != -1) {
        !           368:                c = channel_new("connected socket",
        !           369:                    SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0,
        !           370:                    originator_string, 1);
        !           371:                if (c == NULL) {
        !           372:                        error("channel_input_port_open: channel_new failed");
        !           373:                        close(sock);
        !           374:                } else {
        !           375:                        c->remote_id = remote_id;
        !           376:                }
        !           377:        }
        !           378:        if (c == NULL) {
        !           379:                packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
        !           380:                packet_put_int(remote_id);
        !           381:                packet_send();
        !           382:        }
        !           383:        xfree(host);
        !           384: }