bool SSH2Channel::eof(ExceptionSink *xsink) {
   AutoLocker al(parent->m);
   if (check_open(xsink))
      return true;

   return (bool)libssh2_channel_eof(channel);
}
Exemple #2
0
static int
mx_channel_netconf_read_hello (mx_channel_t *mcp)
{
    mx_buffer_t *mbp = mcp->mc_rbufp;
    int len;

    for (;;) {
	if (mbp->mb_start + mbp->mb_len == mbp->mb_size) {
	    mx_buffer_t *newp = mx_buffer_create(0);
	    if (newp == NULL) {
		mx_log("C%u cannot extend buffer", mcp->mc_id);
		return TRUE;
	    }

	    mbp->mb_next = newp;
	    mbp = newp;
	}

	len = mx_channel_read(mcp, mbp->mb_data + mbp->mb_start + mbp->mb_len,
			       mbp->mb_size - (mbp->mb_start + mbp->mb_len));

	if (libssh2_channel_eof(mcp->mc_channel)) {
	    DBG_POLL("C%u eof during read_hello", mcp->mc_id);
	    return FALSE;
	}

	if (len == LIBSSH2_ERROR_EAGAIN) {
	    /* Nothing to read, nothing to write; move on */
	    DBG_POLL("C%u is drained", mcp->mc_id);
#if 0
	    break;
#else
	    sleep(1);
	    continue;
#endif
	}

	if (len < 0)
	    return TRUE;

	mbp->mb_len += len;
	DBG_POLL("C%u read %d", mcp->mc_id, len);

	if (mx_channel_netconf_has_marker(mcp)) {
	    mx_log("C%u found end-of-frame; len %lu, discarding",
		   mcp->mc_id, mcp->mc_rbufp->mb_len);
	    mbp->mb_len = mbp->mb_start = 0;
	    if (mbp->mb_next) {
		mx_buffer_free(mbp->mb_next);
		mbp->mb_next = NULL;
	    }
	    return TRUE;
	}
    }

    return FALSE;
}
void cql_ccm_bridge_t::wait_for_shell_prompth() {
  const char SHELL_PROMPTH_CHARACTER = '$';

  while (!_esc_remover_stdout.ends_with_character(SHELL_PROMPTH_CHARACTER)) {
    if (libssh2_channel_eof(_ssh_internals->_channel)) {
      throw cql_ccm_bridge_exception_t("connection closed by remote host");
    }

    terminal_read_stream(_esc_remover_stdout, SSH_STDOUT);
    boost::this_thread::sleep(boost::posix_time::milliseconds(50));
  }
}
static int php_ssh2_channel_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
{
	php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;

	if (!abstract->refcount || (--(*(abstract->refcount)) == 0)) {
		/* Last one out, turn off the lights */
		if (abstract->refcount) {
			efree(abstract->refcount);
		}
		libssh2_channel_eof(abstract->channel);
		libssh2_channel_free(abstract->channel);
		zend_list_delete(abstract->session_rsrc);
	}
	efree(abstract);

	return 0;
}
Exemple #5
0
/*
 * Get DNS query using SSH transport layer.
 */
static ssize_t dig_ssh_request(struct ssh_session *ssh_info,
		char *buf, size_t buf_size, ssize_t len)
{
	int ret;
	ssize_t recv_size;

	do {
		ret = libssh2_channel_write(ssh_info->channel, buf, len);
		if (ret < 0) {
			ERR("libssh2_channel_write: %d", ret);
			goto error;
		}
		DBG("DNS request of size %ld sent to ssh channel", len);

		recv_size = libssh2_channel_read(ssh_info->channel, buf, buf_size);
		if (recv_size < 0) {
			char *buf;
			ERR("SSH channel read failed");
			libssh2_session_last_error(ssh_info->session, &buf, NULL, 0);
			ERR("Failure: %s", buf);
		} else if (recv_size == 0) {
			ret = libssh2_channel_eof(ssh_info->channel);
			if (ret) {
				DBG("SSH server disconnected!");
				libssh2_channel_close(ssh_info->channel);
				libssh2_channel_free(ssh_info->channel);
				/* Create new channel */
				ret = ssh_setup_tunnel(ssh_info, dns_ip);
				if (ret < 0) {
					goto error;
				}
			}
		} else {
			DBG("DNS reply red from ssh channel (size: %ld)",
					recv_size);
			goto end;
		}
	} while (1);

end:
	return recv_size;

error:
	return -1;
}
 int detail::process_impl::read_some( char* data, size_t len, int stream_id ){
      if( !sshc->my->session ) { FC_THROW( "Session closed" ); }
      int rc;
      char* buf = data;
      size_t buflen = len;
      do {
          rc = sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_read_ex, chan, stream_id, buf, buflen),
                                                             "read failed: ${message}");
          if( rc > 0 ) {
             buf += rc;
             buflen -= rc;
             return buf-data;
          } else if( rc == 0 ) {
             if( libssh2_channel_eof( chan ) )
               return -1; // eof
             sshc->my->wait_on_socket();
          }
      } while( rc >= 0 && buflen);
      return buf-data;
 }
Exemple #7
0
ShellChannel::ReadReply ShellChannel::readUntil(const QByteArray& marker)
{
	ReadReply result;
	result.readAgain = false;

	//	Check if the buffer is already loaded and ready to go.
	int markerIndex = mReadBuffer.indexOf(marker);
	if (markerIndex == -1)
	{
		//	Actually do the read
		int rc = libssh2_channel_read(mHandle, mScratchBuffer, SSH_SHELL_BUFFER_SIZE);
		if (rc > 0)
			mReadBuffer.append(mScratchBuffer, rc);
		else if (rc == LIBSSH2_ERROR_EAGAIN)
		{
			result.readAgain = true;
			return result;
		}
		else if (rc == 0)
		{
			if (libssh2_channel_eof(mHandle))
				criticalError("Connection closed unexpectedly");
		}
		else
			criticalError("Failed to read from host");

		//	Check again to see if the buffer is ready to go.
		markerIndex = mReadBuffer.indexOf(marker);
	}

	//	If there's data ready to go, pack it into the reply.
	if (markerIndex > -1)
	{
		result.data = mReadBuffer.left(markerIndex);
		mReadBuffer = mReadBuffer.right(mReadBuffer.size() - (markerIndex + marker.length()));
	}

	return result;
}
Exemple #8
0
 int process_d::read_some( char* data, size_t len, int stream_id ) {
     if( !sshc->my->m_session ) { MACE_SSH_THROW( "Session closed\n" ); }
    
    int rc;
    char* buf = data;
    size_t buflen = len;
    do {
        rc = libssh2_channel_read_ex( chan, stream_id, buf, buflen );
        if( rc > 0 ) {
           buf += rc;
           buflen -= rc;
           return buf-data;
        } else if( rc == 0 ) {
           if( libssh2_channel_eof( chan ) )  {
             return -1; // eof
           }
           sshc->my->wait_on_socket();
        } else {
          if( rc == LIBSSH2_ERROR_EAGAIN ) {
            if( 0 < (buf-data) ) {
              return buf-data;
            }
            else  {
              sshc->my->wait_on_socket();
              rc = 0;
              continue;
            }
          } else {
            char* msg;
            if( !sshc || !sshc->my || !sshc->my->m_session ) { MACE_SSH_THROW( "Session closed" ); }
            slog( "my: %1%", sshc->my );
            rc   = libssh2_session_last_error( sshc->my->m_session, &msg, 0, 0 );
            MACE_SSH_THROW( "read failed: %1% - %2%", %rc %msg  ); return buf-data;
          }
        }
    } while( rc >= 0 && buflen);
    return buf-data;
 }
static size_t php_ssh2_channel_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
{
	php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
	ssize_t readstate;
	LIBSSH2_SESSION *session;

	stream->eof = libssh2_channel_eof(abstract->channel);
	libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);
	session = (LIBSSH2_SESSION *)zend_fetch_resource(NULL TSRMLS_CC, abstract->session_rsrc, PHP_SSH2_SESSION_RES_NAME, NULL, 1, le_ssh2_session);

#ifdef PHP_SSH2_SESSION_TIMEOUT
	if (abstract->is_blocking) {
		libssh2_session_set_timeout(session, abstract->timeout);
	}
#endif

	readstate = libssh2_channel_read_ex(abstract->channel, abstract->streamid, buf, count);

#ifdef PHP_SSH2_SESSION_TIMEOUT
	if (abstract->is_blocking) {
		libssh2_session_set_timeout(session, 0);
	}
#endif
	if (readstate == LIBSSH2_ERROR_EAGAIN) {
		readstate = 0;
	}

	if (readstate < 0) {
		char *error_msg = NULL;
		if (libssh2_session_last_error(session, &error_msg, NULL, 0) == readstate) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure '%s' (%ld)", error_msg, readstate);
		}

		stream->eof = 1;
		readstate = 0;
	}
	return readstate;
}
void* ssh_client_thread(void* data) {

    guac_client* client = (guac_client*) data;
    ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;

    guac_socket* socket = client->socket;
    char buffer[8192];

    pthread_t input_thread;

    /* Init SSH base libraries */
    if (guac_common_ssh_init(client))
        return NULL;

    /* Get user and credentials */
    client_data->user = guac_ssh_get_user(client);

    /* Send new name */
    char name[1024];
    snprintf(name, sizeof(name)-1, "%s@%s",
            client_data->username, client_data->hostname);
    guac_protocol_send_name(socket, name);

    /* Open SSH session */
    client_data->session = guac_common_ssh_create_session(client,
            client_data->hostname, client_data->port, client_data->user);
    if (client_data->session == NULL) {
        /* Already aborted within guac_common_ssh_create_session() */
        return NULL;
    }

    pthread_mutex_init(&client_data->term_channel_lock, NULL);

    /* Open channel for terminal */
    client_data->term_channel =
        libssh2_channel_open_session(client_data->session->session);
    if (client_data->term_channel == NULL) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
                "Unable to open terminal channel.");
        return NULL;
    }

#ifdef ENABLE_SSH_AGENT
    /* Start SSH agent forwarding, if enabled */
    if (client_data->enable_agent) {
        libssh2_session_callback_set(client_data->session,
                LIBSSH2_CALLBACK_AUTH_AGENT, (void*) ssh_auth_agent_callback);

        /* Request agent forwarding */
        if (libssh2_channel_request_auth_agent(client_data->term_channel))
            guac_client_log(client, GUAC_LOG_ERROR, "Agent forwarding request failed");
        else
            guac_client_log(client, GUAC_LOG_INFO, "Agent forwarding enabled.");
    }

    client_data->auth_agent = NULL;
#endif

    /* Start SFTP session as well, if enabled */
    if (client_data->enable_sftp) {

        /* Create SSH session specific for SFTP */
        guac_client_log(client, GUAC_LOG_DEBUG, "Reconnecting for SFTP...");
        client_data->sftp_session =
            guac_common_ssh_create_session(client, client_data->hostname,
                    client_data->port, client_data->user);
        if (client_data->sftp_session == NULL) {
            /* Already aborted within guac_common_ssh_create_session() */
            return NULL;
        }

        /* Request SFTP */
        client_data->sftp_filesystem =
            guac_common_ssh_create_sftp_filesystem(
                    client_data->sftp_session, "/");

        /* Set generic (non-filesystem) file upload handler */
        client->file_handler = guac_sftp_file_handler;

        /* Init handlers for Guacamole-specific console codes */
        client_data->term->upload_path_handler = guac_sftp_set_upload_path;
        client_data->term->file_download_handler = guac_sftp_download_file;

        guac_client_log(client, GUAC_LOG_DEBUG, "SFTP session initialized");

    }

    /* Request PTY */
    if (libssh2_channel_request_pty_ex(client_data->term_channel, "linux", sizeof("linux")-1, NULL, 0,
            client_data->term->term_width, client_data->term->term_height, 0, 0)) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to allocate PTY.");
        return NULL;
    }

    /* Request shell */
    if (libssh2_channel_shell(client_data->term_channel)) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to associate shell with PTY.");
        return NULL;
    }

    /* Logged in */
    guac_client_log(client, GUAC_LOG_INFO, "SSH connection successful.");

    /* Start input thread */
    if (pthread_create(&(input_thread), NULL, ssh_input_thread, (void*) client)) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to start input thread");
        return NULL;
    }

    /* Set non-blocking */
    libssh2_session_set_blocking(client_data->session->session, 0);

    /* While data available, write to terminal */
    int bytes_read = 0;
    for (;;) {

        /* Track total amount of data read */
        int total_read = 0;

        pthread_mutex_lock(&(client_data->term_channel_lock));

        /* Stop reading at EOF */
        if (libssh2_channel_eof(client_data->term_channel)) {
            pthread_mutex_unlock(&(client_data->term_channel_lock));
            break;
        }

        /* Read terminal data */
        bytes_read = libssh2_channel_read(client_data->term_channel,
                buffer, sizeof(buffer));

        pthread_mutex_unlock(&(client_data->term_channel_lock));

        /* Attempt to write data received. Exit on failure. */
        if (bytes_read > 0) {
            int written = guac_terminal_write_stdout(client_data->term, buffer, bytes_read);
            if (written < 0)
                break;

            total_read += bytes_read;
        }

        else if (bytes_read < 0 && bytes_read != LIBSSH2_ERROR_EAGAIN)
            break;

#ifdef ENABLE_SSH_AGENT
        /* If agent open, handle any agent packets */
        if (client_data->auth_agent != NULL) {
            bytes_read = ssh_auth_agent_read(client_data->auth_agent);
            if (bytes_read > 0)
                total_read += bytes_read;
            else if (bytes_read < 0 && bytes_read != LIBSSH2_ERROR_EAGAIN)
                client_data->auth_agent = NULL;
        }
#endif

        /* Wait for more data if reads turn up empty */
        if (total_read == 0) {
            fd_set fds;
            struct timeval timeout;

            FD_ZERO(&fds);
            FD_SET(client_data->session->fd, &fds);

            /* Wait for one second */
            timeout.tv_sec = 1;
            timeout.tv_usec = 0;

            if (select(client_data->session->fd + 1, &fds,
                        NULL, NULL, &timeout) < 0)
                break;
        }

    }

    /* Kill client and Wait for input thread to die */
    guac_client_stop(client);
    pthread_join(input_thread, NULL);

    pthread_mutex_destroy(&client_data->term_channel_lock);

    guac_client_log(client, GUAC_LOG_INFO, "SSH connection ended.");
    return NULL;

}
Exemple #11
0
void* ssh_client_thread(void* data) {

    guac_client* client = (guac_client*) data;
    ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;

    char name[1024];

    guac_socket* socket = client->socket;
    char buffer[8192];
    int bytes_read = -1234;

    int socket_fd;
    int stdout_fd = client_data->term->stdout_pipe_fd[1];

    pthread_t input_thread;

    libssh2_init(0);

    /* Get username */
    if (client_data->username[0] == 0)
        prompt(client, "Login as: ", client_data->username, sizeof(client_data->username), true);

    /* Send new name */
    snprintf(name, sizeof(name)-1, "%s@%s", client_data->username, client_data->hostname);
    guac_protocol_send_name(socket, name);

    /* If key specified, import */
    if (client_data->key_base64[0] != 0) {

        /* Attempt to read key without passphrase */
        client_data->key = ssh_key_alloc(client_data->key_base64,
                strlen(client_data->key_base64), "");

        /* On failure, attempt with passphrase */
        if (client_data->key == NULL) {

            /* Prompt for passphrase if missing */
            if (client_data->key_passphrase[0] == 0)
                prompt(client, "Key passphrase: ", client_data->key_passphrase,
                        sizeof(client_data->key_passphrase), false);

            /* Import key with passphrase */
            client_data->key = ssh_key_alloc(client_data->key_base64,
                    strlen(client_data->key_base64),
                    client_data->key_passphrase);

            /* If still failing, give up */
            if (client_data->key == NULL) {
                guac_client_log_error(client, "Auth key import failed.");
                return NULL;
            }

        } /* end decrypt key with passphrase */

        /* Success */
        guac_client_log_info(client, "Auth key successfully imported.");

    } /* end if key given */

    /* Otherwise, get password if not provided */
    else if (client_data->password[0] == 0)
        prompt(client, "Password: "******"\x1B[H\x1B[J", 6);

    /* Open SSH session */
    client_data->session = __guac_ssh_create_session(client, &socket_fd);
    if (client_data->session == NULL) {
        /* Already aborted within __guac_ssh_create_session() */
        return NULL;
    }

    /* Open channel for terminal */
    client_data->term_channel = libssh2_channel_open_session(client_data->session);
    if (client_data->term_channel == NULL) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to open terminal channel.");
        return NULL;
    }

#ifdef ENABLE_SSH_AGENT
    /* Start SSH agent forwarding, if enabled */
    if (client_data->enable_agent) {
        libssh2_session_callback_set(client_data->session,
                LIBSSH2_CALLBACK_AUTH_AGENT, (void*) ssh_auth_agent_callback);

        /* Request agent forwarding */
        if (libssh2_channel_request_auth_agent(client_data->term_channel))
            guac_client_log_error(client, "Agent forwarding request failed");
        else
            guac_client_log_info(client, "Agent forwarding enabled.");
    }

    client_data->auth_agent = NULL;
#endif

    /* Start SFTP session as well, if enabled */
    if (client_data->enable_sftp) {

        /* Create SSH session specific for SFTP */
        guac_client_log_info(client, "Reconnecting for SFTP...");
        client_data->sftp_ssh_session = __guac_ssh_create_session(client, NULL);
        if (client_data->sftp_ssh_session == NULL) {
            /* Already aborted within __guac_ssh_create_session() */
            return NULL;
        }

        /* Request SFTP */
        client_data->sftp_session = libssh2_sftp_init(client_data->sftp_ssh_session);
        if (client_data->sftp_session == NULL) {
            guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to start SFTP session.");
            return NULL;
        }

        /* Set file handler */
        client->file_handler = guac_sftp_file_handler;

        guac_client_log_info(client, "SFTP session initialized");

    }

    /* Request PTY */
    if (libssh2_channel_request_pty_ex(client_data->term_channel, "linux", sizeof("linux")-1, NULL, 0,
            client_data->term->term_width, client_data->term->term_height, 0, 0)) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to allocate PTY.");
        return NULL;
    }

    /* Request shell */
    if (libssh2_channel_shell(client_data->term_channel)) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to associate shell with PTY.");
        return NULL;
    }

    /* Logged in */
    guac_client_log_info(client, "SSH connection successful.");

    /* Start input thread */
    if (pthread_create(&(input_thread), NULL, ssh_input_thread, (void*) client)) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to start input thread");
        return NULL;
    }

    /* Set non-blocking */
    libssh2_session_set_blocking(client_data->session, 0);

    /* While data available, write to terminal */
    bytes_read = 0;
    while (!libssh2_channel_eof(client_data->term_channel)) {

        /* Track total amount of data read */
        int total_read = 0;

        /* Read terminal data */
        bytes_read = libssh2_channel_read(client_data->term_channel,
                buffer, sizeof(buffer));

        /* Attempt to write data received. Exit on failure. */
        if (bytes_read > 0) {
            int written = guac_terminal_write_all(stdout_fd, buffer, bytes_read);
            if (written < 0)
                break;

            total_read += bytes_read;
        }

        else if (bytes_read < 0 && bytes_read != LIBSSH2_ERROR_EAGAIN)
            break;

#ifdef ENABLE_SSH_AGENT
        /* If agent open, handle any agent packets */
        if (client_data->auth_agent != NULL) {
            bytes_read = ssh_auth_agent_read(client_data->auth_agent);
            if (bytes_read > 0)
                total_read += bytes_read;
            else if (bytes_read < 0 && bytes_read != LIBSSH2_ERROR_EAGAIN)
                client_data->auth_agent = NULL;
        }
#endif

        /* Wait for more data if reads turn up empty */
        if (total_read == 0) {
            fd_set fds;
            struct timeval timeout;

            FD_ZERO(&fds);
            FD_SET(socket_fd, &fds);

            /* Wait for one second */
            timeout.tv_sec = 1;
            timeout.tv_usec = 0;

            if (select(socket_fd+1, &fds, NULL, NULL, &timeout) < 0)
                break;
        }

    }

    /* Kill client and Wait for input thread to die */
    guac_client_stop(client);
    pthread_join(input_thread, NULL);

    guac_client_log_info(client, "SSH connection ended.");
    return NULL;

}
Exemple #12
0
int Parser::runCommand(QString command)
{
    // command channel
    //------------setup channel ----------------------
    LIBSSH2_CHANNEL *channel = NULL;
    channel = libssh2_channel_open_session(session_);
    if ( channel == NULL )
    {
        qDebug()<<"Failed to open a new channel\n";
        socket_->disconnectFromHost();
        return -1;
    }

    /* Force Data to on STDOUT and STDERR to be on seperate channels
     * read individually with *_read and *_read_stderr functions */
    libssh2_channel_handle_extended_data(channel,LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL);

    libssh2_channel_set_blocking(channel, 1);

    {
    int rc;
    while ((rc=libssh2_channel_exec(channel, command.toLocal8Bit().constData()))==LIBSSH2_ERROR_EAGAIN );
    if (rc)
    {
        return -1;
    }


    //-------read channel-----------
    int read;

    QString stdout_str;
    QString stderr_str;
    while(true)
    {
        //qDebug("libssh2_channel_read() >>>");

        {
            QByteArray byte_array;
            byte_array.resize(4096);
            char* buffer=byte_array.data();
            int buffer_size=byte_array.size();
            read = libssh2_channel_read(channel, buffer, buffer_size-10);
            if(read>0)
            {
                QByteArray debug = QByteArray(buffer, read);
                stdout_str.append(debug);
            }
            if(LIBSSH2_ERROR_EAGAIN == read)
            {
                qDebug("LIBSSH2_ERROR_EAGAIN");
                break;
            }
            else if(read  < 0)
            {
                qDebug(" error reading from std channel");
                closeChannel(channel);
                goto next_channel;
            }
        }
        {
            QByteArray byte_array;
            byte_array.resize(4096);
            char* buffer=byte_array.data();
            int buffer_size=byte_array.size();

read = libssh2_channel_read_stderr(channel, buffer, buffer_size-10);
            if(read>0)
            {
                QByteArray debug = QByteArray(buffer, read);
                stderr_str.append(debug);
            }
            if(LIBSSH2_ERROR_EAGAIN == read)
            {
                qDebug("LIBSSH2_ERROR_EAGAIN");
                break;
            }
            else if(read  < 0)
            {
                qDebug(" error reading from stderr channel");
                closeChannel(channel);
                goto next_channel;
            }
        }


        int i = libssh2_channel_eof(channel);
        if(i)
        {
            //qDebug("libssh2_channel_eof %i", i);
            closeChannel(channel);
            goto next_channel;
        }
    }
    next_channel:
    if(!stdout_str.isEmpty())
    {
        qDebug()<<"STDOUT:\n"<<stdout_str;
    }
    if(!stderr_str.isEmpty())
    {
        qDebug()<<"STDERR:\n"<<stderr_str;
    }
    }
    return 1;
}
Exemple #13
0
 bool detail::process_istream::eof()const { 
    return 0 != libssh2_channel_eof( proc.chan );
 }
void* ssh_client_thread(void* data) {

    guac_client* client = (guac_client*) data;
    guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;
    guac_ssh_settings* settings = ssh_client->settings;

    char buffer[8192];

    pthread_t input_thread;

    /* Init SSH base libraries */
    if (guac_common_ssh_init(client)) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
                "SSH library initialization failed");
        return NULL;
    }

    /* Set up screen recording, if requested */
    if (settings->recording_path != NULL) {
        guac_common_recording_create(client,
                settings->recording_path,
                settings->recording_name,
                settings->create_recording_path);
    }

    /* Create terminal */
    ssh_client->term = guac_terminal_create(client,
            settings->font_name, settings->font_size,
            settings->resolution, settings->width, settings->height,
            settings->color_scheme);

    /* Fail if terminal init failed */
    if (ssh_client->term == NULL) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
                "Terminal initialization failed");
        return NULL;
    }

    /* Set up typescript, if requested */
    if (settings->typescript_path != NULL) {
        guac_terminal_create_typescript(ssh_client->term,
                settings->typescript_path,
                settings->typescript_name,
                settings->create_typescript_path);
    }

    /* Get user and credentials */
    ssh_client->user = guac_ssh_get_user(client);

    /* Open SSH session */
    ssh_client->session = guac_common_ssh_create_session(client,
            settings->hostname, settings->port, ssh_client->user);
    if (ssh_client->session == NULL) {
        /* Already aborted within guac_common_ssh_create_session() */
        return NULL;
    }

    pthread_mutex_init(&ssh_client->term_channel_lock, NULL);

    /* Open channel for terminal */
    ssh_client->term_channel =
        libssh2_channel_open_session(ssh_client->session->session);
    if (ssh_client->term_channel == NULL) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
                "Unable to open terminal channel.");
        return NULL;
    }

#ifdef ENABLE_SSH_AGENT
    /* Start SSH agent forwarding, if enabled */
    if (ssh_client->enable_agent) {
        libssh2_session_callback_set(ssh_client->session,
                LIBSSH2_CALLBACK_AUTH_AGENT, (void*) ssh_auth_agent_callback);

        /* Request agent forwarding */
        if (libssh2_channel_request_auth_agent(ssh_client->term_channel))
            guac_client_log(client, GUAC_LOG_ERROR, "Agent forwarding request failed");
        else
            guac_client_log(client, GUAC_LOG_INFO, "Agent forwarding enabled.");
    }

    ssh_client->auth_agent = NULL;
#endif

    /* Start SFTP session as well, if enabled */
    if (settings->enable_sftp) {

        /* Create SSH session specific for SFTP */
        guac_client_log(client, GUAC_LOG_DEBUG, "Reconnecting for SFTP...");
        ssh_client->sftp_session =
            guac_common_ssh_create_session(client, settings->hostname,
                    settings->port, ssh_client->user);
        if (ssh_client->sftp_session == NULL) {
            /* Already aborted within guac_common_ssh_create_session() */
            return NULL;
        }

        /* Request SFTP */
        ssh_client->sftp_filesystem = guac_common_ssh_create_sftp_filesystem(
                    ssh_client->sftp_session, "/");

        /* Expose filesystem to connection owner */
        guac_client_for_owner(client,
                guac_common_ssh_expose_sftp_filesystem,
                ssh_client->sftp_filesystem);

        /* Init handlers for Guacamole-specific console codes */
        ssh_client->term->upload_path_handler = guac_sftp_set_upload_path;
        ssh_client->term->file_download_handler = guac_sftp_download_file;

        guac_client_log(client, GUAC_LOG_DEBUG, "SFTP session initialized");

    }

    /* Request PTY */
    if (libssh2_channel_request_pty_ex(ssh_client->term_channel, "linux", sizeof("linux")-1, NULL, 0,
            ssh_client->term->term_width, ssh_client->term->term_height, 0, 0)) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to allocate PTY.");
        return NULL;
    }

    /* If a command is specified, run that instead of a shell */
    if (settings->command != NULL) {
        if (libssh2_channel_exec(ssh_client->term_channel, settings->command)) {
            guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
                    "Unable to execute command.");
            return NULL;
        }
    }

    /* Otherwise, request a shell */
    else if (libssh2_channel_shell(ssh_client->term_channel)) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
                "Unable to associate shell with PTY.");
        return NULL;
    }

    /* Logged in */
    guac_client_log(client, GUAC_LOG_INFO, "SSH connection successful.");

    /* Start input thread */
    if (pthread_create(&(input_thread), NULL, ssh_input_thread, (void*) client)) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to start input thread");
        return NULL;
    }

    /* Set non-blocking */
    libssh2_session_set_blocking(ssh_client->session->session, 0);

    /* While data available, write to terminal */
    int bytes_read = 0;
    for (;;) {

        /* Track total amount of data read */
        int total_read = 0;

        pthread_mutex_lock(&(ssh_client->term_channel_lock));

        /* Stop reading at EOF */
        if (libssh2_channel_eof(ssh_client->term_channel)) {
            pthread_mutex_unlock(&(ssh_client->term_channel_lock));
            break;
        }

        /* Read terminal data */
        bytes_read = libssh2_channel_read(ssh_client->term_channel,
                buffer, sizeof(buffer));

        pthread_mutex_unlock(&(ssh_client->term_channel_lock));

        /* Attempt to write data received. Exit on failure. */
        if (bytes_read > 0) {
            int written = guac_terminal_write_stdout(ssh_client->term, buffer, bytes_read);
            if (written < 0)
                break;

            total_read += bytes_read;
        }

        else if (bytes_read < 0 && bytes_read != LIBSSH2_ERROR_EAGAIN)
            break;

#ifdef ENABLE_SSH_AGENT
        /* If agent open, handle any agent packets */
        if (ssh_client->auth_agent != NULL) {
            bytes_read = ssh_auth_agent_read(ssh_client->auth_agent);
            if (bytes_read > 0)
                total_read += bytes_read;
            else if (bytes_read < 0 && bytes_read != LIBSSH2_ERROR_EAGAIN)
                ssh_client->auth_agent = NULL;
        }
#endif

        /* Wait for more data if reads turn up empty */
        if (total_read == 0) {
            fd_set fds;
            struct timeval timeout;

            FD_ZERO(&fds);
            FD_SET(ssh_client->session->fd, &fds);

            /* Wait for one second */
            timeout.tv_sec = 1;
            timeout.tv_usec = 0;

            if (select(ssh_client->session->fd + 1, &fds,
                        NULL, NULL, &timeout) < 0)
                break;
        }

    }

    /* Kill client and Wait for input thread to die */
    guac_client_stop(client);
    pthread_join(input_thread, NULL);

    pthread_mutex_destroy(&ssh_client->term_channel_lock);

    guac_client_log(client, GUAC_LOG_INFO, "SSH connection ended.");
    return NULL;

}
Exemple #15
0
void *
CSubThread::Entry()
{
	fd_set fds;
	struct timeval tv;
	ssize_t len, wr;
	char buf[20480];
	int rc, i = 0;

	const char *shost = inet_ntoa(m_sin.sin_addr);
	unsigned int sport = ntohs(m_sin.sin_port);

	wxLogInfo(wxT("Forwarding connection from %s:%d to %s:%d"), wxString(inet_ntoa(m_sin.sin_addr), wxConvLibc).c_str(),
	          sport, m_remote_desthost.c_str(), m_remote_destport);

	/* Must use blocking here to avoid connect errors */
	//libssh2_session_set_blocking(m_subThreadSession, 1);

	while((m_channel = libssh2_channel_direct_tcpip_ex(m_subThreadSession, m_remote_desthost.mb_str(),
	                   m_remote_destport, shost, sport)) == NULL)
	{
		rc = libssh2_session_last_error(m_subThreadSession, NULL, NULL, 0);
		if (rc == LIBSSH2_ERROR_EAGAIN)
			Sleep(10);
		else
			break;
	}

	/* Must use non-blocking IO hereafter due to the current libssh2 API */
	libssh2_session_set_blocking(m_subThreadSession, 0);

	if (!m_channel)
	{
		wxLogInfo(_("SSH error: Could not open a direct-tcpip channel!"));
		goto shutdown;
	}

	while (1)
	{
		FD_ZERO(&fds);
		FD_SET(m_forwardsock, &fds);
		tv.tv_sec = 0;
		tv.tv_usec = 100000;
		rc = select(m_forwardsock + 1, &fds, NULL, NULL, &tv);
		memset(buf, 0, sizeof(buf));
		if (-1 == rc)
		{
			wxLogInfo(_("SSH error: select failed with error code %d"), wxSysErrorCode());
			goto shutdown;
		}
		if (rc && FD_ISSET(m_forwardsock, &fds))
		{
			len = recv(m_forwardsock, buf, sizeof(buf), 0);
			if (len < 0)
			{
				wxLogInfo(_("SSH error: read failed with error code %d"), wxSysErrorCode());
				goto shutdown;
			}
			else if (0 == len)
			{
				wxLogInfo(_("The client at %s:%d disconnected!"), wxString(inet_ntoa(m_sin.sin_addr), wxConvLibc).c_str(), sport);
				goto shutdown;
			}
			wr = 0;
			do
			{
				i = libssh2_channel_write(m_channel, buf, len);

				if (i < 0)
				{
					wxLogInfo(_("SSH error: libssh2_channel_write with error code %d"), i);
					goto shutdown;
				}
				wr += i;
			}
			while (i > 0 && wr < len);
		}
		while (1)
		{
			len = libssh2_channel_read(m_channel, buf, sizeof(buf));

			if (LIBSSH2_ERROR_EAGAIN == len)
				break;
			else if (len < 0)
			{
				wxLogInfo(_("SSH error: libssh2_channel_read with error code %d"), (int)len);
				goto shutdown;
			}
			wr = 0;
			while (wr < len)
			{
				i = send(m_forwardsock, buf + wr, len - wr, 0);
				if (i <= 0)
				{
					wxLogInfo(_("SSH error: write failed with error code %d"), wxSysErrorCode());
					goto shutdown;
				}
				wr += i;
			}
			if (libssh2_channel_eof(m_channel))
			{
				wxLogInfo(_("Connection at %s:%d disconnected by server"),
				          wxString(inet_ntoa(m_sin.sin_addr), wxConvLibc).c_str(), sport);
				goto shutdown;
			}
		}
	}
shutdown:
#ifdef WIN32
	closesocket(m_forwardsock);
#else
	close(m_forwardsock);
#endif

	if (m_channel)
	{
		libssh2_channel_close(m_channel);
		libssh2_channel_free(m_channel);
		m_channel = NULL;
	}

	return NULL;
}
Exemple #16
0
/*
 * scp_recv
 *
 * Open a channel and request a remote file via SCP
 *
 */
static LIBSSH2_CHANNEL *
scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
{
    int cmd_len;
    int rc;
    int tmp_err_code;
    const char *tmp_err_msg;

    if (session->scpRecv_state == libssh2_NB_state_idle) {
        session->scpRecv_mode = 0;
        session->scpRecv_size = 0;
        session->scpRecv_mtime = 0;
        session->scpRecv_atime = 0;

        session->scpRecv_command_len =
            _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb?1:0);

        session->scpRecv_command =
            LIBSSH2_ALLOC(session, session->scpRecv_command_len);

        if (!session->scpRecv_command) {
            _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                           "Unable to allocate a command buffer for "
                           "SCP session");
            return NULL;
        }

        snprintf((char *)session->scpRecv_command,
                 session->scpRecv_command_len, "scp -%sf ", sb?"p":"");

        cmd_len = strlen((char *)session->scpRecv_command);

        (void) shell_quotearg(path,
                              &session->scpRecv_command[cmd_len],
                              session->scpRecv_command_len - cmd_len);


        _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                       "Opening channel for SCP receive");

        session->scpRecv_state = libssh2_NB_state_created;
    }

    if (session->scpRecv_state == libssh2_NB_state_created) {
        /* Allocate a channel */
        session->scpRecv_channel =
            _libssh2_channel_open(session, "session",
                                  sizeof("session") - 1,
                                  LIBSSH2_CHANNEL_WINDOW_DEFAULT,
                                  LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
                                  0);
        if (!session->scpRecv_channel) {
            if (libssh2_session_last_errno(session) !=
                    LIBSSH2_ERROR_EAGAIN) {
                LIBSSH2_FREE(session, session->scpRecv_command);
                session->scpRecv_command = NULL;
                session->scpRecv_state = libssh2_NB_state_idle;
            }
            else {
                _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                               "Would block starting up channel");
            }
            return NULL;
        }

        session->scpRecv_state = libssh2_NB_state_sent;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent) {
        /* Request SCP for the desired file */
        rc = _libssh2_channel_process_startup(session->scpRecv_channel, "exec",
                                              sizeof("exec") - 1,
                                              (char *) session->scpRecv_command,
                                              session->scpRecv_command_len);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block requesting SCP startup");
            return NULL;
        } else if (rc) {
            LIBSSH2_FREE(session, session->scpRecv_command);
            session->scpRecv_command = NULL;
            goto scp_recv_error;
        }
        LIBSSH2_FREE(session, session->scpRecv_command);
        session->scpRecv_command = NULL;

        _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sending initial wakeup");
        /* SCP ACK */
        session->scpRecv_response[0] = '\0';

        session->scpRecv_state = libssh2_NB_state_sent1;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent1) {
        rc = _libssh2_channel_write(session->scpRecv_channel, 0,
                                    session->scpRecv_response, 1);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block sending initial wakeup");
            return NULL;
        } else if (rc != 1) {
            goto scp_recv_error;
        }

        /* Parse SCP response */
        session->scpRecv_response_len = 0;

        session->scpRecv_state = libssh2_NB_state_sent2;
    }

    if ((session->scpRecv_state == libssh2_NB_state_sent2)
            || (session->scpRecv_state == libssh2_NB_state_sent3)) {
        while (sb && (session->scpRecv_response_len <
                      LIBSSH2_SCP_RESPONSE_BUFLEN)) {
            unsigned char *s, *p;

            if (session->scpRecv_state == libssh2_NB_state_sent2) {
                rc = _libssh2_channel_read(session->scpRecv_channel, 0,
                                           (char *) session->
                                           scpRecv_response +
                                           session->scpRecv_response_len, 1);
                if (rc == LIBSSH2_ERROR_EAGAIN) {
                    _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                   "Would block waiting for SCP response");
                    return NULL;
                }
                else if (rc < 0) {
                    /* error, give up */
                    _libssh2_error(session, rc, "Failed reading SCP response");
                    goto scp_recv_error;
                }
                else if(rc == 0)
                    goto scp_recv_empty_channel;

                session->scpRecv_response_len++;

                if (session->scpRecv_response[0] != 'T') {
                    size_t err_len;
                    char *err_msg;

                    /* there can be
                       01 for warnings
                       02 for errors

                       The following string MUST be newline terminated
                    */
                    err_len =
                        _libssh2_channel_packet_data_len(session->
                                                         scpRecv_channel, 0);
                    err_msg = LIBSSH2_ALLOC(session, err_len + 1);
                    if (!err_msg) {
                        _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                       "Failed to get memory ");
                        goto scp_recv_error;
                    }

                    /* Read the remote error message */
                    (void)_libssh2_channel_read(session->scpRecv_channel, 0,
                                                err_msg, err_len);
                    /* If it failed for any reason, we ignore it anyway. */

                    /* zero terminate the error */
                    err_msg[err_len]=0;

                    _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                                   "got %02x %s", session->scpRecv_response[0],
                                   err_msg);

                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Failed to recv file");

                    LIBSSH2_FREE(session, err_msg);
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len > 1) &&
                        ((session->
                          scpRecv_response[session->scpRecv_response_len - 1] <
                          '0')
                         || (session->
                             scpRecv_response[session->scpRecv_response_len - 1] >
                             '9'))
                        && (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            ' ')
                        && (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            '\r')
                        && (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            '\n')) {
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid data in SCP response");
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len < 9)
                        || (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            '\n')) {
                    if (session->scpRecv_response_len ==
                            LIBSSH2_SCP_RESPONSE_BUFLEN) {
                        /* You had your chance */
                        _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                       "Unterminated response from SCP server");
                        goto scp_recv_error;
                    }
                    /* Way too short to be an SCP response, or not done yet,
                       short circuit */
                    continue;
                }

                /* We're guaranteed not to go under response_len == 0 by the
                   logic above */
                while ((session->
                        scpRecv_response[session->scpRecv_response_len - 1] ==
                        '\r')
                        || (session->
                            scpRecv_response[session->scpRecv_response_len -
                                             1] == '\n'))
                    session->scpRecv_response_len--;
                session->scpRecv_response[session->scpRecv_response_len] =
                    '\0';

                if (session->scpRecv_response_len < 8) {
                    /* EOL came too soon */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, "
                                   "too short" );
                    goto scp_recv_error;
                }

                s = session->scpRecv_response + 1;

                p = (unsigned char *) strchr((char *) s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, "
                                   "malformed mtime");
                    goto scp_recv_error;
                }

                *(p++) = '\0';
                /* Make sure we don't get fooled by leftover values */
                session->scpRecv_mtime = strtol((char *) s, NULL, 10);

                s = (unsigned char *) strchr((char *) p, ' ');
                if (!s || ((s - p) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, malformed mtime.usec");
                    goto scp_recv_error;
                }

                /* Ignore mtime.usec */
                s++;
                p = (unsigned char *) strchr((char *) s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, too short or malformed");
                    goto scp_recv_error;
                }

                *p = '\0';
                /* Make sure we don't get fooled by leftover values */
                session->scpRecv_atime = strtol((char *) s, NULL, 10);

                /* SCP ACK */
                session->scpRecv_response[0] = '\0';

                session->scpRecv_state = libssh2_NB_state_sent3;
            }

            if (session->scpRecv_state == libssh2_NB_state_sent3) {
                rc = _libssh2_channel_write(session->scpRecv_channel, 0,
                                            session->scpRecv_response, 1);
                if (rc == LIBSSH2_ERROR_EAGAIN) {
                    _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                   "Would block waiting to send SCP ACK");
                    return NULL;
                } else if (rc != 1) {
                    goto scp_recv_error;
                }

                _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                               "mtime = %ld, atime = %ld",
                               session->scpRecv_mtime, session->scpRecv_atime);

                /* We *should* check that atime.usec is valid, but why let
                   that stop use? */
                break;
            }
        }

        session->scpRecv_state = libssh2_NB_state_sent4;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent4) {
        session->scpRecv_response_len = 0;

        session->scpRecv_state = libssh2_NB_state_sent5;
    }

    if ((session->scpRecv_state == libssh2_NB_state_sent5)
            || (session->scpRecv_state == libssh2_NB_state_sent6)) {
        while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
            char *s, *p, *e = NULL;

            if (session->scpRecv_state == libssh2_NB_state_sent5) {
                rc = _libssh2_channel_read(session->scpRecv_channel, 0,
                                           (char *) session->
                                           scpRecv_response +
                                           session->scpRecv_response_len, 1);
                if (rc == LIBSSH2_ERROR_EAGAIN) {
                    _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                   "Would block waiting for SCP response");
                    return NULL;
                }
                else if (rc < 0) {
                    /* error, bail out*/
                    _libssh2_error(session, rc, "Failed reading SCP response");
                    goto scp_recv_error;
                }
                else if(rc == 0)
                    goto scp_recv_empty_channel;

                session->scpRecv_response_len++;

                if (session->scpRecv_response[0] != 'C') {
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server");
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len > 1) &&
                        (session->
                         scpRecv_response[session->scpRecv_response_len - 1] !=
                         '\r')
                        && (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            '\n')
                        &&
                        (session->
                         scpRecv_response[session->scpRecv_response_len - 1]
                         < 32)) {
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid data in SCP response");
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len < 7)
                        || (session->
                            scpRecv_response[session->scpRecv_response_len - 1] !=
                            '\n')) {
                    if (session->scpRecv_response_len ==
                            LIBSSH2_SCP_RESPONSE_BUFLEN) {
                        /* You had your chance */
                        _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                       "Unterminated response from SCP server");
                        goto scp_recv_error;
                    }
                    /* Way too short to be an SCP response, or not done yet,
                       short circuit */
                    continue;
                }

                /* We're guaranteed not to go under response_len == 0 by the
                   logic above */
                while ((session->
                        scpRecv_response[session->scpRecv_response_len - 1] ==
                        '\r')
                        || (session->
                            scpRecv_response[session->scpRecv_response_len -
                                             1] == '\n')) {
                    session->scpRecv_response_len--;
                }
                session->scpRecv_response[session->scpRecv_response_len] =
                    '\0';

                if (session->scpRecv_response_len < 6) {
                    /* EOL came too soon */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, too short");
                    goto scp_recv_error;
                }

                s = (char *) session->scpRecv_response + 1;

                p = strchr(s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, malformed mode");
                    goto scp_recv_error;
                }

                *(p++) = '\0';
                /* Make sure we don't get fooled by leftover values */

                session->scpRecv_mode = strtol(s, &e, 8);
                if (e && *e) {
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, invalid mode");
                    goto scp_recv_error;
                }

                s = strchr(p, ' ');
                if (!s || ((s - p) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, too short or malformed");
                    goto scp_recv_error;
                }

                *s = '\0';
                /* Make sure we don't get fooled by leftover values */
                session->scpRecv_size = scpsize_strtol(p, &e, 10);
                if (e && *e) {
                    _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                   "Invalid response from SCP server, invalid size");
                    goto scp_recv_error;
                }

                /* SCP ACK */
                session->scpRecv_response[0] = '\0';

                session->scpRecv_state = libssh2_NB_state_sent6;
            }

            if (session->scpRecv_state == libssh2_NB_state_sent6) {
                rc = _libssh2_channel_write(session->scpRecv_channel, 0,
                                            session->scpRecv_response, 1);
                if (rc == LIBSSH2_ERROR_EAGAIN) {
                    _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                   "Would block sending SCP ACK");
                    return NULL;
                } else if (rc != 1) {
                    goto scp_recv_error;
                }
                _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                               "mode = 0%lo size = %ld", session->scpRecv_mode,
                               session->scpRecv_size);

                /* We *should* check that basename is valid, but why let that
                   stop us? */
                break;
            }
        }

        session->scpRecv_state = libssh2_NB_state_sent7;
    }

    if (sb) {
        memset(sb, 0, sizeof(struct stat));

        sb->st_mtime = session->scpRecv_mtime;
        sb->st_atime = session->scpRecv_atime;
        sb->st_size = session->scpRecv_size;
        sb->st_mode = session->scpRecv_mode;
    }

    session->scpRecv_state = libssh2_NB_state_idle;
    return session->scpRecv_channel;

scp_recv_empty_channel:
    /* the code only jumps here as a result of a zero read from channel_read()
       so we check EOF status to avoid getting stuck in a loop */
    if(libssh2_channel_eof(session->scpRecv_channel))
        _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                       "Unexpected channel close");
    else
        return session->scpRecv_channel;
    /* fall-through */
scp_recv_error:
    tmp_err_code = session->err_code;
    tmp_err_msg = session->err_msg;
    while (libssh2_channel_free(session->scpRecv_channel) ==
            LIBSSH2_ERROR_EAGAIN);
    session->err_code = tmp_err_code;
    session->err_msg = tmp_err_msg;
    session->scpRecv_channel = NULL;
    session->scpRecv_state = libssh2_NB_state_idle;
    return NULL;
}
Exemple #17
0
/**
 * loop_and_copy (int infd, int outfd, struct seashell_connection* conn)
 * Copies data to/from the file descriptors and socket.
 *
 *
 * Arguments:
 *  infd, outfd - input/output file descriptors.
 *  conn - Seashell connection object.
 *
 * Returns:
 *  0 on clean disconnect, nonzero value otherwise.
 */
int loop_and_copy(int infd, int outfd, struct seashell_connection* conn) {
  struct timeval timeout;
  fd_set readfds;

  char buffer[4096];
  ssize_t start = 0, len = 0, rc = 0;
  int nfds = 1 + MAX(infd, conn->sockfd);

  while (1) {
    FD_ZERO(&readfds);
    FD_SET(conn->sockfd, &readfds);
    FD_SET(infd, &readfds);

    timeout.tv_sec = 10;
    timeout.tv_usec = 0;

    if (select(nfds, &readfds, NULL, NULL, &timeout) > 0) {
      /** We're OK only when we have something to read from and something to write to. */

      /**
       *  Something to read from remote - might block on write, this is OK.
       *  Time permitting, it might be nice to have a write queue and
       *  go through the select loop again for fairness,
       *  but it really doesn't matter.
       */
      if (FD_ISSET(conn->sockfd, &readfds)) {
        /** Do our reads in nonblocking mode as we may get payload data for
         *  some other stream. */
        seashell_set_nonblocking(conn);
        len = libssh2_channel_read(conn->channel, buffer, sizeof(buffer));
        seashell_set_blocking(conn);

        if (len == LIBSSH2_ERROR_EAGAIN) {
        }
        else if (len < 0) {
          return len;
        } else if (len > 0) {

          start = 0;

          while (len) {
            rc = write(outfd, buffer + start, len);
            if (rc < 0) {
              return rc;
            }
            len -= rc;
            start += rc;
          }
        }

        /** Drain stderr. */
        seashell_set_nonblocking(conn);
        len = libssh2_channel_read_stderr(conn->channel, buffer, sizeof(buffer));
        seashell_set_blocking(conn);
        if (len == LIBSSH2_ERROR_EAGAIN) {
        }
        else if (len < 0) {
          return len;
        } else if (len > 0) {
          start = 0;

          while (len) {
            rc = write(2, buffer + start, len);
            if (rc < 0) {
              return rc;
            }
            len -= rc;
            start += rc;
          }
        }
      }

      /**
       * Something to read from local - might block on write, this is OK.
       * See above for rationale, and libssh2_channel_write doesn't seem
       * to block nicely.  Oh well.
       */
      if (FD_ISSET(infd, &readfds)) {
        len = read(infd, buffer, sizeof(buffer));

        if (len < 0) {
          return len;
        } else if (len == 0) {
          return 0;
        } else {
          start = 0;

          while (len) {
            rc = libssh2_channel_write(conn->channel, buffer + start, len);
            if (rc < 0) {
              return rc;
            }
            len -= rc;
            start += rc;
          }
        }
      }
    }
    /**
     * And if we died...
     */
    if (libssh2_channel_eof(conn->channel) == 1) {
      return 0;
    }
  }
}
int ssh2_forward_port(const char *hostip,
                      const char *username,
                      const char *password,
                      int listenport,
                      const char *desthost,
                      int destport,
                      int *initialized,
                      int *finished,
                      char **errmsg)
{
    int rc, sock = -1, listensock = -1, forwardsock = -1, i;
    struct sockaddr_in sin;
    socklen_t sinlen;
    LIBSSH2_SESSION *session;
    LIBSSH2_CHANNEL *channel = NULL;
    const char *shost;
    unsigned int sport;
    fd_set fds;
    struct timeval tv;
    ssize_t len, wr;
    char buf[16384];
    struct StringBuffer *sberrmsg = new_string_buffer();

#ifdef WIN32
    char sockopt;
    WSADATA wsadata;

    WSAStartup(MAKEWORD(2,0), &wsadata);
#else
    int sockopt;
#endif

    rc = libssh2_init (0);
    if (rc != 0) {
        sbprintf (sberrmsg, "libssh2 initialization failed (%d)\n", rc);
        return 1;
    }

    /* Connect to SSH server */
    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr(hostip))) {
        perror("inet_addr");
        return -1;
    }
    sin.sin_port = htons(22);
    if (connect(sock, (struct sockaddr*)(&sin),
                sizeof(struct sockaddr_in)) != 0) {
        sbprintf(sberrmsg, "failed to connect!\n");
        return -1;
    }

    /* Create a session instance */
    session = libssh2_session_init();
    if(!session) {
        sbprintf(sberrmsg, "Could not initialize SSH session!\n");
        return -1;
    }

    /* ... start it up. This will trade welcome banners, exchange keys,
     * and setup crypto, compression, and MAC layers
     */
    rc = libssh2_session_handshake(session, sock);
    if(rc) {
        sbprintf(sberrmsg, "Error when starting up SSH session: %d\n", rc);
        return -1;
    }

    if (libssh2_userauth_password(session, username, password)) {
        sbprintf(sberrmsg, "Authentication by password failed.\n");
        goto shutdown;
    }

    listensock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    sin.sin_family = AF_INET;
    sin.sin_port = htons(listenport);
    if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr("127.0.0.1"))) {
        sbprintf(sberrmsg, "inet_addr: %s.", strerror(errno));
        goto shutdown;
    }
    sockopt = 1;
    setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
    sinlen=sizeof(sin);
    if (-1 == bind(listensock, (struct sockaddr *)&sin, sinlen)) {
        sbprintf(sberrmsg, "bind: %s.", strerror(errno));
        goto shutdown;
    }
    if (-1 == listen(listensock, 2)) {
        sbprintf(sberrmsg, "listen: %s.", strerror(errno));
        goto shutdown;
    }

    printf("Waiting for TCP connection on %s:%d...\n",
        inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
    *initialized = 1;

    forwardsock = accept(listensock, (struct sockaddr *)&sin, &sinlen);
    if (-1 == forwardsock) {
        sbprintf(sberrmsg, "accept: %s.", strerror(errno));
        goto shutdown;
    }

    shost = inet_ntoa(sin.sin_addr);
    sport = ntohs(sin.sin_port);

    printf("Forwarding connection from %s:%d here to remote %s:%d\n", shost,
        sport, desthost, destport);

    channel = libssh2_channel_direct_tcpip_ex(session, desthost,
        destport, shost, sport);
    if (!channel) {
        sbprintf(sberrmsg, "Could not open the direct-tcpip channel!\n"
                "(Note that this can be a problem at the server!"
                " Please review the server logs.)\n");
        goto shutdown;
    }

    /* Must use non-blocking IO hereafter due to the current libssh2 API */
    libssh2_session_set_blocking(session, 0);

    while (1) {
        if(*finished) libssh2_channel_send_eof(channel);
        FD_ZERO(&fds);
        FD_SET(forwardsock, &fds);
        tv.tv_sec = 0;
        tv.tv_usec = 100000;
        rc = select(forwardsock + 1, &fds, NULL, NULL, &tv);
        if (-1 == rc) {
            sbprintf(sberrmsg, "select: %s.", strerror(errno));
            goto shutdown;
        }
        if (rc && FD_ISSET(forwardsock, &fds)) {
            len = recv(forwardsock, buf, sizeof(buf), 0);
            if (len < 0) {
                perror("read");
                goto shutdown;
            } else if (0 == len) {
                printf("The client at %s:%d disconnected!\n", shost, sport);
                goto shutdown;
            }
            wr = 0;
            do {
                i = libssh2_channel_write(channel, buf, len);
                if (i < 0) {
                    sbprintf(sberrmsg, "libssh2_channel_write: %d\n", i);
                    goto shutdown;
                }
                wr += i;
            } while(i > 0 && wr < len);
        }
        while (1) {
            len = libssh2_channel_read(channel, buf, sizeof(buf));
            if (LIBSSH2_ERROR_EAGAIN == len)
                break;
            else if (len < 0) {
                sbprintf(sberrmsg, "libssh2_channel_read: %d", (int)len);
                goto shutdown;
            }
            wr = 0;
            while (wr < len) {
                i = send(forwardsock, buf + wr, len - wr, 0);
                if (i <= 0) {
                    perror("write");
                    goto shutdown;
                }
                wr += i;
            }
            if (libssh2_channel_eof(channel)) {
                printf("The server at %s:%d disconnected!\n",
                    desthost, destport);
                goto shutdown;
            }
        }
    }

shutdown:
 fprintf(stderr, "finished = %d\n", *finished);
#ifdef WIN32
    closesocket(forwardsock);
    closesocket(listensock);
#else
    close(forwardsock);
    close(listensock);
#endif
    if (channel)
        libssh2_channel_free(channel);
    libssh2_session_disconnect(session, "Client disconnecting normally");
    libssh2_session_free(session);

#ifdef WIN32
    closesocket(sock);
#else
    close(sock);
#endif

    libssh2_exit();

    if(string_buffer_is_empty(sberrmsg)) {
       free_string_buffer(sberrmsg, 1);
       return 0;
    }

    *errmsg = free_string_buffer(sberrmsg, 0);
    return 1;
}
Exemple #19
0
/*
 * scp_send()
 *
 * Send a file using SCP
 *
 */
static LIBSSH2_CHANNEL *
scp_send(LIBSSH2_SESSION * session, const char *path, int mode,
         libssh2_int64_t size, time_t mtime, time_t atime)
{
    int cmd_len;
    int rc;
    int tmp_err_code;
    const char *tmp_err_msg;

    if (session->scpSend_state == libssh2_NB_state_idle) {
        session->scpSend_command_len =
            _libssh2_shell_quotedsize(path) + sizeof("scp -t ") +
            ((mtime || atime)?1:0);

        session->scpSend_command =
            LIBSSH2_ALLOC(session, session->scpSend_command_len);
        if (!session->scpSend_command) {
            _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                           "Unable to allocate a command buffer for scp session");
            return NULL;
        }

        snprintf((char *)session->scpSend_command, session->scpSend_command_len,
                 "scp -%st ", (mtime || atime)?"p":"");

        cmd_len = strlen((char *)session->scpSend_command);

        (void)shell_quotearg(path,
                             &session->scpSend_command[cmd_len],
                             session->scpSend_command_len - cmd_len);

        session->scpSend_command[session->scpSend_command_len - 1] = '\0';

        _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                       "Opening channel for SCP send");
        /* Allocate a channel */

        session->scpSend_state = libssh2_NB_state_created;
    }

    if (session->scpSend_state == libssh2_NB_state_created) {
        session->scpSend_channel =
            _libssh2_channel_open(session, "session", sizeof("session") - 1,
                                  LIBSSH2_CHANNEL_WINDOW_DEFAULT,
                                  LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
        if (!session->scpSend_channel) {
            if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
                /* previous call set libssh2_session_last_error(), pass it
                   through */
                LIBSSH2_FREE(session, session->scpSend_command);
                session->scpSend_command = NULL;
                session->scpSend_state = libssh2_NB_state_idle;
            }
            else {
                _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                               "Would block starting up channel");
            }
            return NULL;
        }

        session->scpSend_state = libssh2_NB_state_sent;
    }

    if (session->scpSend_state == libssh2_NB_state_sent) {
        /* Request SCP for the desired file */
        rc = _libssh2_channel_process_startup(session->scpSend_channel, "exec",
                                              sizeof("exec") - 1,
                                              (char *) session->scpSend_command,
                                              session->scpSend_command_len);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block requesting SCP startup");
            return NULL;
        }
        else if (rc) {
            /* previous call set libssh2_session_last_error(), pass it
               through */
            LIBSSH2_FREE(session, session->scpSend_command);
            session->scpSend_command = NULL;
            _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                           "Unknown error while getting error string");
            goto scp_send_error;
        }
        LIBSSH2_FREE(session, session->scpSend_command);
        session->scpSend_command = NULL;

        session->scpSend_state = libssh2_NB_state_sent1;
    }

    if (session->scpSend_state == libssh2_NB_state_sent1) {
        /* Wait for ACK */
        rc = _libssh2_channel_read(session->scpSend_channel, 0,
                                   (char *) session->scpSend_response, 1);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block waiting for response from remote");
            return NULL;
        }
        else if (rc < 0) {
            _libssh2_error(session, rc, "SCP failure");
            goto scp_send_error;
        }
        else if(!rc)
            /* remain in the same state */
            goto scp_send_empty_channel;
        else if (session->scpSend_response[0] != 0) {
            _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                           "Invalid ACK response from remote");
            goto scp_send_error;
        }
        if (mtime || atime) {
            /* Send mtime and atime to be used for file */
            session->scpSend_response_len =
                snprintf((char *) session->scpSend_response,
                         LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n",
                         (long)mtime, (long)atime);
            _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s",
                           session->scpSend_response);
        }

        session->scpSend_state = libssh2_NB_state_sent2;
    }

    /* Send mtime and atime to be used for file */
    if (mtime || atime) {
        if (session->scpSend_state == libssh2_NB_state_sent2) {
            rc = _libssh2_channel_write(session->scpSend_channel, 0,
                                        session->scpSend_response,
                                        session->scpSend_response_len);
            if (rc == LIBSSH2_ERROR_EAGAIN) {
                _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                               "Would block sending time data for SCP file");
                return NULL;
            } else if (rc != (int)session->scpSend_response_len) {
                _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                               "Unable to send time data for SCP file");
                goto scp_send_error;
            }

            session->scpSend_state = libssh2_NB_state_sent3;
        }

        if (session->scpSend_state == libssh2_NB_state_sent3) {
            /* Wait for ACK */
            rc = _libssh2_channel_read(session->scpSend_channel, 0,
                                       (char *) session->scpSend_response, 1);
            if (rc == LIBSSH2_ERROR_EAGAIN) {
                _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                               "Would block waiting for response");
                return NULL;
            }
            else if (rc < 0) {
                _libssh2_error(session, rc, "SCP failure");
                goto scp_send_error;
            }
            else if(!rc)
                /* remain in the same state */
                goto scp_send_empty_channel;
            else if (session->scpSend_response[0] != 0) {
                _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                               "Invalid SCP ACK response");
                goto scp_send_error;
            }

            session->scpSend_state = libssh2_NB_state_sent4;
        }
    } else {
        if (session->scpSend_state == libssh2_NB_state_sent2) {
            session->scpSend_state = libssh2_NB_state_sent4;
        }
    }

    if (session->scpSend_state == libssh2_NB_state_sent4) {
        /* Send mode, size, and basename */
        const char *base = strrchr(path, '/');
        if (base)
            base++;
        else
            base = path;

        session->scpSend_response_len =
            snprintf((char *) session->scpSend_response,
                     LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %"
                     LIBSSH2_INT64_T_FORMAT " %s\n", mode,
                     size, base);
        _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s",
                       session->scpSend_response);

        session->scpSend_state = libssh2_NB_state_sent5;
    }

    if (session->scpSend_state == libssh2_NB_state_sent5) {
        rc = _libssh2_channel_write(session->scpSend_channel, 0,
                                    session->scpSend_response,
                                    session->scpSend_response_len);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block send core file data for SCP file");
            return NULL;
        } else if (rc != (int)session->scpSend_response_len) {
            _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                           "Unable to send core file data for SCP file");
            goto scp_send_error;
        }

        session->scpSend_state = libssh2_NB_state_sent6;
    }

    if (session->scpSend_state == libssh2_NB_state_sent6) {
        /* Wait for ACK */
        rc = _libssh2_channel_read(session->scpSend_channel, 0,
                                   (char *) session->scpSend_response, 1);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                           "Would block waiting for response");
            return NULL;
        }
        else if (rc < 0) {
            _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                           "Invalid ACK response from remote");
            goto scp_send_error;
        }
        else if (rc == 0)
            goto scp_send_empty_channel;

        else if (session->scpSend_response[0] != 0) {
            size_t err_len;
            char *err_msg;

            err_len =
                _libssh2_channel_packet_data_len(session->scpSend_channel, 0);
            err_msg = LIBSSH2_ALLOC(session, err_len + 1);
            if (!err_msg) {
                _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                               "failed to get memory");
                goto scp_send_error;
            }

            /* Read the remote error message */
            rc = _libssh2_channel_read(session->scpSend_channel, 0,
                                       err_msg, err_len);
            if (rc > 0) {
                err_msg[err_len]=0;
                _libssh2_debug(session, LIBSSH2_TRACE_SCP,
                               "got %02x %s", session->scpSend_response[0],
                               err_msg);
            }
            LIBSSH2_FREE(session, err_msg);
            _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                           "failed to send file");
            goto scp_send_error;
        }
    }

    session->scpSend_state = libssh2_NB_state_idle;
    return session->scpSend_channel;

scp_send_empty_channel:
    /* the code only jumps here as a result of a zero read from channel_read()
       so we check EOF status to avoid getting stuck in a loop */
    if(libssh2_channel_eof(session->scpSend_channel)) {
        _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                       "Unexpected channel close");
    }
    else
        return session->scpSend_channel;
    /* fall-through */
scp_send_error:
    tmp_err_code = session->err_code;
    tmp_err_msg = session->err_msg;
    while (libssh2_channel_free(session->scpSend_channel) ==
            LIBSSH2_ERROR_EAGAIN);
    session->err_code = tmp_err_code;
    session->err_msg = tmp_err_msg;
    session->scpSend_channel = NULL;
    session->scpSend_state = libssh2_NB_state_idle;
    return NULL;
}
Exemple #20
0
int main(int argc, char *argv[])
{
    int rc, i, auth = AUTH_NONE;
    struct sockaddr_in sin;
    socklen_t sinlen = sizeof(sin);
    const char *fingerprint;
    char *userauthlist;
    LIBSSH2_SESSION *session;
    LIBSSH2_LISTENER *listener = NULL;
    LIBSSH2_CHANNEL *channel = NULL;
    fd_set fds;
    struct timeval tv;
    ssize_t len, wr;
    char buf[16384];

#ifdef WIN32
    SOCKET sock = INVALID_SOCKET, forwardsock = INVALID_SOCKET;
    WSADATA wsadata;
    int err;

    err = WSAStartup(MAKEWORD(2,0), &wsadata);
    if (err != 0) {
        fprintf(stderr, "WSAStartup failed with error: %d\n", err);
        return 1;
    }
#else
    int sock = -1, forwardsock = -1;
#endif

    if (argc > 1)
        server_ip = argv[1];
    if (argc > 2)
        username = argv[2];
    if (argc > 3)
        password = argv[3];
    if (argc > 4)
        remote_listenhost = argv[4];
    if (argc > 5)
        remote_wantport = atoi(argv[5]);
    if (argc > 6)
        local_destip = argv[6];
    if (argc > 7)
        local_destport = atoi(argv[7]);

    rc = libssh2_init (0);
    if (rc != 0) {
        fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
        return 1;
    }

    /* Connect to SSH server */
    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
#ifdef WIN32
    if (sock == INVALID_SOCKET) {
        fprintf(stderr, "failed to open socket!\n");
        return -1;
    }
#else
    if (sock == -1) {
        perror("socket");
        return -1;
    }
#endif

    sin.sin_family = AF_INET;
    if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr(server_ip))) {
        perror("inet_addr");
        return -1;
    }
    sin.sin_port = htons(22);
    if (connect(sock, (struct sockaddr*)(&sin),
                sizeof(struct sockaddr_in)) != 0) {
        fprintf(stderr, "failed to connect!\n");
        return -1;
    }

    /* Create a session instance */
    session = libssh2_session_init();
    if(!session) {
        fprintf(stderr, "Could not initialize SSH session!\n");
        return -1;
    }

    /* ... start it up. This will trade welcome banners, exchange keys,
     * and setup crypto, compression, and MAC layers
     */
    rc = libssh2_session_handshake(session, sock);
    if(rc) {
        fprintf(stderr, "Error when starting up SSH session: %d\n", rc);
        return -1;
    }

    /* At this point we havn't yet authenticated.  The first thing to do
     * is check the hostkey's fingerprint against our known hosts Your app
     * may have it hard coded, may go to a file, may present it to the
     * user, that's your call
     */
    fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
    fprintf(stderr, "Fingerprint: ");
    for(i = 0; i < 20; i++)
        fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
    fprintf(stderr, "\n");

    /* check what authentication methods are available */
    userauthlist = libssh2_userauth_list(session, username, strlen(username));
    fprintf(stderr, "Authentication methods: %s\n", userauthlist);
    if (strstr(userauthlist, "password"))
        auth |= AUTH_PASSWORD;
    if (strstr(userauthlist, "publickey"))
        auth |= AUTH_PUBLICKEY;

    /* check for options */
    if(argc > 8) {
        if ((auth & AUTH_PASSWORD) && !strcasecmp(argv[8], "-p"))
            auth = AUTH_PASSWORD;
        if ((auth & AUTH_PUBLICKEY) && !strcasecmp(argv[8], "-k"))
            auth = AUTH_PUBLICKEY;
    }

    if (auth & AUTH_PASSWORD) {
        if (libssh2_userauth_password(session, username, password)) {
            fprintf(stderr, "Authentication by password failed.\n");
            goto shutdown;
        }
    } else if (auth & AUTH_PUBLICKEY) {
        if (libssh2_userauth_publickey_fromfile(session, username, keyfile1,
                                                keyfile2, password)) {
            fprintf(stderr, "\tAuthentication by public key failed!\n");
            goto shutdown;
        }
        fprintf(stderr, "\tAuthentication by public key succeeded.\n");
    } else {
        fprintf(stderr, "No supported authentication methods found!\n");
        goto shutdown;
    }

    fprintf(stderr, "Asking server to listen on remote %s:%d\n",
        remote_listenhost, remote_wantport);

    listener = libssh2_channel_forward_listen_ex(session, remote_listenhost,
        remote_wantport, &remote_listenport, 1);
    if (!listener) {
        fprintf(stderr, "Could not start the tcpip-forward listener!\n"
                "(Note that this can be a problem at the server!"
                " Please review the server logs.)\n");
        goto shutdown;
    }

    fprintf(stderr, "Server is listening on %s:%d\n", remote_listenhost,
        remote_listenport);

    fprintf(stderr, "Waiting for remote connection\n");
    channel = libssh2_channel_forward_accept(listener);
    if (!channel) {
        fprintf(stderr, "Could not accept connection!\n"
                "(Note that this can be a problem at the server!"
                " Please review the server logs.)\n");
        goto shutdown;
    }

    fprintf(stderr,
        "Accepted remote connection. Connecting to local server %s:%d\n",
        local_destip, local_destport);
    forwardsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
#ifdef WIN32
    if (forwardsock == INVALID_SOCKET) {
        fprintf(stderr, "failed to open forward socket!\n");
        goto shutdown;
    }
#else
    if (forwardsock == -1) {
        perror("socket");
        goto shutdown;
    }
#endif

    sin.sin_family = AF_INET;
    sin.sin_port = htons(local_destport);
    if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr(local_destip))) {
        perror("inet_addr");
        goto shutdown;
    }
    if (-1 == connect(forwardsock, (struct sockaddr *)&sin, sinlen)) {
        perror("connect");
        goto shutdown;
    }

    fprintf(stderr, "Forwarding connection from remote %s:%d to local %s:%d\n",
        remote_listenhost, remote_listenport, local_destip, local_destport);

    /* Must use non-blocking IO hereafter due to the current libssh2 API */
    libssh2_session_set_blocking(session, 0);

    while (1) {
        FD_ZERO(&fds);
        FD_SET(forwardsock, &fds);
        tv.tv_sec = 0;
        tv.tv_usec = 100000;
        rc = select(forwardsock + 1, &fds, NULL, NULL, &tv);
        if (-1 == rc) {
            perror("select");
            goto shutdown;
        }
        if (rc && FD_ISSET(forwardsock, &fds)) {
            len = recv(forwardsock, buf, sizeof(buf), 0);
            if (len < 0) {
                perror("read");
                goto shutdown;
            } else if (0 == len) {
                fprintf(stderr, "The local server at %s:%d disconnected!\n",
                    local_destip, local_destport);
                goto shutdown;
            }
            wr = 0;
            do {
                i = libssh2_channel_write(channel, buf, len);
                if (i < 0) {
                    fprintf(stderr, "libssh2_channel_write: %d\n", i);
                    goto shutdown;
                }
                wr += i;
            } while(i > 0 && wr < len);
        }
        while (1) {
            len = libssh2_channel_read(channel, buf, sizeof(buf));
            if (LIBSSH2_ERROR_EAGAIN == len)
                break;
            else if (len < 0) {
                fprintf(stderr, "libssh2_channel_read: %d", (int)len);
                goto shutdown;
            }
            wr = 0;
            while (wr < len) {
                i = send(forwardsock, buf + wr, len - wr, 0);
                if (i <= 0) {
                    perror("write");
                    goto shutdown;
                }
                wr += i;
            }
            if (libssh2_channel_eof(channel)) {
                fprintf(stderr, "The remote client at %s:%d disconnected!\n",
                    remote_listenhost, remote_listenport);
                goto shutdown;
            }
        }
    }

shutdown:
#ifdef WIN32
    closesocket(forwardsock);
#else
    close(forwardsock);
#endif
    if (channel)
        libssh2_channel_free(channel);
    if (listener)
        libssh2_channel_forward_cancel(listener);
    libssh2_session_disconnect(session, "Client disconnecting normally");
    libssh2_session_free(session);

#ifdef WIN32
    closesocket(sock);
#else
    close(sock);
#endif

    libssh2_exit();

    return 0;
}
Exemple #21
-1
QString Parser::sshRequest(QString commandline)
{
    QString host_ip(this->sharedHost);
    QString user_name=this->sharedUser;
    QString pass_word=this->sharedPass;

    //---------- connection --------------
    int libssh2_error = libssh2_init(0);
    if(libssh2_error)
    {
        qDebug("libssh2_init() error: %d", libssh2_error);
        //return -2;
    }

    QTcpSocket socket;
    socket.connectToHost(host_ip, 22);
    if(!socket.waitForConnected())
    {
        qDebug("Error connecting to host %s", host_ip.toLocal8Bit().constData());
        //return -1;
    }

    LIBSSH2_SESSION *session = libssh2_session_init();
    if(!session)
    {
        qDebug("libssh2_session_init() failed");
        //return -2;
    }

    libssh2_error = libssh2_session_startup(session, socket.socketDescriptor());
    if(libssh2_error)
    {
        qDebug("libssh2_session_startup() error: %d", libssh2_error);
        //return -3;
    }

    {
    /* At this point we havn't yet authenticated.  The first thing to do
     * is check the hostkey's fingerprint against our known hosts Your app
     * may have it hard coded, may go to a file, may present it to the
     * user, that's your call
     */
    const char *fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
    }

    libssh2_userauth_list(session, user_name.toLocal8Bit().constData(), user_name.toLocal8Bit().length());
    if(libssh2_userauth_password(
        session,
        user_name.toLocal8Bit().constData(),
        pass_word.toLocal8Bit().constData()
    ))
    {
        qDebug("Password authentication failed");

        socket.disconnectFromHost();
        libssh2_session_disconnect(session, "Client disconnecting for error");
        libssh2_session_free(session);
        libssh2_exit();

        //return -4;
    }

    // command channel
    //------------setup channel ----------------------
    LIBSSH2_CHANNEL *channel = NULL;
    channel = libssh2_channel_open_session(session);
    int rc;
    if ( channel == NULL )
    {
        qDebug()<<"Failed to open a new channel\n";
        socket.disconnectFromHost();
        //return -1;
    }
    libssh2_channel_set_blocking(channel, 1);
    while ((rc=libssh2_channel_exec(channel, commandline.toLocal8Bit().constData()))==LIBSSH2_ERROR_EAGAIN );
    if (rc)
    {
        //return -1;
    }

    //-------read channel-----------
    int read;
    QByteArray byte_array;
    byte_array.resize(4096);
    char* buffer=byte_array.data();
    int buffer_size=byte_array.size();

    QString myOutPut;

    while(true)
    {
        {
            read = libssh2_channel_read(channel, buffer, buffer_size);
            QByteArray debug = QByteArray(buffer, read);

            //qDebug()<<"STDOUT: "<<debug.constData();
            myOutPut = debug.constData();
            qDebug() << myOutPut;
            if(LIBSSH2_ERROR_EAGAIN == read)
            {
                qDebug("LIBSSH2_ERROR_EAGAIN");
                break;
            }
            else if(read  < 0)
            {
                qDebug(" error reading from channel");
                closeChannel(channel);
                goto next_channel;
            }

        }
        {
            read = libssh2_channel_read_stderr(channel, buffer, buffer_size);
            QByteArray debug = QByteArray(buffer, read);
            qDebug()<<"STDERR: "<<debug.constData();
            if(LIBSSH2_ERROR_EAGAIN == read)
            {
                qDebug("LIBSSH2_ERROR_EAGAIN");
                break;
            }
            else if(read  < 0)
            {
                qDebug(" error reading from channel");
                closeChannel(channel);
                goto next_channel;
            }

        }

        int i=0;

        i = libssh2_channel_eof(channel);
        if(i)
        {
            qDebug("libssh2_channel_eof %i", i);
            closeChannel(channel);
            goto next_channel;
        }
    }
next_channel:

    //------------ clean session
    socket.disconnectFromHost();

    libssh2_session_disconnect(session, "Client disconnecting normally");
    libssh2_session_free(session);
    libssh2_exit();

    return myOutPut;
}