Remove core SSH client code. Refactor message handler to handle pipe for STDOUT. Refactor key and clipboard handlers to handle pipe for STDIN.
This commit is contained in:
parent
791da3dc81
commit
ec845a812a
@ -48,21 +48,44 @@
|
||||
#include "terminal.h"
|
||||
#include "cursor.h"
|
||||
|
||||
/**
|
||||
* SSH-specific client data.
|
||||
*/
|
||||
typedef struct ssh_guac_client_data {
|
||||
|
||||
ssh_session session;
|
||||
ssh_channel term_channel;
|
||||
|
||||
/**
|
||||
* The terminal which will render all output from the SSH client.
|
||||
*/
|
||||
guac_terminal* term;
|
||||
|
||||
/**
|
||||
* The current contents of the clipboard.
|
||||
*/
|
||||
char* clipboard_data;
|
||||
|
||||
char password[1024];
|
||||
int password_length;
|
||||
|
||||
/**
|
||||
* Whether the control key is currently being held down.
|
||||
*/
|
||||
int mod_ctrl;
|
||||
|
||||
/**
|
||||
* The current mouse button state.
|
||||
*/
|
||||
int mouse_mask;
|
||||
|
||||
/**
|
||||
* Pipe which will be used to provide STDOUT to the SSH client.
|
||||
*/
|
||||
int stdout_pipe_fd[2];
|
||||
|
||||
/**
|
||||
* Pipe which will be used to provide STDIN to the SSH client.
|
||||
*/
|
||||
int stdin_pipe_fd[2];
|
||||
|
||||
/**
|
||||
* The cached I-bar cursor.
|
||||
*/
|
||||
@ -80,7 +103,5 @@ typedef struct ssh_guac_client_data {
|
||||
|
||||
} ssh_guac_client_data;
|
||||
|
||||
int ssh_guac_client_auth(guac_client* client, const char* password);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -38,12 +38,12 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/error.h>
|
||||
|
||||
#include "ssh_client.h"
|
||||
#include "ssh_handlers.h"
|
||||
@ -59,53 +59,6 @@ const char* GUAC_CLIENT_ARGS[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
int ssh_guac_client_password_key_handler(guac_client* client, int keysym, int pressed) {
|
||||
|
||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||
|
||||
/* If key pressed */
|
||||
if (pressed) {
|
||||
|
||||
/* If simple ASCII key */
|
||||
if (keysym >= 0x00 && keysym <= 0xFF) {
|
||||
/* Add to password */
|
||||
client_data->password[client_data->password_length++] = keysym;
|
||||
guac_terminal_write(client_data->term, "*", 1);
|
||||
guac_terminal_display_flush(client_data->term->display);
|
||||
guac_socket_flush(client->socket);
|
||||
}
|
||||
else if (keysym == 0xFF08) {
|
||||
|
||||
if (client_data->password_length > 0) {
|
||||
client_data->password_length--;
|
||||
|
||||
/* Backspace */
|
||||
guac_terminal_write(client_data->term, "\x08\x1B[K", 4);
|
||||
guac_terminal_display_flush(client_data->term->display);
|
||||
guac_socket_flush(client->socket);
|
||||
}
|
||||
|
||||
}
|
||||
else if (keysym == 0xFF0D) {
|
||||
|
||||
/* Finish password */
|
||||
client_data->password[client_data->password_length] = '\0';
|
||||
|
||||
/* Clear screen */
|
||||
guac_terminal_write(client_data->term, "\x1B[2J\x1B[1;1H", 10);
|
||||
guac_terminal_display_flush(client_data->term->display);
|
||||
guac_socket_flush(client->socket);
|
||||
|
||||
return ssh_guac_client_auth(client, client_data->password);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_client_init(guac_client* client, int argc, char** argv) {
|
||||
|
||||
guac_socket* socket = client->socket;
|
||||
@ -135,111 +88,44 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
|
||||
|
||||
guac_socket_flush(socket);
|
||||
|
||||
/* Open SSH session */
|
||||
client_data->session = ssh_new();
|
||||
if (client_data->session == NULL) {
|
||||
guac_protocol_send_error(socket, "Unable to create SSH session.");
|
||||
guac_socket_flush(socket);
|
||||
/* Open STDOUT pipe */
|
||||
if (pipe(client_data->stdout_pipe_fd)) {
|
||||
guac_error = GUAC_STATUS_SEE_ERRNO;
|
||||
guac_error_message = "Unable to open pipe for STDOUT";
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set session options */
|
||||
ssh_options_set(client_data->session, SSH_OPTIONS_HOST, argv[0]);
|
||||
ssh_options_set(client_data->session, SSH_OPTIONS_USER, argv[1]);
|
||||
/* Redirect STDOUT to pipe */
|
||||
if (dup2(client_data->stdout_pipe_fd[1], STDOUT_FILENO) < 0) {
|
||||
guac_error = GUAC_STATUS_SEE_ERRNO;
|
||||
guac_error_message = "Unable redirect STDOUT";
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Connect */
|
||||
if (ssh_connect(client_data->session) != SSH_OK) {
|
||||
guac_protocol_send_error(socket, "Unable to connect via SSH.");
|
||||
guac_socket_flush(socket);
|
||||
/* Open STDIN pipe */
|
||||
if (pipe(client_data->stdin_pipe_fd)) {
|
||||
guac_error = GUAC_STATUS_SEE_ERRNO;
|
||||
guac_error_message = "Unable to open pipe for STDIN";
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Redirect STDIN to pipe */
|
||||
if (dup2(client_data->stdin_pipe_fd[0], STDIN_FILENO) < 0) {
|
||||
guac_error = GUAC_STATUS_SEE_ERRNO;
|
||||
guac_error_message = "Unable redirect STDIN";
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set basic handlers */
|
||||
client->free_handler = ssh_guac_client_free_handler;
|
||||
client->size_handler = ssh_guac_client_size_handler;
|
||||
|
||||
/* If password provided, authenticate now */
|
||||
if (argv[2][0] != '\0')
|
||||
return ssh_guac_client_auth(client, argv[2]);
|
||||
|
||||
/* Otherwise, prompt for password */
|
||||
else {
|
||||
|
||||
client_data->password_length = 0;
|
||||
guac_terminal_write(client_data->term, "Password: ", 10);
|
||||
guac_terminal_display_flush(client_data->term->display);
|
||||
guac_socket_flush(client->socket);
|
||||
|
||||
client->key_handler = ssh_guac_client_password_key_handler;
|
||||
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int ssh_guac_client_auth(guac_client* client, const char* password) {
|
||||
|
||||
guac_socket* socket = client->socket;
|
||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||
guac_terminal* term = client_data->term;
|
||||
|
||||
/* Authenticate */
|
||||
if (ssh_userauth_password(client_data->session, NULL, password) != SSH_AUTH_SUCCESS) {
|
||||
guac_protocol_send_error(socket, "SSH auth failed.");
|
||||
guac_socket_flush(socket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Open channel for terminal */
|
||||
client_data->term_channel = channel_new(client_data->session);
|
||||
if (client_data->term_channel == NULL) {
|
||||
guac_protocol_send_error(socket, "Unable to open channel.");
|
||||
guac_socket_flush(socket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Open session for channel */
|
||||
if (channel_open_session(client_data->term_channel) != SSH_OK) {
|
||||
guac_protocol_send_error(socket, "Unable to open channel session.");
|
||||
guac_socket_flush(socket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Request PTY */
|
||||
if (channel_request_pty(client_data->term_channel) != SSH_OK) {
|
||||
guac_protocol_send_error(socket, "Unable to allocate PTY for channel.");
|
||||
guac_socket_flush(socket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Request PTY size */
|
||||
if (channel_change_pty_size(client_data->term_channel, term->term_width, term->term_height) != SSH_OK) {
|
||||
guac_protocol_send_error(socket, "Unable to change PTY size.");
|
||||
guac_socket_flush(socket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Request shell */
|
||||
if (channel_request_shell(client_data->term_channel) != SSH_OK) {
|
||||
guac_protocol_send_error(socket, "Unable to associate shell with PTY.");
|
||||
guac_socket_flush(socket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
guac_client_log_info(client, "SSH connection successful.");
|
||||
|
||||
/* Set handlers */
|
||||
client->handle_messages = ssh_guac_client_handle_messages;
|
||||
client->mouse_handler = ssh_guac_client_mouse_handler;
|
||||
client->key_handler = ssh_guac_client_key_handler;
|
||||
client->clipboard_handler = ssh_guac_client_clipboard_handler;
|
||||
client->key_handler = ssh_guac_client_key_handler;
|
||||
client->mouse_handler = ssh_guac_client_mouse_handler;
|
||||
client->size_handler = ssh_guac_client_size_handler;
|
||||
client->free_handler = ssh_guac_client_free_handler;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -41,14 +41,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <pango/pangocairo.h>
|
||||
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/error.h>
|
||||
|
||||
#include "ssh_handlers.h"
|
||||
#include "ssh_client.h"
|
||||
@ -61,42 +60,32 @@ int ssh_guac_client_handle_messages(guac_client* client) {
|
||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||
char buffer[8192];
|
||||
|
||||
ssh_channel channels[2], out_channels[2];
|
||||
int ret_val;
|
||||
int fd = client_data->stdout_pipe_fd[0];
|
||||
struct timeval timeout;
|
||||
fd_set fds;
|
||||
int ssh_fd;
|
||||
|
||||
/* Channels to read */
|
||||
channels[0] = client_data->term_channel;
|
||||
channels[1] = NULL;
|
||||
|
||||
/* Get SSH file descriptor */
|
||||
ssh_fd = ssh_get_fd(client_data->session);
|
||||
|
||||
/* Build fd_set */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(ssh_fd, &fds);
|
||||
FD_SET(fd, &fds);
|
||||
|
||||
/* Time to wait */
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
/* Wait for data to be available */
|
||||
if (ssh_select(channels, out_channels, ssh_fd+1, &fds, &timeout)
|
||||
== SSH_OK) {
|
||||
ret_val = select(fd+1, &fds, NULL, NULL, &timeout);
|
||||
if (ret_val > 0) {
|
||||
|
||||
int bytes_read = 0;
|
||||
|
||||
/* Lock terminal access */
|
||||
pthread_mutex_lock(&(client_data->term->lock));
|
||||
|
||||
/* While data available, write to terminal */
|
||||
while (channel_is_open(client_data->term_channel)
|
||||
&& !channel_is_eof(client_data->term_channel)
|
||||
&& (bytes_read = channel_read_nonblocking(client_data->term_channel, buffer, sizeof(buffer), 0)) > 0) {
|
||||
/* Read data, write to terminal */
|
||||
if ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) {
|
||||
|
||||
if (guac_terminal_write(client_data->term, buffer, bytes_read)
|
||||
|| guac_socket_flush(socket))
|
||||
if (guac_terminal_write(client_data->term, buffer, bytes_read))
|
||||
return 1;
|
||||
|
||||
}
|
||||
@ -118,6 +107,11 @@ int ssh_guac_client_handle_messages(guac_client* client) {
|
||||
pthread_mutex_unlock(&(client_data->term->lock));
|
||||
|
||||
}
|
||||
else if (ret_val < 0) {
|
||||
guac_error_message = "Error waiting for pipe";
|
||||
guac_error = GUAC_STATUS_SEE_ERRNO;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -164,7 +158,7 @@ int ssh_guac_client_mouse_handler(guac_client* client, int x, int y, int mask) {
|
||||
|
||||
int length = strlen(client_data->clipboard_data);
|
||||
if (length)
|
||||
return channel_write(client_data->term_channel,
|
||||
return write(client_data->stdin_pipe_fd[1],
|
||||
client_data->clipboard_data, length);
|
||||
|
||||
}
|
||||
@ -234,6 +228,9 @@ int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
|
||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||
guac_terminal* term = client_data->term;
|
||||
|
||||
/* Get write end of STDIN pipe */
|
||||
int fd = client_data->stdin_pipe_fd[1];
|
||||
|
||||
/* Hide mouse cursor if not already hidden */
|
||||
if (client_data->current_cursor != client_data->blank_cursor) {
|
||||
pthread_mutex_lock(&(term->lock));
|
||||
@ -275,7 +272,7 @@ int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
|
||||
else
|
||||
return 0;
|
||||
|
||||
return channel_write(client_data->term_channel, &data, 1);
|
||||
return write(fd, &data, 1);
|
||||
|
||||
}
|
||||
|
||||
@ -286,7 +283,7 @@ int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
|
||||
char data[5];
|
||||
|
||||
length = guac_terminal_encode_utf8(keysym & 0xFFFF, data);
|
||||
return channel_write(client_data->term_channel, data, length);
|
||||
return write(fd, data, length);
|
||||
|
||||
}
|
||||
|
||||
@ -309,7 +306,7 @@ int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
|
||||
/* Ignore other keys */
|
||||
else return 0;
|
||||
|
||||
return channel_write(client_data->term_channel, data, length);
|
||||
return write(fd, data, length);
|
||||
}
|
||||
|
||||
}
|
||||
@ -335,8 +332,8 @@ int ssh_guac_client_size_handler(guac_client* client, int width, int height) {
|
||||
|
||||
/* Resize terminal */
|
||||
guac_terminal_resize(terminal, columns, rows);
|
||||
channel_change_pty_size(guac_client_data->term_channel,
|
||||
terminal->term_width, terminal->term_height);
|
||||
|
||||
/* FIXME: Make resize call to SSH thread */
|
||||
|
||||
/* Reset scroll region */
|
||||
terminal->scroll_end = rows - 1;
|
||||
|
Loading…
Reference in New Issue
Block a user