Working migration to libssh2 (hard-coded host).

This commit is contained in:
Michael Jumper 2013-12-01 16:09:48 -08:00
parent d32018cf87
commit 150e645383
5 changed files with 230 additions and 41 deletions

View File

@ -51,6 +51,7 @@ libguac_client_ssh_la_SOURCES = \
guac_handlers.c \ guac_handlers.c \
ibar.c \ ibar.c \
sftp.c \ sftp.c \
ssh_buffer.c \
ssh_client.c \ ssh_client.c \
ssh_key.c \ ssh_key.c \
terminal.c \ terminal.c \
@ -67,6 +68,7 @@ noinst_HEADERS = \
guac_handlers.h \ guac_handlers.h \
ibar.h \ ibar.h \
sftp.h \ sftp.h \
ssh_buffer.h \
ssh_client.h \ ssh_client.h \
ssh_key.h \ ssh_key.h \
terminal.h \ terminal.h \

View File

@ -441,6 +441,7 @@ int ssh_guac_client_free_handler(guac_client* client) {
} }
/* Free session */ /* Free session */
if (guac_client_data->session != NULL)
libssh2_session_free(guac_client_data->session); libssh2_session_free(guac_client_data->session);
/* Free auth key */ /* Free auth key */

View File

@ -0,0 +1,111 @@
#include <stdint.h>
#include <string.h>
#include <openssl/bn.h>
void buffer_write_byte(char** buffer, uint8_t value) {
uint8_t* data = (uint8_t*) *buffer;
*data = value;
(*buffer)++;
}
void buffer_write_uint32(char** buffer, uint32_t value) {
uint8_t* data = (uint8_t*) *buffer;
data[0] = (value & 0xFF000000) >> 24;
data[1] = (value & 0x00FF0000) >> 16;
data[2] = (value & 0x0000FF00) >> 8;
data[3] = value & 0x000000FF;
*buffer += 4;
}
void buffer_write_data(char** buffer, const char* data, int length) {
memcpy(*buffer, data, length);
*buffer += length;
}
void buffer_write_bignum(char** buffer, BIGNUM* value) {
unsigned char* bn_buffer;
int length;
/* If zero, just write zero length */
if (BN_is_zero(value)) {
buffer_write_uint32(buffer, 0);
return;
}
/* Allocate output buffer, add padding byte */
length = BN_num_bytes(value);
bn_buffer = malloc(length);
/* Convert BIGNUM */
BN_bn2bin(value, bn_buffer);
/* If first byte has high bit set, write padding byte */
if (bn_buffer[0] & 0x80) {
buffer_write_uint32(buffer, length+1);
buffer_write_byte(buffer, 0);
}
else
buffer_write_uint32(buffer, length);
/* Write data */
memcpy(*buffer, bn_buffer, length);
*buffer += length;
free(bn_buffer);
}
void buffer_write_string(char** buffer, const char* string, int length) {
buffer_write_uint32(buffer, length);
buffer_write_data(buffer, string, length);
}
uint8_t buffer_read_byte(char** buffer) {
uint8_t* data = (uint8_t*) *buffer;
uint8_t value = *data;
(*buffer)++;
return value;
}
uint32_t buffer_read_uint32(char** buffer) {
uint8_t* data = (uint8_t*) *buffer;
uint32_t value =
(data[0] << 24)
| (data[1] << 16)
| (data[2] << 8)
| data[3];
*buffer += 4;
return value;
}
char* buffer_read_string(char** buffer, int* length) {
char* value;
*length = buffer_read_uint32(buffer);
value = *buffer;
*buffer += *length;
return value;
}

View File

@ -0,0 +1,58 @@
#ifndef _GUAC_SSH_BUFFER_H
#define _GUAC_SSH_BUFFER_H
#include <stdint.h>
#include <openssl/bn.h>
/**
* Writes the given byte to the given buffer, advancing the buffer pointer by
* one byte.
*/
void buffer_write_byte(char** buffer, uint8_t value);
/**
* Writes the given integer to the given buffer, advancing the buffer pointer
* four bytes.
*/
void buffer_write_uint32(char** buffer, uint32_t value);
/**
* Writes the given string and its length to the given buffer, advancing the
* buffer pointer by the size of the length (four bytes) and the size of the
* string.
*/
void buffer_write_string(char** buffer, const char* string, int length);
/**
* Writes the given BIGNUM the given buffer, advancing the buffer pointer by
* the size of the length (four bytes) and the size of the BIGNUM.
*/
void buffer_write_bignum(char** buffer, BIGNUM* value);
/**
* Writes the given data the given buffer, advancing the buffer pointer by the
* given length.
*/
void buffer_write_data(char** buffer, const char* data, int length);
/**
* Reads a single byte from the given buffer, advancing the buffer by one byte.
*/
uint8_t buffer_read_byte(char** buffer);
/**
* Reads an integer from the given buffer, advancing the buffer by four bytes.
*/
uint32_t buffer_read_uint32(char** buffer);
/**
* Reads a string and its length from the given buffer, advancing the buffer
* by the size of the length (four bytes) and the size of the string, and
* returning a pointer to the buffer. The length of the string is stored in
* the given int.
*/
char* buffer_read_string(char** buffer, int* length);
#endif

View File

@ -40,6 +40,12 @@
#include <string.h> #include <string.h>
#include <pthread.h> #include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/protocol.h> #include <guacamole/protocol.h>
#include <guacamole/socket.h> #include <guacamole/socket.h>
@ -122,37 +128,56 @@ void* ssh_input_thread(void* data) {
/* Write all data read */ /* Write all data read */
while ((bytes_read = read(stdin_fd, buffer, sizeof(buffer))) > 0) while ((bytes_read = read(stdin_fd, buffer, sizeof(buffer))) > 0)
channel_write(client_data->term_channel, buffer, bytes_read); libssh2_channel_write(client_data->term_channel, buffer, bytes_read);
return NULL; return NULL;
} }
static ssh_session __guac_ssh_create_session(guac_client* client) { static LIBSSH2_SESSION* __guac_ssh_create_session(guac_client* client) {
int fd;
struct sockaddr_in addr;
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data; ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
/* Get socket */
fd = socket(AF_INET, SOCK_STREAM, 0);
/* Connect to SSH server */
addr.sin_family = AF_INET;
addr.sin_port = htons(22);
addr.sin_addr.s_addr = htonl(0x0A0000C0); /* proto-test: 10.0.0.192 */
/* Connect */
if (connect(fd, (struct sockaddr*)(&addr),
sizeof(struct sockaddr_in)) != 0) {
guac_client_log_error(client, "Connection failed: %s", strerror(errno));
return NULL;
}
/* Open SSH session */ /* Open SSH session */
ssh_session session = ssh_new(); LIBSSH2_SESSION* session = libssh2_session_init();
if (session == NULL) { if (session == NULL) {
guac_client_log_error(client, "Session allocation failed", guac_client_log_error(client, "Session allocation failed");
ssh_get_error(session)); return NULL;
}
/* Perform handshake */
if (libssh2_session_handshake(session, fd)) {
guac_client_log_error(client, "SSH handshake failed");
return NULL; return NULL;
} }
/* Set session options */ /* Set session options */
#if 0
ssh_options_set(session, SSH_OPTIONS_HOST, client_data->hostname); ssh_options_set(session, SSH_OPTIONS_HOST, client_data->hostname);
ssh_options_set(session, SSH_OPTIONS_PORT, &(client_data->port)); ssh_options_set(session, SSH_OPTIONS_PORT, &(client_data->port));
ssh_options_set(session, SSH_OPTIONS_USER, client_data->username); ssh_options_set(session, SSH_OPTIONS_USER, client_data->username);
#endif
/* Connect */
if (ssh_connect(session) != SSH_OK) {
guac_client_log_error(client, "Unable to connect via SSH: %s",
ssh_get_error(session));
return NULL;
}
/* Authenticate with key if available */ /* Authenticate with key if available */
#if 0
if (client_data->key != NULL) { if (client_data->key != NULL) {
if (ssh_userauth_publickey(session, NULL, client_data->key) if (ssh_userauth_publickey(session, NULL, client_data->key)
== SSH_AUTH_SUCCESS) == SSH_AUTH_SUCCESS)
@ -164,15 +189,18 @@ static ssh_session __guac_ssh_create_session(guac_client* client) {
return NULL; return NULL;
} }
} }
#endif
/* Authenticate with password */ /* Authenticate with password */
if (ssh_userauth_password(session, NULL, client_data->password) if (!libssh2_userauth_password(session, client_data->username,
== SSH_AUTH_SUCCESS) client_data->password))
return session; return session;
else { else {
char* error_message;
libssh2_session_last_error(session, &error_message, NULL, 0);
guac_client_log_error(client, guac_client_log_error(client,
"Password authentication failed: %s", "Password authentication failed: %s", error_message);
ssh_get_error(session));
return NULL; return NULL;
} }
@ -202,6 +230,7 @@ void* ssh_client_thread(void* data) {
snprintf(name, sizeof(name)-1, "%s@%s", client_data->username, client_data->hostname); snprintf(name, sizeof(name)-1, "%s@%s", client_data->username, client_data->hostname);
guac_protocol_send_name(socket, name); guac_protocol_send_name(socket, name);
#if 0
/* If key specified, import */ /* If key specified, import */
if (client_data->key_base64[0] != 0) { if (client_data->key_base64[0] != 0) {
@ -239,6 +268,7 @@ void* ssh_client_thread(void* data) {
sizeof(client_data->password), false) == NULL) sizeof(client_data->password), false) == NULL)
return NULL; return NULL;
} }
#endif
/* Clear screen */ /* Clear screen */
guac_terminal_write_all(stdout_fd, "\x1B[H\x1B[J", 6); guac_terminal_write_all(stdout_fd, "\x1B[H\x1B[J", 6);
@ -253,7 +283,8 @@ void* ssh_client_thread(void* data) {
} }
/* Open channel for terminal */ /* Open channel for terminal */
client_data->term_channel = channel_new(client_data->session); client_data->term_channel =
libssh2_channel_open_session(client_data->session);
if (client_data->term_channel == NULL) { if (client_data->term_channel == NULL) {
guac_protocol_send_error(socket, "Unable to open channel.", guac_protocol_send_error(socket, "Unable to open channel.",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR); GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
@ -261,14 +292,6 @@ void* ssh_client_thread(void* data) {
return NULL; return NULL;
} }
/* 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_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(socket);
return NULL;
}
/* Start SFTP session as well, if enabled */ /* Start SFTP session as well, if enabled */
if (client_data->enable_sftp) { if (client_data->enable_sftp) {
@ -276,7 +299,8 @@ void* ssh_client_thread(void* data) {
client_data->sftp_ssh_session = __guac_ssh_create_session(client); client_data->sftp_ssh_session = __guac_ssh_create_session(client);
/* Request SFTP */ /* Request SFTP */
client_data->sftp_session = sftp_new(client_data->sftp_ssh_session); client_data->sftp_session =
libssh2_sftp_init(client_data->sftp_ssh_session);
if (client_data->sftp_session == NULL) { if (client_data->sftp_session == NULL) {
guac_protocol_send_error(socket, "Unable to start SFTP session..", guac_protocol_send_error(socket, "Unable to start SFTP session..",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR); GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
@ -284,14 +308,6 @@ void* ssh_client_thread(void* data) {
return NULL; return NULL;
} }
/* Init SFTP */
if (sftp_init(client_data->sftp_session) != SSH_OK) {
guac_protocol_send_error(socket, "Unable to initialize SFTP session.",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(socket);
return NULL;
}
/* Set file handlers */ /* Set file handlers */
client->ack_handler = guac_sftp_ack_handler; client->ack_handler = guac_sftp_ack_handler;
client->file_handler = guac_sftp_file_handler; client->file_handler = guac_sftp_file_handler;
@ -303,8 +319,10 @@ void* ssh_client_thread(void* data) {
} }
/* Request PTY */ /* Request PTY */
if (channel_request_pty_size(client_data->term_channel, "linux", if (libssh2_channel_request_pty_ex(client_data->term_channel,
client_data->term->term_width, client_data->term->term_height) != SSH_OK) { "linux", sizeof("linux")-1, NULL, 0,
client_data->term->term_width, client_data->term->term_height,
0, 0)) {
guac_protocol_send_error(socket, "Unable to allocate PTY for channel.", guac_protocol_send_error(socket, "Unable to allocate PTY for channel.",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR); GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(socket); guac_socket_flush(socket);
@ -312,7 +330,7 @@ void* ssh_client_thread(void* data) {
} }
/* Request shell */ /* Request shell */
if (channel_request_shell(client_data->term_channel) != SSH_OK) { if (libssh2_channel_shell(client_data->term_channel)) {
guac_protocol_send_error(socket, "Unable to associate shell with PTY.", guac_protocol_send_error(socket, "Unable to associate shell with PTY.",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR); GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(socket); guac_socket_flush(socket);
@ -329,11 +347,10 @@ void* ssh_client_thread(void* data) {
} }
/* While data available, write to terminal */ /* While data available, write to terminal */
while (channel_is_open(client_data->term_channel) while (!libssh2_channel_eof(client_data->term_channel)) {
&& !channel_is_eof(client_data->term_channel)) {
/* Repeat read if necessary */ /* Repeat read if necessary */
if ((bytes_read = channel_read(client_data->term_channel, buffer, sizeof(buffer), 0)) == SSH_AGAIN) if ((bytes_read = libssh2_channel_read(client_data->term_channel, buffer, sizeof(buffer))) == LIBSSH2_ERROR_EAGAIN)
continue; continue;
/* Attempt to write data received. Exit on failure. */ /* Attempt to write data received. Exit on failure. */