コード例 #1
0
ファイル: packet.c プロジェクト: Aahanbhatt/robomongo
/*
 * packet_x11_open
 *
 * Accept a forwarded X11 connection
 */
static inline int
packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
                unsigned long datalen,
                packet_x11_open_state_t *x11open_state)
{
    int failure_code = SSH_OPEN_CONNECT_FAILED;
    /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
    unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1);
    unsigned char *p;
    LIBSSH2_CHANNEL *channel = x11open_state->channel;
    int rc;

    (void) datalen;

    if (x11open_state->state == libssh2_NB_state_idle) {
        unsigned char *s = data + (sizeof("x11") - 1) + 5;
        x11open_state->sender_channel = _libssh2_ntohu32(s);
        s += 4;
        x11open_state->initial_window_size = _libssh2_ntohu32(s);
        s += 4;
        x11open_state->packet_size = _libssh2_ntohu32(s);
        s += 4;
        x11open_state->shost_len = _libssh2_ntohu32(s);
        s += 4;
        x11open_state->shost = s;
        s += x11open_state->shost_len;
        x11open_state->sport = _libssh2_ntohu32(s);

        _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                       "X11 Connection Received from %s:%ld on channel %lu",
                       x11open_state->shost, x11open_state->sport,
                       x11open_state->sender_channel);

        x11open_state->state = libssh2_NB_state_allocated;
    }

    if (session->x11) {
        if (x11open_state->state == libssh2_NB_state_allocated) {
            channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL));
            if (!channel) {
                _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                               "allocate a channel for new connection");
                failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
                goto x11_exit;
            }

            channel->session = session;
            channel->channel_type_len = sizeof("x11") - 1;
            channel->channel_type = LIBSSH2_ALLOC(session,
                                                  channel->channel_type_len +
                                                  1);
            if (!channel->channel_type) {
                _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                               "allocate a channel for new connection");
                LIBSSH2_FREE(session, channel);
                failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
                goto x11_exit;
            }
            memcpy(channel->channel_type, "x11",
                   channel->channel_type_len + 1);

            channel->remote.id = x11open_state->sender_channel;
            channel->remote.window_size_initial =
                LIBSSH2_CHANNEL_WINDOW_DEFAULT;
            channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
            channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT;

            channel->local.id = _libssh2_channel_nextid(session);
            channel->local.window_size_initial =
                x11open_state->initial_window_size;
            channel->local.window_size = x11open_state->initial_window_size;
            channel->local.packet_size = x11open_state->packet_size;

            _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                           "X11 Connection established: channel %lu/%lu "
                           "win %lu/%lu packet %lu/%lu",
                           channel->local.id, channel->remote.id,
                           channel->local.window_size,
                           channel->remote.window_size,
                           channel->local.packet_size,
                           channel->remote.packet_size);
            p = x11open_state->packet;
            *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
            _libssh2_store_u32(&p, channel->remote.id);
            _libssh2_store_u32(&p, channel->local.id);
            _libssh2_store_u32(&p, channel->remote.window_size_initial);
            _libssh2_store_u32(&p, channel->remote.packet_size);

            x11open_state->state = libssh2_NB_state_created;
        }

        if (x11open_state->state == libssh2_NB_state_created) {
            rc = _libssh2_transport_send(session, x11open_state->packet, 17,
                                         NULL, 0);
            if (rc == LIBSSH2_ERROR_EAGAIN) {
                return rc;
            } else if (rc) {
                x11open_state->state = libssh2_NB_state_idle;
                return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                                      "Unable to send channel open "
                                      "confirmation");
            }

            /* Link the channel into the session */
            _libssh2_list_add(&session->channels, &channel->node);

            /*
             * Pass control to the callback, they may turn right around and
             * free the channel, or actually use it
             */
            LIBSSH2_X11_OPEN(channel, (char *)x11open_state->shost,
                             x11open_state->sport);

            x11open_state->state = libssh2_NB_state_idle;
            return 0;
        }
    }
    else
        failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
    /* fall-trough */
  x11_exit:
    p = x11open_state->packet;
    *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
    _libssh2_store_u32(&p, x11open_state->sender_channel);
    _libssh2_store_u32(&p, failure_code);
    _libssh2_store_str(&p, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1);
    _libssh2_htonu32(p, 0);

    rc = _libssh2_transport_send(session, x11open_state->packet, packet_len,
                                 NULL, 0);
    if (rc == LIBSSH2_ERROR_EAGAIN) {
        return rc;
    } else if (rc) {
        x11open_state->state = libssh2_NB_state_idle;
        return _libssh2_error(session, rc, "Unable to send open failure");
    }
    x11open_state->state = libssh2_NB_state_idle;
    return 0;
}
コード例 #2
0
ファイル: packet.c プロジェクト: Aahanbhatt/robomongo
/*
 * _libssh2_packet_add
 *
 * Create a new packet and attach it to the brigade. Called from the transport
 * layer when it has received a packet.
 *
 * The input pointer 'data' is pointing to allocated data that this function
 * is asked to deal with so on failure OR success, it must be freed fine.
 * The only exception is when the return code is LIBSSH2_ERROR_EAGAIN.
 *
 * This function will always be called with 'datalen' greater than zero.
 */
int
_libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
                    size_t datalen, int macstate)
{
    int rc = 0;
    char *message=NULL;
    char *language=NULL;
    size_t message_len=0;
    size_t language_len=0;
    LIBSSH2_CHANNEL *channelp = NULL;
    size_t data_head = 0;
    unsigned char msg = data[0];

    switch(session->packAdd_state) {
    case libssh2_NB_state_idle:
        _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
                       "Packet type %d received, length=%d",
                       (int) msg, (int) datalen);

        if ((macstate == LIBSSH2_MAC_INVALID) &&
            (!session->macerror ||
             LIBSSH2_MACERROR(session, (char *) data, datalen))) {
            /* Bad MAC input, but no callback set or non-zero return from the
               callback */

            LIBSSH2_FREE(session, data);
            return _libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
                                  "Invalid MAC received");
        }
        session->packAdd_state = libssh2_NB_state_allocated;
        break;
    case libssh2_NB_state_jump1:
        goto libssh2_packet_add_jump_point1;
    case libssh2_NB_state_jump2:
        goto libssh2_packet_add_jump_point2;
    case libssh2_NB_state_jump3:
        goto libssh2_packet_add_jump_point3;
    case libssh2_NB_state_jump4:
        goto libssh2_packet_add_jump_point4;
    case libssh2_NB_state_jump5:
        goto libssh2_packet_add_jump_point5;
    default: /* nothing to do */
        break;
    }

    if (session->packAdd_state == libssh2_NB_state_allocated) {
        /* A couple exceptions to the packet adding rule: */
        switch (msg) {

            /*
              byte      SSH_MSG_DISCONNECT
              uint32    reason code
              string    description in ISO-10646 UTF-8 encoding [RFC3629]
              string    language tag [RFC3066]
            */

        case SSH_MSG_DISCONNECT:
            if(datalen >= 5) {
                size_t reason = _libssh2_ntohu32(data + 1);

                if(datalen >= 9) {
                    message_len = _libssh2_ntohu32(data + 5);

                    if(message_len < datalen-13) {
                        /* 9 = packet_type(1) + reason(4) + message_len(4) */
                        message = (char *) data + 9;

                        language_len = _libssh2_ntohu32(data + 9 + message_len);
                        language = (char *) data + 9 + message_len + 4;

                        if(language_len > (datalen-13-message_len)) {
                            /* bad input, clear info */
                            language = message = NULL;
                            language_len = message_len = 0;
                        }
                    }
                    else
                        /* bad size, clear it */
                        message_len=0;
                }
                if (session->ssh_msg_disconnect) {
                    LIBSSH2_DISCONNECT(session, reason, message,
                                       message_len, language, language_len);
                }
                _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
                               "Disconnect(%d): %s(%s)", reason,
                               message, language);
            }

            LIBSSH2_FREE(session, data);
            session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
            session->packAdd_state = libssh2_NB_state_idle;
            return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
                                  "socket disconnect");
            /*
              byte      SSH_MSG_IGNORE
              string    data
            */

        case SSH_MSG_IGNORE:
            if (datalen >= 2) {
                if (session->ssh_msg_ignore) {
                    LIBSSH2_IGNORE(session, (char *) data + 1, datalen - 1);
                }
            } else if (session->ssh_msg_ignore) {
                LIBSSH2_IGNORE(session, "", 0);
            }
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;

            /*
              byte      SSH_MSG_DEBUG
              boolean   always_display
              string    message in ISO-10646 UTF-8 encoding [RFC3629]
              string    language tag [RFC3066]
            */

        case SSH_MSG_DEBUG:
            if(datalen >= 2) {
                int always_display= data[1];

                if(datalen >= 6) {
                    message_len = _libssh2_ntohu32(data + 2);

                    if(message_len <= (datalen - 10)) {
                        /* 6 = packet_type(1) + display(1) + message_len(4) */
                        message = (char *) data + 6;
                        language_len = _libssh2_ntohu32(data + 6 + message_len);

                        if(language_len <= (datalen - 10 - message_len))
                            language = (char *) data + 10 + message_len;
                    }
                }

                if (session->ssh_msg_debug) {
                    LIBSSH2_DEBUG(session, always_display, message,
                                  message_len, language, language_len);
                }
            }
            /*
             * _libssh2_debug will actually truncate this for us so
             * that it's not an inordinate about of data
             */
            _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
                           "Debug Packet: %s", message);
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;

            /*
              byte      SSH_MSG_GLOBAL_REQUEST
              string    request name in US-ASCII only
              boolean   want reply
              ....      request-specific data follows
            */

        case SSH_MSG_GLOBAL_REQUEST:
            if(datalen >= 5) {
                uint32_t len =0;
                unsigned char want_reply=0;
                len = _libssh2_ntohu32(data + 1);
                if(datalen >= (6 + len)) {
                    want_reply = data[5 + len];
                    _libssh2_debug(session,
                                   LIBSSH2_TRACE_CONN,
                                   "Received global request type %.*s (wr %X)",
                                   len, data + 5, want_reply);
                }


                if (want_reply) {
                    static const unsigned char packet =
                        SSH_MSG_REQUEST_FAILURE;
                  libssh2_packet_add_jump_point5:
                    session->packAdd_state = libssh2_NB_state_jump5;
                    rc = _libssh2_transport_send(session, &packet, 1, NULL, 0);
                    if (rc == LIBSSH2_ERROR_EAGAIN)
                        return rc;
                }
            }
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;

            /*
              byte      SSH_MSG_CHANNEL_EXTENDED_DATA
              uint32    recipient channel
              uint32    data_type_code
              string    data
            */

        case SSH_MSG_CHANNEL_EXTENDED_DATA:
            /* streamid(4) */
            data_head += 4;

            /* fall-through */

            /*
              byte      SSH_MSG_CHANNEL_DATA
              uint32    recipient channel
              string    data
            */

        case SSH_MSG_CHANNEL_DATA:
            /* packet_type(1) + channelno(4) + datalen(4) */
            data_head += 9;

            if(datalen >= data_head)
                channelp =
                    _libssh2_channel_locate(session,
                                            _libssh2_ntohu32(data + 1));

            if (!channelp) {
                _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN,
                               "Packet received for unknown channel");
                LIBSSH2_FREE(session, data);
                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }
#ifdef LIBSSH2DEBUG
            {
                uint32_t stream_id = 0;
                if (msg == SSH_MSG_CHANNEL_EXTENDED_DATA)
                    stream_id = _libssh2_ntohu32(data + 5);

                _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                               "%d bytes packet_add() for %lu/%lu/%lu",
                               (int) (datalen - data_head),
                               channelp->local.id,
                               channelp->remote.id,
                               stream_id);
            }
#endif
            if ((channelp->remote.extended_data_ignore_mode ==
                 LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) &&
                (msg == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
                /* Pretend we didn't receive this */
                LIBSSH2_FREE(session, data);

                _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                               "Ignoring extended data and refunding %d bytes",
                               (int) (datalen - 13));
                if (channelp->read_avail + datalen - data_head >=
                    channelp->remote.window_size)
                    datalen = channelp->remote.window_size -
                        channelp->read_avail + data_head;

                channelp->remote.window_size -= datalen - data_head;
                _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                               "shrinking window size by %lu bytes to %lu, read_avail %lu",
                               datalen - data_head,
                               channelp->remote.window_size,
                               channelp->read_avail);

                session->packAdd_channelp = channelp;

                /* Adjust the window based on the block we just freed */
              libssh2_packet_add_jump_point1:
                session->packAdd_state = libssh2_NB_state_jump1;
                rc = _libssh2_channel_receive_window_adjust(session->
                                                            packAdd_channelp,
                                                            datalen - 13,
                                                            1, NULL);
                if (rc == LIBSSH2_ERROR_EAGAIN)
                    return rc;

                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }

            /*
             * REMEMBER! remote means remote as source of data,
             * NOT remote window!
             */
            if (channelp->remote.packet_size < (datalen - data_head)) {
                /*
                 * Spec says we MAY ignore bytes sent beyond
                 * packet_size
                 */
                _libssh2_error(session,
                               LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
                               "Packet contains more data than we offered"
                               " to receive, truncating");
                datalen = channelp->remote.packet_size + data_head;
            }
            if (channelp->remote.window_size <= channelp->read_avail) {
                /*
                 * Spec says we MAY ignore bytes sent beyond
                 * window_size
                 */
                _libssh2_error(session,
                               LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
                               "The current receive window is full,"
                               " data ignored");
                LIBSSH2_FREE(session, data);
                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }
            /* Reset EOF status */
            channelp->remote.eof = 0;

            if (channelp->read_avail + datalen - data_head >
                channelp->remote.window_size) {
                _libssh2_error(session,
                               LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
                               "Remote sent more data than current "
                               "window allows, truncating");
                datalen = channelp->remote.window_size -
                    channelp->read_avail + data_head;
            }

            /* Update the read_avail counter. The window size will be
             * updated once the data is actually read from the queue
             * from an upper layer */
            channelp->read_avail += datalen - data_head;

            _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                           "increasing read_avail by %lu bytes to %lu/%lu",
                           (long)(datalen - data_head),
                           (long)channelp->read_avail,
                           (long)channelp->remote.window_size);

            break;

            /*
              byte      SSH_MSG_CHANNEL_EOF
              uint32    recipient channel
            */

        case SSH_MSG_CHANNEL_EOF:
            if(datalen >= 5)
                channelp =
                    _libssh2_channel_locate(session,
                                            _libssh2_ntohu32(data + 1));
            if (!channelp)
                /* We may have freed already, just quietly ignore this... */
                ;
            else {
                _libssh2_debug(session,
                               LIBSSH2_TRACE_CONN,
                               "EOF received for channel %lu/%lu",
                               channelp->local.id,
                               channelp->remote.id);
                channelp->remote.eof = 1;
            }
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;

            /*
              byte      SSH_MSG_CHANNEL_REQUEST
              uint32    recipient channel
              string    request type in US-ASCII characters only
              boolean   want reply
              ....      type-specific data follows
            */

        case SSH_MSG_CHANNEL_REQUEST:
            if(datalen >= 9) {
                uint32_t channel = _libssh2_ntohu32(data + 1);
                uint32_t len = _libssh2_ntohu32(data + 5);
                unsigned char want_reply = 1;

                if(len < (datalen - 10))
                    want_reply = data[9 + len];

                _libssh2_debug(session,
                               LIBSSH2_TRACE_CONN,
                               "Channel %d received request type %.*s (wr %X)",
                               channel, len, data + 9, want_reply);

                if (len == sizeof("exit-status") - 1
                    && !memcmp("exit-status", data + 9,
                               sizeof("exit-status") - 1)) {

                    /* we've got "exit-status" packet. Set the session value */
                    if(datalen >= 20)
                        channelp =
                            _libssh2_channel_locate(session, channel);

                    if (channelp) {
                        channelp->exit_status =
                            _libssh2_ntohu32(data + 9 + sizeof("exit-status"));
                        _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                                       "Exit status %lu received for "
                                       "channel %lu/%lu",
                                       channelp->exit_status,
                                       channelp->local.id,
                                       channelp->remote.id);
                    }

                }
                else if (len == sizeof("exit-signal") - 1
                         && !memcmp("exit-signal", data + 9,
                                    sizeof("exit-signal") - 1)) {
                    /* command terminated due to signal */
                    if(datalen >= 20)
                        channelp = _libssh2_channel_locate(session, channel);

                    if (channelp) {
                        /* set signal name (without SIG prefix) */
                        uint32_t namelen =
                            _libssh2_ntohu32(data + 9 + sizeof("exit-signal"));
                        channelp->exit_signal =
                            LIBSSH2_ALLOC(session, namelen + 1);
                        if (!channelp->exit_signal)
                            rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                                "memory for signal name");
                        else {
                            memcpy(channelp->exit_signal,
                                   data + 13 + sizeof("exit_signal"), namelen);
                            channelp->exit_signal[namelen] = '\0';
                            /* TODO: save error message and language tag */
                            _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                                           "Exit signal %s received for "
                                           "channel %lu/%lu",
                                           channelp->exit_signal,
                                           channelp->local.id,
                                           channelp->remote.id);
                        }
                    }
                }


                if (want_reply) {
                    unsigned char packet[5];
                  libssh2_packet_add_jump_point4:
                    session->packAdd_state = libssh2_NB_state_jump4;
                    packet[0] = SSH_MSG_CHANNEL_FAILURE;
                    memcpy(&packet[1], data+1, 4);
                    rc = _libssh2_transport_send(session, packet, 5, NULL, 0);
                    if (rc == LIBSSH2_ERROR_EAGAIN)
                        return rc;
                }
            }
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return rc;

            /*
              byte      SSH_MSG_CHANNEL_CLOSE
              uint32    recipient channel
            */

        case SSH_MSG_CHANNEL_CLOSE:
            if(datalen >= 5)
                channelp =
                    _libssh2_channel_locate(session,
                                            _libssh2_ntohu32(data + 1));
            if (!channelp) {
                /* We may have freed already, just quietly ignore this... */
                LIBSSH2_FREE(session, data);
                session->packAdd_state = libssh2_NB_state_idle;
                return 0;
            }
            _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                           "Close received for channel %lu/%lu",
                           channelp->local.id,
                           channelp->remote.id);

            channelp->remote.close = 1;
            channelp->remote.eof = 1;

            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;

            /*
              byte      SSH_MSG_CHANNEL_OPEN
              string    "session"
              uint32    sender channel
              uint32    initial window size
              uint32    maximum packet size
            */

        case SSH_MSG_CHANNEL_OPEN:
            if(datalen < 17)
                ;
            else if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
                     ((sizeof("forwarded-tcpip") - 1) ==
                      _libssh2_ntohu32(data + 1))
                     &&
                     (memcmp(data + 5, "forwarded-tcpip",
                             sizeof("forwarded-tcpip") - 1) == 0)) {

                /* init the state struct */
                memset(&session->packAdd_Qlstn_state, 0,
                       sizeof(session->packAdd_Qlstn_state));

              libssh2_packet_add_jump_point2:
                session->packAdd_state = libssh2_NB_state_jump2;
                rc = packet_queue_listener(session, data, datalen,
                                           &session->packAdd_Qlstn_state);
            }
            else if ((datalen >= (sizeof("x11") + 4)) &&
                     ((sizeof("x11") - 1) == _libssh2_ntohu32(data + 1)) &&
                     (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {

                /* init the state struct */
                memset(&session->packAdd_x11open_state, 0,
                       sizeof(session->packAdd_x11open_state));

              libssh2_packet_add_jump_point3:
                session->packAdd_state = libssh2_NB_state_jump3;
                rc = packet_x11_open(session, data, datalen,
                                     &session->packAdd_x11open_state);
            }
            if (rc == LIBSSH2_ERROR_EAGAIN)
                return rc;

            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return rc;

            /*
              byte      SSH_MSG_CHANNEL_WINDOW_ADJUST
              uint32    recipient channel
              uint32    bytes to add
            */
        case SSH_MSG_CHANNEL_WINDOW_ADJUST:
            if(datalen < 9)
                ;
            else {
                uint32_t bytestoadd = _libssh2_ntohu32(data + 5);
                channelp =
                    _libssh2_channel_locate(session,
                                            _libssh2_ntohu32(data + 1));
                if(channelp) {
                    channelp->local.window_size += bytestoadd;

                    _libssh2_debug(session, LIBSSH2_TRACE_CONN,
                                   "Window adjust for channel %lu/%lu, "
                                   "adding %lu bytes, new window_size=%lu",
                                   channelp->local.id,
                                   channelp->remote.id,
                                   bytestoadd,
                                   channelp->local.window_size);
                }
            }
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return 0;
        default:
            break;
        }

        session->packAdd_state = libssh2_NB_state_sent;
    }

    if (session->packAdd_state == libssh2_NB_state_sent) {
        LIBSSH2_PACKET *packetp =
            LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
        if (!packetp) {
            _libssh2_debug(session, LIBSSH2_ERROR_ALLOC,
                           "memory for packet");
            LIBSSH2_FREE(session, data);
            session->packAdd_state = libssh2_NB_state_idle;
            return LIBSSH2_ERROR_ALLOC;
        }
        packetp->data = data;
        packetp->data_len = datalen;
        packetp->data_head = data_head;

        _libssh2_list_add(&session->packets, &packetp->node);

        session->packAdd_state = libssh2_NB_state_sent1;
    }

    if ((msg == SSH_MSG_KEXINIT &&
         !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) ||
        (session->packAdd_state == libssh2_NB_state_sent2)) {
        if (session->packAdd_state == libssh2_NB_state_sent1) {
            /*
             * Remote wants new keys
             * Well, it's already in the brigade,
             * let's just call back into ourselves
             */
            _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Renegotiating Keys");

            session->packAdd_state = libssh2_NB_state_sent2;
        }

        /*
         * The KEXINIT message has been added to the queue.  The packAdd and
         * readPack states need to be reset because _libssh2_kex_exchange
         * (eventually) calls upon _libssh2_transport_read to read the rest of
         * the key exchange conversation.
         */
        session->readPack_state = libssh2_NB_state_idle;
        session->packet.total_num = 0;
        session->packAdd_state = libssh2_NB_state_idle;
        session->fullpacket_state = libssh2_NB_state_idle;

        memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t));

        /*
         * If there was a key reexchange failure, let's just hope we didn't
         * send NEWKEYS yet, otherwise remote will drop us like a rock
         */
        rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state);
        if (rc == LIBSSH2_ERROR_EAGAIN)
            return rc;
    }

    session->packAdd_state = libssh2_NB_state_idle;
    return 0;
}
コード例 #3
0
ファイル: agent.c プロジェクト: elitau/MacSleep
static int
agent_list_identities(LIBSSH2_AGENT *agent)
{
    agent_transaction_ctx_t transctx = &agent->transctx;
    ssize_t len, num_identities;
    unsigned char *s;
    int rc;

    /* Create a request to list identities */
    if (transctx->state == agent_NB_state_init) {
      unsigned char c = SSH2_AGENTC_REQUEST_IDENTITIES;
      transctx->request = &c;
      transctx->request_len = 1;
      transctx->state = agent_NB_state_request_created;
    }

    /* Make sure to be re-called as a result of EAGAIN. */
    if (*transctx->request != SSH2_AGENTC_REQUEST_IDENTITIES)
        return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE,
                              "illegal agent request");

    if (!agent->ops)
        /* if no agent has been connected, bail out */
        return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE,
                              "agent not connected");

    rc = agent->ops->transact(agent, transctx);
    if (rc) {
        goto error;
    }
    transctx->request = NULL;

    len = transctx->response_len;
    s = transctx->response;
    len--;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    if (*s != SSH2_AGENT_IDENTITIES_ANSWER) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    s++;

    /* Read the length of identities */
    len -= 4;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    num_identities = _libssh2_ntohu32(s);
    s += 4;

    while (num_identities--) {
        struct agent_publickey *identity;
        ssize_t comment_len;

        identity = LIBSSH2_ALLOC(agent->session, sizeof *identity);
        if (!identity) {
            rc = LIBSSH2_ERROR_ALLOC;
            goto error;
        }

        /* Read the length of the blob */
        len -= 4;
        if (len < 0) {
            rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
            goto error;
        }
        identity->external.blob_len = _libssh2_ntohu32(s);
        s += 4;

        /* Read the blob */
        len -= identity->external.blob_len;
        if (len < 0) {
            rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
            goto error;
        }
        identity->external.blob = LIBSSH2_ALLOC(agent->session,
                                                identity->external.blob_len);
        if (!identity->external.blob) {
            rc = LIBSSH2_ERROR_ALLOC;
            goto error;
        }
        memcpy(identity->external.blob, s, identity->external.blob_len);
        s += identity->external.blob_len;

        /* Read the length of the comment */
        len -= 4;
        if (len < 0) {
            rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
            goto error;
        }
        comment_len = _libssh2_ntohu32(s);
        s += 4;

        /* Read the comment */
        len -= comment_len;
        if (len < 0) {
            rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
            goto error;
        }
        identity->external.comment = LIBSSH2_ALLOC(agent->session,
                                                   comment_len + 1);
        if (!identity->external.comment) {
            rc = LIBSSH2_ERROR_ALLOC;
            goto error;
        }
        identity->external.comment[comment_len] = '\0';
        memcpy(identity->external.comment, s, comment_len);
        s += comment_len;

        _libssh2_list_add(&agent->head, &identity->node);
    }
 error:
    LIBSSH2_FREE(agent->session, transctx->response);
    transctx->response = NULL;

    return _libssh2_error(agent->session, rc,
                          "agent list id failed");
}
コード例 #4
0
ファイル: agent.c プロジェクト: elitau/MacSleep
static int
agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
           const unsigned char *data, size_t data_len, void **abstract)
{
    LIBSSH2_AGENT *agent = (LIBSSH2_AGENT *) (*abstract);
    agent_transaction_ctx_t transctx = &agent->transctx;
    struct agent_publickey *identity = agent->identity;
    ssize_t len = 1 + 4 + identity->external.blob_len + 4 + data_len + 4;
    ssize_t method_len;
    unsigned char *s;
    int rc;

    /* Create a request to sign the data */
    if (transctx->state == agent_NB_state_init) {
        s = transctx->request = LIBSSH2_ALLOC(session, len);
        if (!transctx->request)
            return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                  "out of memory");

        *s++ = SSH2_AGENTC_SIGN_REQUEST;
        /* key blob */
        _libssh2_store_str(&s, (const char *)identity->external.blob,
                           identity->external.blob_len);
        /* data */
        _libssh2_store_str(&s, (const char *)data, data_len);

        /* flags */
        _libssh2_store_u32(&s, 0);

        transctx->request_len = s - transctx->request;
        transctx->state = agent_NB_state_request_created;
    }

    /* Make sure to be re-called as a result of EAGAIN. */
    if (*transctx->request != SSH2_AGENTC_SIGN_REQUEST)
        return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE,
                              "illegal request");

    if (!agent->ops)
        /* if no agent has been connected, bail out */
        return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE,
                              "agent not connected");

    rc = agent->ops->transact(agent, transctx);
    if (rc) {
        goto error;
    }
    LIBSSH2_FREE(session, transctx->request);
    transctx->request = NULL;

    len = transctx->response_len;
    s = transctx->response;
    len--;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    if (*s != SSH2_AGENT_SIGN_RESPONSE) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    s++;

    /* Skip the entire length of the signature */
    len -= 4;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    s += 4;

    /* Skip signing method */
    len -= 4;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    method_len = _libssh2_ntohu32(s);
    s += 4;
    len -= method_len;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    s += method_len;

    /* Read the signature */
    len -= 4;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }
    *sig_len = _libssh2_ntohu32(s);
    s += 4;
    len -= *sig_len;
    if (len < 0) {
        rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
        goto error;
    }

    *sig = LIBSSH2_ALLOC(session, *sig_len);
    if (!*sig) {
        rc = LIBSSH2_ERROR_ALLOC;
        goto error;
    }
    memcpy(*sig, s, *sig_len);

  error:
    LIBSSH2_FREE(session, transctx->request);
    transctx->request = NULL;

    LIBSSH2_FREE(session, transctx->response);
    transctx->response = NULL;

    return _libssh2_error(session, rc, "agent sign failure");
}
コード例 #5
0
ファイル: agent.c プロジェクト: elitau/MacSleep
static int
agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
{
    unsigned char buf[4];
    int rc;

    /* Send the length of the request */
    if (transctx->state == agent_NB_state_request_created) {
        _libssh2_htonu32(buf, transctx->request_len);
        rc = send(agent->fd, buf, sizeof buf, 0);
        if (rc < 0) {
            if (errno == EAGAIN)
                return LIBSSH2_ERROR_EAGAIN;
            return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
                                  "agent send failed");
        }
        transctx->state = agent_NB_state_request_length_sent;
    }

    /* Send the request body */
    if (transctx->state == agent_NB_state_request_length_sent) {
        rc = send(agent->fd, transctx->request,
                  transctx->request_len, 0);
        if (rc < 0) {
            if (errno == EAGAIN)
                return LIBSSH2_ERROR_EAGAIN;
            return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
                                  "agent send failed");
        }
        transctx->state = agent_NB_state_request_sent;
    }

    /* Receive the length of a response */
    if (transctx->state == agent_NB_state_request_sent) {
        rc = recv(agent->fd, buf, sizeof buf, 0);
        if (rc < 0) {
            if (errno == EAGAIN)
                return LIBSSH2_ERROR_EAGAIN;
            return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_NONE,
                                  "agent recv failed");
        }
        transctx->response_len = _libssh2_ntohu32(buf);
        transctx->response = LIBSSH2_ALLOC(agent->session,
                                           transctx->response_len);
        if (!transctx->response)
            return LIBSSH2_ERROR_ALLOC;

        transctx->state = agent_NB_state_response_length_received;
    }

    /* Receive the response body */
    if (transctx->state == agent_NB_state_response_length_received) {
        rc = recv(agent->fd, transctx->response, transctx->response_len, 0);
        if (rc < 0) {
            if (errno == EAGAIN)
                return LIBSSH2_ERROR_EAGAIN;
            return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
                                  "agent recv failed");
        }
        transctx->state = agent_NB_state_response_received;
    }

    return 0;
}
コード例 #6
0
ファイル: agent.c プロジェクト: Aahanbhatt/robomongo
static int
agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
{
    HWND hwnd;
    char mapname[23];
    HANDLE filemap;
    unsigned char *p;
    unsigned char *p2;
    int id;
    COPYDATASTRUCT cds;

    if (!transctx || 4 + transctx->request_len > PAGEANT_MAX_MSGLEN)
        return _libssh2_error(agent->session, LIBSSH2_ERROR_INVAL,
                              "illegal input");

    hwnd = FindWindow("Pageant", "Pageant");
    if (!hwnd)
        return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
                              "found no pageant");

    sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId());
    filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
                                0, PAGEANT_MAX_MSGLEN, mapname);

    if (filemap == NULL || filemap == INVALID_HANDLE_VALUE)
        return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
                              "failed setting up pageant filemap");

    p2 = p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
    if (p == NULL || p2 == NULL) {
        CloseHandle(filemap);
        return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
                              "failed to open pageant filemap for writing");
    }

    _libssh2_store_str(&p2, (const char *)transctx->request,
                       transctx->request_len);

    cds.dwData = PAGEANT_COPYDATA_ID;
    cds.cbData = 1 + strlen(mapname);
    cds.lpData = mapname;

    id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds);
    if (id > 0) {
        transctx->response_len = _libssh2_ntohu32(p);
        if (transctx->response_len > PAGEANT_MAX_MSGLEN) {
            UnmapViewOfFile(p);
            CloseHandle(filemap);
            return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
                                  "agent setup fail");
        }
        transctx->response = LIBSSH2_ALLOC(agent->session,
                                           transctx->response_len);
        if (!transctx->response) {
            UnmapViewOfFile(p);
            CloseHandle(filemap);
            return _libssh2_error(agent->session, LIBSSH2_ERROR_ALLOC,
                                  "agent malloc");
        }
        memcpy(transctx->response, p + 4, transctx->response_len);
    }

    UnmapViewOfFile(p);
    CloseHandle(filemap);
    return 0;
}
コード例 #7
0
ファイル: hostkey.c プロジェクト: dmiller-nmap/libssh2
/*
 * hostkey_method_ssh_ecdsa_init
 *
 * Initialize the server hostkey working area with e/n pair
 */
static int
hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session,
                          const unsigned char *hostkey_data,
                          size_t hostkey_data_len,
                          void **abstract)
{
    libssh2_ecdsa_ctx *ecdsactx = NULL;
    const unsigned char *s, *k;
    size_t len, key_len, n_len;
    libssh2_curve_type type;

    if(abstract != NULL && *abstract) {
        hostkey_method_ssh_ecdsa_dtor(session, abstract);
        *abstract = NULL;
    }

    if(hostkey_data_len < 23)
        return -1;

    s = hostkey_data;
    len = _libssh2_ntohu32(s);
    s += 4;

    if(len != 19)
        return -1;

    if(strncmp((char *) s, "ecdsa-sha2-nistp256", 19) == 0) {
        type = LIBSSH2_EC_CURVE_NISTP256;
    }
    else if(strncmp((char *) s, "ecdsa-sha2-nistp384", 19) == 0) {
        type = LIBSSH2_EC_CURVE_NISTP384;
    }
    else if(strncmp((char *) s, "ecdsa-sha2-nistp521", 19) == 0) {
        type = LIBSSH2_EC_CURVE_NISTP521;
    }
    else {
        return -1;
    }
    s += 19;

    /* Domain length */
    n_len = _libssh2_ntohu32(s);
    s += 4;

    if(n_len != 8)
        return -1;

    if(type == LIBSSH2_EC_CURVE_NISTP256 && strncmp((char *)s, "nistp256", 8) != 0) {
        return -1;
    }
    else if(type == LIBSSH2_EC_CURVE_NISTP384 && strncmp((char *)s, "nistp384", 8) != 0) {
        return -1;
    }
    else if(type == LIBSSH2_EC_CURVE_NISTP521 && strncmp((char *)s, "nistp521", 8) != 0) {
        return -1;
    }

    s += 8;

    /* public key */
    key_len = _libssh2_ntohu32(s);
    s += 4;

    k = s;

    if(_libssh2_ecdsa_curve_name_with_octal_new(&ecdsactx, k, key_len, type) )
        return -1;

    if(abstract != NULL)
        *abstract = ecdsactx;

    return 0;
}