Beispiel #1
0
static int main_loop(ssh_channel chan) {
    ssh_session session = ssh_channel_get_session(chan);
    socket_t fd;
    struct termios *term = NULL;
    struct winsize *win = NULL;
    pid_t childpid;
    ssh_event event;
    short events;


    childpid = forkpty(&fd, NULL, term, win);
    if(childpid == 0) {
        execl("/bin/bash", "/bin/bash", (char *)NULL);
        abort();
    }

    cb.userdata = &fd;
    ssh_callbacks_init(&cb);
    ssh_set_channel_callbacks(chan, &cb);

    events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;

    event = ssh_event_new();
    if(event == NULL) {
        printf("Couldn't get a event\n");
        return -1;
    }
    if(ssh_event_add_fd(event, fd, events, copy_fd_to_chan, chan) != SSH_OK) {
        printf("Couldn't add an fd to the event\n");
        return -1;
    }
    if(ssh_event_add_session(event, session) != SSH_OK) {
        printf("Couldn't add the session to the event\n");
        return -1;
    }

    do {
        ssh_event_dopoll(event, 1000);
    } while(!ssh_channel_is_closed(chan));

    ssh_event_remove_fd(event, fd);

    ssh_event_remove_session(event, session);

    ssh_event_free(event);
    return 0;
}
Beispiel #2
0
static void do_cleanup(struct cleanup_node_struct **head_ref) {
    struct cleanup_node_struct *current = (*head_ref);
    struct cleanup_node_struct *previous = NULL, *gone = NULL;

    while (current != NULL) {
        if (ssh_channel_is_closed(current->data->channel)) {
            if (current == (*head_ref)) {
                (*head_ref) = current->next;
            }
            if (previous != NULL) {
                previous->next = current->next;
            }
            gone = current;
            current = current->next;

            if (gone->data->channel) {
                _close_socket(*gone->data);
                ssh_remove_channel_callbacks(gone->data->channel, gone->data->cb_chan);
                ssh_channel_free(gone->data->channel);
                gone->data->channel = NULL;

                SAFE_FREE(gone->data->p_fd);
                SAFE_FREE(gone->data->cb_chan);
                SAFE_FREE(gone->data);
                SAFE_FREE(gone);
            }
            else {
                fprintf(stderr, "channel already freed!\n");
            }
            _ssh_log(SSH_LOG_FUNCTIONS, "=== do_cleanup", "Freed.");
        }
        else {
            ssh_channel_close(current->data->channel);
            previous = current;
            current = current->next;
        }
    }
}
Beispiel #3
0
static void select_loop(ssh_session_t *session,ssh_channel_t *channel)
{
    fd_set fds;
    struct timeval timeout;
    char buffer[4096];
    /* channels will be set to the channels to poll.
     * outchannels will contain the result of the poll
     */
    ssh_channel_t *channels[2], *outchannels[2];
    int lus;
    int eof=0;
    int maxfd;
    unsigned int r;
    int ret;
    while(channel)
    {
        do
        {
            FD_ZERO(&fds);
            if(!eof)
            {
                FD_SET(0, &fds);
            }
            timeout.tv_sec = 30;
            timeout.tv_usec = 0;
            FD_SET(ssh_get_fd(session), &fds);
            maxfd = ssh_get_fd(session) + 1;
            channels[0] = channel; // set the first channel we want to read from
            channels[1] = NULL;
            ret = ssh_select(channels, outchannels, maxfd, &fds, &timeout);
            if(signal_delayed)
            {
                sizechanged();
            }
            if(ret == EINTR)
            {
                continue;
            }
            if(FD_ISSET(0, &fds))
            {
                lus = read(0, buffer, sizeof(buffer));
                if(lus)
                    ssh_channel_write(channel, buffer, lus);
                else
                {
                    eof = 1;
                    ssh_channel_send_eof(channel);
                }
            }
            if(channel && ssh_channel_is_closed(channel))
            {
                ssh_channel_free(channel);
                channel=NULL;
                channels[0]=NULL;
            }
            if(outchannels[0])
            {
                while(channel && ssh_channel_is_open(channel) && (r = ssh_channel_poll(channel,0))!=0)
                {
                    lus = ssh_channel_read(channel,buffer,sizeof(buffer) > r ? r : sizeof(buffer),0);
                    if(lus == -1)
                    {
                        fprintf(stderr, "Error reading channel: %s\n",
                                ssh_get_error(session));
                        return;
                    }
                    if(lus == 0)
                    {
                        ssh_channel_free(channel);
                        channel=channels[0]=NULL;
                    }
                    else
                    {
                        if (write(1,buffer,lus) < 0)
                        {
                            fprintf(stderr, "Error writing to buffer\n");
                            return;
                        }
                    }
                }
                while(channel && ssh_channel_is_open(channel) && (r = ssh_channel_poll(channel,1))!=0)  /* stderr */
                {
                    lus = ssh_channel_read(channel,buffer,sizeof(buffer) > r ? r : sizeof(buffer),1);
                    if(lus == -1)
                    {
                        fprintf(stderr, "Error reading channel: %s\n",
                                ssh_get_error(session));
                        return;
                    }
                    if(lus == 0)
                    {
                        ssh_channel_free(channel);
                        channel = channels[0] = NULL;
                    }
                    else
                    {
                        if (write(2, buffer, lus) < 0)
                        {
                            fprintf(stderr, "Error writing to buffer\n");
                            return;
                        }
                    }
                }
            }
            if(channel && ssh_channel_is_closed(channel))
            {
                ssh_channel_free(channel);
                channel=NULL;
            }
        }
        while (ret == EINTR || ret == SSH_EINTR);

    }
}
Beispiel #4
0
static int pkd_exec_hello(int fd, struct pkd_daemon_args *args) {
    int rc = -1;
    ssh_bind b = NULL;
    ssh_session s = NULL;
    ssh_event e = NULL;
    ssh_channel c = NULL;
    enum ssh_bind_options_e opts = -1;

    int level = args->opts.libssh_log_level;
    enum pkd_hostkey_type_e type = args->type;
    const char *hostkeypath = args->hostkeypath;

    pkd_state.eof_received = 0;
    pkd_state.close_received  = 0;
    pkd_state.req_exec_received = 0;

    b = ssh_bind_new();
    if (b == NULL) {
        pkderr("ssh_bind_new\n");
        goto outclose;
    }

    if (type == PKD_RSA) {
        opts = SSH_BIND_OPTIONS_RSAKEY;
    } else if (type == PKD_DSA) {
        opts = SSH_BIND_OPTIONS_DSAKEY;
    } else if (type == PKD_ECDSA) {
        opts = SSH_BIND_OPTIONS_ECDSAKEY;
    } else {
        pkderr("unknown kex algorithm: %d\n", type);
        rc = -1;
        goto outclose;
    }

    rc = ssh_bind_options_set(b, opts, hostkeypath);
    if (rc != 0) {
        pkderr("ssh_bind_options_set: %s\n", ssh_get_error(b));
        goto outclose;
    }

    rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_LOG_VERBOSITY, &level);
    if (rc != 0) {
        pkderr("ssh_bind_options_set log verbosity: %s\n", ssh_get_error(b));
        goto outclose;
    }

    s = ssh_new();
    if (s == NULL) {
        pkderr("ssh_new\n");
        goto outclose;
    }

    /*
     * ssh_bind_accept loads host key as side-effect.  If this
     * succeeds, the given 'fd' will be closed upon 'ssh_free(s)'.
     */
    rc = ssh_bind_accept_fd(b, s, fd);
    if (rc != SSH_OK) {
        pkderr("ssh_bind_accept_fd: %s\n", ssh_get_error(b));
        goto outclose;
    }

    /* accept only publickey-based auth */
    ssh_set_auth_methods(s, SSH_AUTH_METHOD_PUBLICKEY);

    /* initialize callbacks */
    ssh_callbacks_init(&pkd_server_cb);
    pkd_server_cb.userdata = &c;
    rc = ssh_set_server_callbacks(s, &pkd_server_cb);
    if (rc != SSH_OK) {
        pkderr("ssh_set_server_callbacks: %s\n", ssh_get_error(s));
        goto out;
    }

    /* first do key exchange */
    rc = ssh_handle_key_exchange(s);
    if (rc != SSH_OK) {
        pkderr("ssh_handle_key_exchange: %s\n", ssh_get_error(s));
        goto out;
    }

    /* setup and pump event to carry out exec channel */
    e = ssh_event_new();
    if (e == NULL) {
        pkderr("ssh_event_new\n");
        goto out;
    }

    rc = ssh_event_add_session(e, s);
    if (rc != SSH_OK) {
        pkderr("ssh_event_add_session\n");
        goto out;
    }

    /* poll until exec channel established */
    while ((ctx.keep_going != 0) &&
            (rc != SSH_ERROR) && (pkd_state.req_exec_received == 0)) {
        rc = ssh_event_dopoll(e, -1 /* infinite timeout */);
    }

    if (rc == SSH_ERROR) {
        pkderr("ssh_event_dopoll\n");
        goto out;
    } else if (c == NULL) {
        pkderr("poll loop exited but exec channel not ready\n");
        rc = -1;
        goto out;
    }

    rc = ssh_channel_write(c, "hello\n", 6); /* XXX: customizable payloads */
    if (rc != 6) {
        pkderr("ssh_channel_write partial (%d)\n", rc);
    }

    rc = ssh_channel_request_send_exit_status(c, 0);
    if (rc != SSH_OK) {
        pkderr("ssh_channel_request_send_exit_status: %s\n",
               ssh_get_error(s));
        goto out;
    }

    rc = ssh_channel_send_eof(c);
    if (rc != SSH_OK) {
        pkderr("ssh_channel_send_eof: %s\n", ssh_get_error(s));
        goto out;
    }

    rc = ssh_channel_close(c);
    if (rc != SSH_OK) {
        pkderr("ssh_channel_close: %s\n", ssh_get_error(s));
        goto out;
    }

    while ((ctx.keep_going != 0) &&
            (pkd_state.eof_received == 0) &&
            (pkd_state.close_received == 0) &&
            (ssh_channel_is_closed(c) == 0)) {
        rc = ssh_event_dopoll(e, 1000 /* milliseconds */);
        if (rc == SSH_ERROR) {
            pkderr("ssh_event_dopoll for eof + close: %s\n", ssh_get_error(s));
            break;
        } else {
            rc = 0;
        }
    }
    goto out;

outclose:
    close(fd);
out:
    if (c != NULL) {
        ssh_channel_free(c);
    }
    if (e != NULL) {
        ssh_event_remove_session(e, s);
        ssh_event_free(e);
    }
    if (s != NULL) {
        ssh_disconnect(s);
        ssh_free(s);
    }
    if (b != NULL) {
        ssh_bind_free(b);
    }
    return rc;
}
Beispiel #5
0
/* channel_select base main loop, with a standard select(2)
 */
static void select_loop(ssh_session session,ssh_channel channel){
    fd_set fds;
    struct timeval timeout;
    char buffer[4096];
    ssh_buffer readbuf=ssh_buffer_new();
    ssh_channel channels[2];
    int lus;
    int eof=0;
    int maxfd;
    int ret;
    while(channel){
       /* when a signal is caught, ssh_select will return
         * with SSH_EINTR, which means it should be started
         * again. It lets you handle the signal the faster you
         * can, like in this window changed example. Of course, if
         * your signal handler doesn't call libssh at all, you're
         * free to handle signals directly in sighandler.
         */
        do{
            FD_ZERO(&fds);
            if(!eof)
                FD_SET(0,&fds);
            timeout.tv_sec=30;
            timeout.tv_usec=0;
            FD_SET(ssh_get_fd(session),&fds);
            maxfd=ssh_get_fd(session)+1;
            ret=select(maxfd,&fds,NULL,NULL,&timeout);
            if(ret==EINTR)
                continue;
            if(FD_ISSET(0,&fds)){
                lus=read(0,buffer,sizeof(buffer));
                if(lus)
                    ssh_channel_write(channel,buffer,lus);
                else {
                    eof=1;
                    ssh_channel_send_eof(channel);
                }
            }
            if(FD_ISSET(ssh_get_fd(session),&fds)){
                ssh_set_fd_toread(session);
            }
            channels[0]=channel; // set the first channel we want to read from
            channels[1]=NULL;
            ret=ssh_channel_select(channels,NULL,NULL,NULL); // no specific timeout - just poll
            if(signal_delayed)
                sizechanged();
        } while (ret==EINTR || ret==SSH_EINTR);

        // we already looked for input from stdin. Now, we are looking for input from the channel

        if(channel && ssh_channel_is_closed(channel)){
            ssh_channel_free(channel);
            channel=NULL;
            channels[0]=NULL;
        }
        if(channels[0]){
            while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,0)>0){
                lus=channel_read_buffer(channel,readbuf,0,0);
                if(lus==-1){
                    fprintf(stderr, "Error reading channel: %s\n",
                        ssh_get_error(session));
                    return;
                }
                if(lus==0){
                    ssh_channel_free(channel);
                    channel=channels[0]=NULL;
                } else
                    if (write(1,ssh_buffer_get_begin(readbuf),lus) < 0) {
                      fprintf(stderr, "Error writing to buffer\n");
                      return;
                    }
            }
            while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,1)>0){ /* stderr */
                lus=channel_read_buffer(channel,readbuf,0,1);
                if(lus==-1){
                    fprintf(stderr, "Error reading channel: %s\n",
                        ssh_get_error(session));
                    return;
                }
                if(lus==0){
                    ssh_channel_free(channel);
                    channel=channels[0]=NULL;
                } else
                    if (write(2,ssh_buffer_get_begin(readbuf),lus) < 0) {
                      fprintf(stderr, "Error writing to buffer\n");
                      return;
                    }
            }
        }
        if(channel && ssh_channel_is_closed(channel)){
            ssh_channel_free(channel);
            channel=NULL;
        }
    }
    ssh_buffer_free(readbuf);
}
Beispiel #6
0
static int my_fd_data_function(UNUSED_PARAM(socket_t fd),
                               int revents,
                               void *userdata)
{
    struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
    ssh_channel channel = event_fd_data->channel;
    ssh_session session;
    int len, i, wr;
    char buf[16384];
    int blocking;

    if (channel == NULL) {
        _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel == NULL!");
        return 0;
    }

    session = ssh_channel_get_session(channel);

    if (ssh_channel_is_closed(channel)) {
        _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel is closed!");
        stack_socket_close(session, event_fd_data);
        return 0;
    }

    if (!(revents & POLLIN)) {
        if (revents & POLLPRI) {
            _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLPRI");
        }
        if (revents & POLLOUT) {
            _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLOUT");
        }
        if (revents & POLLHUP) {
            _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLHUP");
        }
        if (revents & POLLNVAL) {
            _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLNVAL");
        }
        if (revents & POLLERR) {
            _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLERR");
        }
        return 0;
    }

    blocking = ssh_is_blocking(session);
    ssh_set_blocking(session, 0);

    _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "Trying to read from tcp socket fd = %d... (Channel %d:%d state=%d)",
                        *event_fd_data->p_fd, channel->local_channel, channel->remote_channel, channel->state);
#ifdef _WIN32
    struct sockaddr from;
    int fromlen = sizeof(from);
    len = recvfrom(*event_fd_data->p_fd, buf, sizeof(buf), 0, &from, &fromlen);
#else
    len = recv(*event_fd_data->p_fd, buf, sizeof(buf), 0);
#endif // _WIN32
    if (len < 0) {
        _ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Reading from tcp socket: %s", strerror(errno));

        ssh_channel_send_eof(channel);
    }
    else if (len > 0) {
        if (ssh_channel_is_open(channel)) {
            wr = 0;
            do {
                i = ssh_channel_write(channel, buf, len);
                if (i < 0) {
                    _ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Error writing on the direct-tcpip channel: %d", i);
                    len = wr;
                    break;
                }
                wr += i;
                _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel_write (%d from %d)", wr, len);
            } while (i > 0 && wr < len);
        }
        else {
            _ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Can't write on closed channel!");
        }
    }
    else {
        _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "The destination host has disconnected!");

        ssh_channel_close(channel);
#ifdef _WIN32
        shutdown(*event_fd_data->p_fd, SD_RECEIVE);
#else
        shutdown(*event_fd_data->p_fd, SHUT_RD);
#endif // _WIN32
    }
    ssh_set_blocking(session, blocking);

    return len;
}
Beispiel #7
0
int channel_is_closed(ssh_channel channel){
  return ssh_channel_is_closed(channel);
}
Beispiel #8
0
static int
nc_write(struct nc_session *session, const void *buf, size_t count)
{
    int c;
    size_t written = 0;
#ifdef NC_ENABLED_TLS
    unsigned long e;
#endif

    if ((session->status != NC_STATUS_RUNNING) && (session->status != NC_STATUS_STARTING)) {
        return -1;
    }

    /* prevent SIGPIPE this way */
    if (!nc_session_is_connected(session)) {
        ERR("Session %u: communication socket unexpectedly closed.", session->id);
        session->status = NC_STATUS_INVALID;
        session->term_reason = NC_SESSION_TERM_DROPPED;
        return -1;
    }

    DBG("Session %u: sending message:\n%.*s\n", session->id, count, buf);

    do {
        switch (session->ti_type) {
        case NC_TI_FD:
            c = write(session->ti.fd.out, (char *)(buf + written), count - written);
            if (c < 0) {
                ERR("Session %u: socket error (%s).", session->id, strerror(errno));
                return -1;
            }
            break;

#ifdef NC_ENABLED_SSH
        case NC_TI_LIBSSH:
            if (ssh_channel_is_closed(session->ti.libssh.channel) || ssh_channel_is_eof(session->ti.libssh.channel)) {
                if (ssh_channel_is_closed(session->ti.libssh.channel)) {
                    ERR("Session %u: SSH channel unexpectedly closed.", session->id);
                } else {
                    ERR("Session %u: SSH channel unexpected EOF.", session->id);
                }
                session->status = NC_STATUS_INVALID;
                session->term_reason = NC_SESSION_TERM_DROPPED;
                return -1;
            }
            c = ssh_channel_write(session->ti.libssh.channel, (char *)(buf + written), count - written);
            if ((c == SSH_ERROR) || (c == -1)) {
                ERR("Session %u: SSH channel write failed.", session->id);
                return -1;
            }
            break;
#endif
#ifdef NC_ENABLED_TLS
        case NC_TI_OPENSSL:
            c = SSL_write(session->ti.tls, (char *)(buf + written), count - written);
            if (c < 1) {
                switch ((e = SSL_get_error(session->ti.tls, c))) {
                case SSL_ERROR_ZERO_RETURN:
                    ERR("Session %u: SSL connection was properly closed.", session->id);
                    return -1;
                case SSL_ERROR_WANT_WRITE:
                    c = 0;
                    break;
                case SSL_ERROR_SYSCALL:
                    ERR("Session %u: SSL socket error (%s).", session->id, strerror(errno));
                    return -1;
                case SSL_ERROR_SSL:
                    ERR("Session %u: SSL error (%s).", session->id, ERR_reason_error_string(e));
                    return -1;
                default:
                    ERR("Session %u: unknown SSL error occured.", session->id);
                    return -1;
                }
            }
            break;
#endif
        default:
            ERRINT;
            return -1;
        }

        if (c == 0) {
            /* we must wait */
            usleep(NC_TIMEOUT_STEP);
        }

        written += c;
    } while (written < count);

    return written;
}