From 30ec3be92433be5bd3a27981b48843964c25fc04 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sat, 3 Aug 2019 17:15:02 -0400 Subject: [PATCH] GUACAMOLE-860: [WIP] TN5250 adjustments. --- src/protocols/tn5250/argv.c | 60 ++++++------ src/protocols/tn5250/argv.h | 8 +- src/protocols/tn5250/client.c | 54 +++++------ src/protocols/tn5250/client.h | 8 +- src/protocols/tn5250/clipboard.c | 20 ++-- src/protocols/tn5250/clipboard.h | 10 +- src/protocols/tn5250/input.c | 38 ++++---- src/protocols/tn5250/input.h | 10 +- src/protocols/tn5250/pipe.c | 10 +- src/protocols/tn5250/pipe.h | 8 +- src/protocols/tn5250/settings.c | 134 ++++++++++++++------------ src/protocols/tn5250/settings.h | 157 +++++++++++++++++++++++++----- src/protocols/tn5250/tn5250.c | 160 +++++++++++++++---------------- src/protocols/tn5250/tn5250.h | 16 ++-- src/protocols/tn5250/user.c | 42 ++++---- src/protocols/tn5250/user.h | 4 +- 16 files changed, 431 insertions(+), 308 deletions(-) diff --git a/src/protocols/tn5250/argv.c b/src/protocols/tn5250/argv.c index 8cf857d7..7b884f4a 100644 --- a/src/protocols/tn5250/argv.c +++ b/src/protocols/tn5250/argv.c @@ -30,50 +30,50 @@ #include /** - * All telnet connection settings which may be updated by unprivileged users + * All tn5250 connection settings which may be updated by unprivileged users * through "argv" streams. */ -typedef enum guac_telnet_argv_setting { +typedef enum guac_tn5250_argv_setting { /** * The color scheme of the terminal. */ - GUAC_TELNET_ARGV_SETTING_COLOR_SCHEME, + GUAC_TN5250_ARGV_SETTING_COLOR_SCHEME, /** * The name of the font family used by the terminal. */ - GUAC_TELNET_ARGV_SETTING_FONT_NAME, + GUAC_TN5250_ARGV_SETTING_FONT_NAME, /** * The size of the font used by the terminal, in points. */ - GUAC_TELNET_ARGV_SETTING_FONT_SIZE + GUAC_TN5250_ARGV_SETTING_FONT_SIZE -} guac_telnet_argv_setting; +} guac_tn5250_argv_setting; /** * The value or current status of a connection parameter received over an * "argv" stream. */ -typedef struct guac_telnet_argv { +typedef struct guac_tn5250_argv { /** * The specific setting being updated. */ - guac_telnet_argv_setting setting; + guac_tn5250_argv_setting setting; /** * Buffer space for containing the received argument value. */ - char buffer[GUAC_TELNET_ARGV_MAX_LENGTH]; + char buffer[GUAC_TN5250_ARGV_MAX_LENGTH]; /** * The number of bytes received so far. */ int length; -} guac_telnet_argv; +} guac_tn5250_argv; /** * Handler for "blob" instructions which appends the data from received blobs @@ -81,10 +81,10 @@ typedef struct guac_telnet_argv { * * @see guac_user_blob_handler */ -static int guac_telnet_argv_blob_handler(guac_user* user, +static int guac_tn5250_argv_blob_handler(guac_user* user, guac_stream* stream, void* data, int length) { - guac_telnet_argv* argv = (guac_telnet_argv*) stream->data; + guac_tn5250_argv* argv = (guac_tn5250_argv*) stream->data; /* Calculate buffer size remaining, including space for null terminator, * adjusting received length accordingly */ @@ -106,40 +106,40 @@ static int guac_telnet_argv_blob_handler(guac_user* user, * * @see guac_user_end_handler */ -static int guac_telnet_argv_end_handler(guac_user* user, +static int guac_tn5250_argv_end_handler(guac_user* user, guac_stream* stream) { int size; guac_client* client = user->client; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; - guac_terminal* terminal = telnet_client->term; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; + guac_terminal* terminal = tn5250_client->term; /* Append null terminator to value */ - guac_telnet_argv* argv = (guac_telnet_argv*) stream->data; + guac_tn5250_argv* argv = (guac_tn5250_argv*) stream->data; argv->buffer[argv->length] = '\0'; /* Apply changes to chosen setting */ switch (argv->setting) { /* Update color scheme */ - case GUAC_TELNET_ARGV_SETTING_COLOR_SCHEME: + case GUAC_TN5250_ARGV_SETTING_COLOR_SCHEME: guac_terminal_apply_color_scheme(terminal, argv->buffer); break; /* Update font name */ - case GUAC_TELNET_ARGV_SETTING_FONT_NAME: + case GUAC_TN5250_ARGV_SETTING_FONT_NAME: guac_terminal_apply_font(terminal, argv->buffer, -1, 0); break; /* Update font size */ - case GUAC_TELNET_ARGV_SETTING_FONT_SIZE: + case GUAC_TN5250_ARGV_SETTING_FONT_SIZE: /* Update only if font size is sane */ size = atoi(argv->buffer); if (size > 0) { guac_terminal_apply_font(terminal, NULL, size, - telnet_client->settings->resolution); + tn5250_client->settings->resolution); } break; @@ -147,8 +147,8 @@ static int guac_telnet_argv_end_handler(guac_user* user, } /* Update terminal window size if connected */ - if (telnet_client->telnet != NULL && telnet_client->naws_enabled) - guac_telnet_send_naws(telnet_client->telnet, terminal->term_width, + if (tn5250_client->tn5250 != NULL && tn5250_client->naws_enabled) + guac_tn5250_send_naws(tn5250_client->tn5250, terminal->term_width, terminal->term_height); free(argv); @@ -156,18 +156,18 @@ static int guac_telnet_argv_end_handler(guac_user* user, } -int guac_telnet_argv_handler(guac_user* user, guac_stream* stream, +int guac_tn5250_argv_handler(guac_user* user, guac_stream* stream, char* mimetype, char* name) { - guac_telnet_argv_setting setting; + guac_tn5250_argv_setting setting; /* Allow users to update the color scheme and font details */ if (strcmp(name, "color-scheme") == 0) - setting = GUAC_TELNET_ARGV_SETTING_COLOR_SCHEME; + setting = GUAC_TN5250_ARGV_SETTING_COLOR_SCHEME; else if (strcmp(name, "font-name") == 0) - setting = GUAC_TELNET_ARGV_SETTING_FONT_NAME; + setting = GUAC_TN5250_ARGV_SETTING_FONT_NAME; else if (strcmp(name, "font-size") == 0) - setting = GUAC_TELNET_ARGV_SETTING_FONT_SIZE; + setting = GUAC_TN5250_ARGV_SETTING_FONT_SIZE; /* No other connection parameters may be updated */ else { @@ -177,13 +177,13 @@ int guac_telnet_argv_handler(guac_user* user, guac_stream* stream, return 0; } - guac_telnet_argv* argv = malloc(sizeof(guac_telnet_argv)); + guac_tn5250_argv* argv = malloc(sizeof(guac_tn5250_argv)); argv->setting = setting; argv->length = 0; /* Prepare stream to receive argument value */ - stream->blob_handler = guac_telnet_argv_blob_handler; - stream->end_handler = guac_telnet_argv_end_handler; + stream->blob_handler = guac_tn5250_argv_blob_handler; + stream->end_handler = guac_tn5250_argv_end_handler; stream->data = argv; /* Signal stream is ready */ diff --git a/src/protocols/tn5250/argv.h b/src/protocols/tn5250/argv.h index aa13dda9..50caca51 100644 --- a/src/protocols/tn5250/argv.h +++ b/src/protocols/tn5250/argv.h @@ -18,8 +18,8 @@ */ -#ifndef GUAC_TELNET_ARGV_H -#define GUAC_TELNET_ARGV_H +#ifndef GUAC_TN5250_ARGV_H +#define GUAC_TN5250_ARGV_H #include "config.h" @@ -29,13 +29,13 @@ * The maximum number of bytes to allow for any argument value received via an * argv stream, including null terminator. */ -#define GUAC_TELNET_ARGV_MAX_LENGTH 16384 +#define GUAC_TN5250_ARGV_MAX_LENGTH 16384 /** * Handles an incoming stream from a Guacamole "argv" instruction, updating the * given connection parameter if that parameter is allowed to be updated. */ -guac_user_argv_handler guac_telnet_argv_handler; +guac_user_argv_handler guac_tn5250_argv_handler; #endif diff --git a/src/protocols/tn5250/client.c b/src/protocols/tn5250/client.c index 1c6a2ec8..94b6c3f1 100644 --- a/src/protocols/tn5250/client.c +++ b/src/protocols/tn5250/client.c @@ -21,7 +21,7 @@ #include "client.h" #include "common/recording.h" #include "settings.h" -#include "telnet.h" +#include "tn5250.h" #include "terminal/terminal.h" #include "user.h" @@ -36,23 +36,23 @@ int guac_client_init(guac_client* client) { /* Set client args */ - client->args = GUAC_TELNET_CLIENT_ARGS; + client->args = GUAC_TN5250_CLIENT_ARGS; /* Allocate client instance data */ - guac_telnet_client* telnet_client = calloc(1, sizeof(guac_telnet_client)); - client->data = telnet_client; + guac_tn5250_client* tn5250_client = calloc(1, sizeof(guac_tn5250_client)); + client->data = tn5250_client; /* Init clipboard */ - telnet_client->clipboard = guac_common_clipboard_alloc(GUAC_TELNET_CLIPBOARD_MAX_LENGTH); + tn5250_client->clipboard = guac_common_clipboard_alloc(GUAC_TN5250_CLIPBOARD_MAX_LENGTH); - /* Init telnet client */ - telnet_client->socket_fd = -1; - telnet_client->naws_enabled = 0; - telnet_client->echo_enabled = 1; + /* Init tn5250 client */ + tn5250_client->socket_fd = -1; + tn5250_client->naws_enabled = 0; + tn5250_client->echo_enabled = 1; /* Set handlers */ - client->join_handler = guac_telnet_user_join_handler; - client->free_handler = guac_telnet_client_free_handler; + client->join_handler = guac_tn5250_user_join_handler; + client->free_handler = guac_tn5250_client_free_handler; /* Set locale and warn if not UTF-8 */ setlocale(LC_CTYPE, ""); @@ -67,33 +67,33 @@ int guac_client_init(guac_client* client) { } -int guac_telnet_client_free_handler(guac_client* client) { +int guac_tn5250_client_free_handler(guac_client* client) { - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; - /* Close telnet connection */ - if (telnet_client->socket_fd != -1) - close(telnet_client->socket_fd); + /* Close tn5250 connection */ + if (tn5250_client->socket_fd != -1) + close(tn5250_client->socket_fd); /* Clean up recording, if in progress */ - if (telnet_client->recording != NULL) - guac_common_recording_free(telnet_client->recording); + if (tn5250_client->recording != NULL) + guac_common_recording_free(tn5250_client->recording); /* Kill terminal */ - guac_terminal_free(telnet_client->term); + guac_terminal_free(tn5250_client->term); - /* Wait for and free telnet session, if connected */ - if (telnet_client->telnet != NULL) { - pthread_join(telnet_client->client_thread, NULL); - telnet_free(telnet_client->telnet); + /* Wait for and free tn5250 session, if connected */ + if (tn5250_client->telnet != NULL) { + pthread_join(tn5250_client->client_thread, NULL); + telnet_free(tn5250_client->telnet); } /* Free settings */ - if (telnet_client->settings != NULL) - guac_telnet_settings_free(telnet_client->settings); + if (tn5250_client->settings != NULL) + guac_tn5250_settings_free(tn5250_client->settings); - guac_common_clipboard_free(telnet_client->clipboard); - free(telnet_client); + guac_common_clipboard_free(tn5250_client->clipboard); + free(tn5250_client); return 0; } diff --git a/src/protocols/tn5250/client.h b/src/protocols/tn5250/client.h index 47d21f28..710c1a6e 100644 --- a/src/protocols/tn5250/client.h +++ b/src/protocols/tn5250/client.h @@ -17,8 +17,8 @@ * under the License. */ -#ifndef GUAC_TELNET__CLIENT_H -#define GUAC_TELNET__CLIENT_H +#ifndef GUAC_TN5250_CLIENT_H +#define GUAC_TN5250_CLIENT_H #include "config.h" #include "terminal/terminal.h" @@ -32,13 +32,13 @@ /** * The maximum number of bytes to allow within the clipboard. */ -#define GUAC_TELNET_CLIPBOARD_MAX_LENGTH 262144 +#define GUAC_TN5250_CLIPBOARD_MAX_LENGTH 262144 /** * Free handler. Required by libguac and called when the guac_client is * disconnected and must be cleaned up. */ -guac_client_free_handler guac_telnet_client_free_handler; +guac_client_free_handler guac_tn5250_client_free_handler; #endif diff --git a/src/protocols/tn5250/clipboard.c b/src/protocols/tn5250/clipboard.c index b663b2c3..475e76da 100644 --- a/src/protocols/tn5250/clipboard.c +++ b/src/protocols/tn5250/clipboard.c @@ -20,40 +20,40 @@ #include "config.h" #include "clipboard.h" #include "common/clipboard.h" -#include "telnet.h" +#include "tn5250.h" #include "terminal/terminal.h" #include #include #include -int guac_telnet_clipboard_handler(guac_user* user, guac_stream* stream, +int guac_tn5250_clipboard_handler(guac_user* user, guac_stream* stream, char* mimetype) { /* Clear clipboard and prepare for new data */ guac_client* client = user->client; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; - guac_common_clipboard_reset(telnet_client->clipboard, mimetype); + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; + guac_common_clipboard_reset(tn5250_client->clipboard, mimetype); /* Set handlers for clipboard stream */ - stream->blob_handler = guac_telnet_clipboard_blob_handler; - stream->end_handler = guac_telnet_clipboard_end_handler; + stream->blob_handler = guac_tn5250_clipboard_blob_handler; + stream->end_handler = guac_tn5250_clipboard_end_handler; return 0; } -int guac_telnet_clipboard_blob_handler(guac_user* user, guac_stream* stream, +int guac_tn5250_clipboard_blob_handler(guac_user* user, guac_stream* stream, void* data, int length) { /* Append new data */ guac_client* client = user->client; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; - guac_common_clipboard_append(telnet_client->clipboard, data, length); + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; + guac_common_clipboard_append(tn5250_client->clipboard, data, length); return 0; } -int guac_telnet_clipboard_end_handler(guac_user* user, guac_stream* stream) { +int guac_tn5250_clipboard_end_handler(guac_user* user, guac_stream* stream) { /* Nothing to do - clipboard is implemented within client */ diff --git a/src/protocols/tn5250/clipboard.h b/src/protocols/tn5250/clipboard.h index 9428beda..65d7dcd7 100644 --- a/src/protocols/tn5250/clipboard.h +++ b/src/protocols/tn5250/clipboard.h @@ -17,8 +17,8 @@ * under the License. */ -#ifndef GUAC_TELNET_CLIPBOARD_H -#define GUAC_TELNET_CLIPBOARD_H +#ifndef GUAC_TN5250_CLIPBOARD_H +#define GUAC_TN5250_CLIPBOARD_H #include "config.h" @@ -27,17 +27,17 @@ /** * Handler for inbound clipboard streams. */ -guac_user_clipboard_handler guac_telnet_clipboard_handler; +guac_user_clipboard_handler guac_tn5250_clipboard_handler; /** * Handler for data received along clipboard streams. */ -guac_user_blob_handler guac_telnet_clipboard_blob_handler; +guac_user_blob_handler guac_tn5250_clipboard_blob_handler; /** * Handler for end-of-stream related to clipboard. */ -guac_user_end_handler guac_telnet_clipboard_end_handler; +guac_user_end_handler guac_tn5250_clipboard_end_handler; #endif diff --git a/src/protocols/tn5250/input.c b/src/protocols/tn5250/input.c index 9a63da40..499651b8 100644 --- a/src/protocols/tn5250/input.c +++ b/src/protocols/tn5250/input.c @@ -21,7 +21,7 @@ #include "common/recording.h" #include "input.h" #include "terminal/terminal.h" -#include "telnet.h" +#include "tn5250.h" #include #include @@ -32,20 +32,20 @@ #include #include -int guac_telnet_user_mouse_handler(guac_user* user, int x, int y, int mask) { +int guac_tn5250_user_mouse_handler(guac_user* user, int x, int y, int mask) { guac_client* client = user->client; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; - guac_telnet_settings* settings = telnet_client->settings; - guac_terminal* term = telnet_client->term; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; + guac_tn5250_settings* settings = tn5250_client->settings; + guac_terminal* term = tn5250_client->term; /* Skip if terminal not yet ready */ if (term == NULL) return 0; /* Report mouse position within recording */ - if (telnet_client->recording != NULL) - guac_common_recording_report_mouse(telnet_client->recording, x, y, + if (tn5250_client->recording != NULL) + guac_common_recording_report_mouse(tn5250_client->recording, x, y, mask); /* Send mouse if not searching for password or username */ @@ -56,16 +56,16 @@ int guac_telnet_user_mouse_handler(guac_user* user, int x, int y, int mask) { } -int guac_telnet_user_key_handler(guac_user* user, int keysym, int pressed) { +int guac_tn5250_user_key_handler(guac_user* user, int keysym, int pressed) { guac_client* client = user->client; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; - guac_telnet_settings* settings = telnet_client->settings; - guac_terminal* term = telnet_client->term; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; + guac_tn5250_settings* settings = tn5250_client->settings; + guac_terminal* term = tn5250_client->term; /* Report key state within recording */ - if (telnet_client->recording != NULL) - guac_common_recording_report_key(telnet_client->recording, + if (tn5250_client->recording != NULL) + guac_common_recording_report_key(tn5250_client->recording, keysym, pressed); /* Skip if terminal not yet ready */ @@ -104,7 +104,7 @@ int guac_telnet_user_key_handler(guac_user* user, int keysym, int pressed) { )) { /* Send IAC BRK */ - telnet_iac(telnet_client->telnet, TELNET_BREAK); + telnet_iac(tn5250_client->telnet, TELNET_BREAK); return 0; } @@ -116,12 +116,12 @@ int guac_telnet_user_key_handler(guac_user* user, int keysym, int pressed) { } -int guac_telnet_user_size_handler(guac_user* user, int width, int height) { +int guac_tn5250_user_size_handler(guac_user* user, int width, int height) { /* Get terminal */ guac_client* client = user->client; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; - guac_terminal* terminal = telnet_client->term; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; + guac_terminal* terminal = tn5250_client->term; /* Skip if terminal not yet ready */ if (terminal == NULL) @@ -131,8 +131,8 @@ int guac_telnet_user_size_handler(guac_user* user, int width, int height) { guac_terminal_resize(terminal, width, height); /* Update terminal window size if connected */ - if (telnet_client->telnet != NULL && telnet_client->naws_enabled) - guac_telnet_send_naws(telnet_client->telnet, terminal->term_width, + if (tn5250_client->telnet != NULL && tn5250_client->naws_enabled) + guac_tn5250_send_naws(tn5250_client->telnet, terminal->term_width, terminal->term_height); return 0; diff --git a/src/protocols/tn5250/input.h b/src/protocols/tn5250/input.h index 082f9a17..acccbd71 100644 --- a/src/protocols/tn5250/input.h +++ b/src/protocols/tn5250/input.h @@ -17,8 +17,8 @@ * under the License. */ -#ifndef GUAC_TELNET_INPUT_H -#define GUAC_TELNET_INPUT_H +#ifndef GUAC_TN5250_INPUT_H +#define GUAC_TN5250_INPUT_H #include "config.h" @@ -28,19 +28,19 @@ * Handler for key events. Required by libguac and called whenever key events * are received. */ -guac_user_key_handler guac_telnet_user_key_handler; +guac_user_key_handler guac_tn5250_user_key_handler; /** * Handler for mouse events. Required by libguac and called whenever mouse * events are received. */ -guac_user_mouse_handler guac_telnet_user_mouse_handler; +guac_user_mouse_handler guac_tn5250_user_mouse_handler; /** * Handler for size events. Required by libguac and called whenever the remote * display (window) is resized. */ -guac_user_size_handler guac_telnet_user_size_handler; +guac_user_size_handler guac_tn5250_user_size_handler; #endif diff --git a/src/protocols/tn5250/pipe.c b/src/protocols/tn5250/pipe.c index 0293a841..5f875398 100644 --- a/src/protocols/tn5250/pipe.c +++ b/src/protocols/tn5250/pipe.c @@ -19,7 +19,7 @@ #include "config.h" #include "pipe.h" -#include "telnet.h" +#include "tn5250.h" #include "terminal/terminal.h" #include @@ -28,15 +28,15 @@ #include -int guac_telnet_pipe_handler(guac_user* user, guac_stream* stream, +int guac_tn5250_pipe_handler(guac_user* user, guac_stream* stream, char* mimetype, char* name) { guac_client* client = user->client; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; /* Redirect STDIN if pipe has required name */ - if (strcmp(name, GUAC_TELNET_STDIN_PIPE_NAME) == 0) { - guac_terminal_send_stream(telnet_client->term, user, stream); + if (strcmp(name, GUAC_TN5250_STDIN_PIPE_NAME) == 0) { + guac_terminal_send_stream(tn5250_client->term, user, stream); return 0; } diff --git a/src/protocols/tn5250/pipe.h b/src/protocols/tn5250/pipe.h index 51e9f9c8..9b7006ee 100644 --- a/src/protocols/tn5250/pipe.h +++ b/src/protocols/tn5250/pipe.h @@ -18,8 +18,8 @@ */ -#ifndef GUAC_TELNET_PIPE_H -#define GUAC_TELNET_PIPE_H +#ifndef GUAC_TN5250_PIPE_H +#define GUAC_TN5250_PIPE_H #include "config.h" @@ -29,14 +29,14 @@ * The name reserved for the inbound pipe stream which forces the terminal * emulator's STDIN to be received from the pipe. */ -#define GUAC_TELNET_STDIN_PIPE_NAME "STDIN" +#define GUAC_TN5250_STDIN_PIPE_NAME "STDIN" /** * Handles an incoming stream from a Guacamole "pipe" instruction. If the pipe * is named "STDIN", the the contents of the pipe stream are redirected to * STDIN of the terminal emulator for as long as the pipe is open. */ -guac_user_pipe_handler guac_telnet_pipe_handler; +guac_user_pipe_handler guac_tn5250_pipe_handler; #endif diff --git a/src/protocols/tn5250/settings.c b/src/protocols/tn5250/settings.c index b72f4d28..a33173f8 100644 --- a/src/protocols/tn5250/settings.c +++ b/src/protocols/tn5250/settings.c @@ -33,6 +33,7 @@ const char* GUAC_TN5250_CLIENT_ARGS[] = { "hostname", "port", + "ssl", "username", "username-regex", "password", @@ -60,7 +61,7 @@ const char* GUAC_TN5250_CLIENT_ARGS[] = { NULL }; -enum TELNET_ARGS_IDX { +enum TN5250_ARGS_IDX { /** * The hostname to connect to. Required. @@ -71,6 +72,11 @@ enum TELNET_ARGS_IDX { * The port to connect to. Optional. */ IDX_PORT, + + /** + * Whether or not to use SSL. Optional. + */ + IDX_SSL, /** * The name of the user to login as. Optional. @@ -232,13 +238,13 @@ enum TELNET_ARGS_IDX { */ IDX_DISABLE_PASTE, - TELNET_ARGS_COUNT + TN5250_ARGS_COUNT }; /** * Compiles the given regular expression, returning NULL if compilation fails * or of the given regular expression is NULL. The returned regex_t must be - * freed with regfree() AND free(), or with guac_telnet_regex_free(). + * freed with regfree() AND free(), or with guac_tn5250_regex_free(). * * @param user * The user who provided the setting associated with the given regex @@ -251,7 +257,7 @@ enum TELNET_ARGS_IDX { * The compiled regular expression, or NULL if compilation fails or NULL * was originally provided for the pattern. */ -static regex_t* guac_telnet_compile_regex(guac_user* user, char* pattern) { +static regex_t* guac_tn5250_compile_regex(guac_user* user, char* pattern) { /* Nothing to compile if no pattern provided */ if (pattern == NULL) @@ -275,7 +281,7 @@ static regex_t* guac_telnet_compile_regex(guac_user* user, char* pattern) { return regex; } -void guac_telnet_regex_free(regex_t** regex) { +void guac_tn5250_regex_free(regex_t** regex) { if (*regex != NULL) { regfree(*regex); free(*regex); @@ -283,100 +289,100 @@ void guac_telnet_regex_free(regex_t** regex) { } } -guac_telnet_settings* guac_telnet_parse_args(guac_user* user, +guac_tn5250_settings* guac_tn5250_parse_args(guac_user* user, int argc, const char** argv) { /* Validate arg count */ - if (argc != TELNET_ARGS_COUNT) { + if (argc != TN5250_ARGS_COUNT) { guac_user_log(user, GUAC_LOG_WARNING, "Incorrect number of connection " "parameters provided: expected %i, got %i.", - TELNET_ARGS_COUNT, argc); + TN5250_ARGS_COUNT, argc); return NULL; } - guac_telnet_settings* settings = calloc(1, sizeof(guac_telnet_settings)); + guac_tn5250_settings* settings = calloc(1, sizeof(guac_tn5250_settings)); - /* Read parameters */ + /* Read hostname */ settings->hostname = - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_HOSTNAME, ""); /* Read username */ settings->username = - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_USERNAME, NULL); /* Read username regex only if username is specified */ if (settings->username != NULL) { - settings->username_regex = guac_telnet_compile_regex(user, - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, - IDX_USERNAME_REGEX, GUAC_TELNET_DEFAULT_USERNAME_REGEX)); + settings->username_regex = guac_tn5250_compile_regex(user, + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, + IDX_USERNAME_REGEX, GUAC_TN5250_DEFAULT_USERNAME_REGEX)); } /* Read password */ settings->password = - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_PASSWORD, NULL); /* Read password regex only if password is specified */ if (settings->password != NULL) { - settings->password_regex = guac_telnet_compile_regex(user, - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, - IDX_PASSWORD_REGEX, GUAC_TELNET_DEFAULT_PASSWORD_REGEX)); + settings->password_regex = guac_tn5250_compile_regex(user, + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, + IDX_PASSWORD_REGEX, GUAC_TN5250_DEFAULT_PASSWORD_REGEX)); } /* Read optional login success detection regex */ - settings->login_success_regex = guac_telnet_compile_regex(user, - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, + settings->login_success_regex = guac_tn5250_compile_regex(user, + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_LOGIN_SUCCESS_REGEX, NULL)); /* Read optional login failure detection regex */ - settings->login_failure_regex = guac_telnet_compile_regex(user, - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, + settings->login_failure_regex = guac_tn5250_compile_regex(user, + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_LOGIN_FAILURE_REGEX, NULL)); /* Both login success and login failure regexes must be provided if either * is present at all */ if (settings->login_success_regex != NULL && settings->login_failure_regex == NULL) { - guac_telnet_regex_free(&settings->login_success_regex); + guac_tn5250_regex_free(&settings->login_success_regex); guac_user_log(user, GUAC_LOG_WARNING, "Ignoring provided value for " "\"%s\" as \"%s\" must also be provided.", - GUAC_TELNET_CLIENT_ARGS[IDX_LOGIN_SUCCESS_REGEX], - GUAC_TELNET_CLIENT_ARGS[IDX_LOGIN_FAILURE_REGEX]); + GUAC_TN5250_CLIENT_ARGS[IDX_LOGIN_SUCCESS_REGEX], + GUAC_TN5250_CLIENT_ARGS[IDX_LOGIN_FAILURE_REGEX]); } else if (settings->login_failure_regex != NULL && settings->login_success_regex == NULL) { - guac_telnet_regex_free(&settings->login_failure_regex); + guac_tn5250_regex_free(&settings->login_failure_regex); guac_user_log(user, GUAC_LOG_WARNING, "Ignoring provided value for " "\"%s\" as \"%s\" must also be provided.", - GUAC_TELNET_CLIENT_ARGS[IDX_LOGIN_FAILURE_REGEX], - GUAC_TELNET_CLIENT_ARGS[IDX_LOGIN_SUCCESS_REGEX]); + GUAC_TN5250_CLIENT_ARGS[IDX_LOGIN_FAILURE_REGEX], + GUAC_TN5250_CLIENT_ARGS[IDX_LOGIN_SUCCESS_REGEX]); } /* Read-only mode */ settings->read_only = - guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_boolean(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_READ_ONLY, false); /* Read maximum scrollback size */ settings->max_scrollback = - guac_user_parse_args_int(user, GUAC_TELNET_CLIENT_ARGS, argv, - IDX_SCROLLBACK, GUAC_TELNET_DEFAULT_MAX_SCROLLBACK); + guac_user_parse_args_int(user, GUAC_TN5250_CLIENT_ARGS, argv, + IDX_SCROLLBACK, GUAC_TN5250_DEFAULT_MAX_SCROLLBACK); /* Read font name */ settings->font_name = - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, - IDX_FONT_NAME, GUAC_TELNET_DEFAULT_FONT_NAME); + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, + IDX_FONT_NAME, GUAC_TN5250_DEFAULT_FONT_NAME); /* Read font size */ settings->font_size = - guac_user_parse_args_int(user, GUAC_TELNET_CLIENT_ARGS, argv, - IDX_FONT_SIZE, GUAC_TELNET_DEFAULT_FONT_SIZE); + guac_user_parse_args_int(user, GUAC_TN5250_CLIENT_ARGS, argv, + IDX_FONT_SIZE, GUAC_TN5250_DEFAULT_FONT_SIZE); /* Copy requested color scheme */ settings->color_scheme = - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_COLOR_SCHEME, ""); /* Pull width/height/resolution directly from user */ @@ -384,74 +390,84 @@ guac_telnet_settings* guac_telnet_parse_args(guac_user* user, settings->height = user->info.optimal_height; settings->resolution = user->info.optimal_resolution; + /* Read SSL */ + settings->ssl = + guac_user_parse_args_boolean(user, GUAC_TN5250_CLIENT_ARGS, argv, + IDX_SSL, false); + + int defualt_port = GUAC_TN5250_DEFAULT_PORT; + + if (settings->ssl) + default_port = GUAC_TN5250_DEFAULT_SSL_PORT; + /* Read port */ settings->port = - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, - IDX_PORT, GUAC_TELNET_DEFAULT_PORT); + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, + IDX_PORT, defualt_port); /* Read typescript path */ settings->typescript_path = - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_TYPESCRIPT_PATH, NULL); /* Read typescript name */ settings->typescript_name = - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, - IDX_TYPESCRIPT_NAME, GUAC_TELNET_DEFAULT_TYPESCRIPT_NAME); + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, + IDX_TYPESCRIPT_NAME, GUAC_TN5250_DEFAULT_TYPESCRIPT_NAME); /* Parse path creation flag */ settings->create_typescript_path = - guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_boolean(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_CREATE_TYPESCRIPT_PATH, false); /* Read recording path */ settings->recording_path = - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_RECORDING_PATH, NULL); /* Read recording name */ settings->recording_name = - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, - IDX_RECORDING_NAME, GUAC_TELNET_DEFAULT_RECORDING_NAME); + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, + IDX_RECORDING_NAME, GUAC_TN5250_DEFAULT_RECORDING_NAME); /* Parse output exclusion flag */ settings->recording_exclude_output = - guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_boolean(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_RECORDING_EXCLUDE_OUTPUT, false); /* Parse mouse exclusion flag */ settings->recording_exclude_mouse = - guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_boolean(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_RECORDING_EXCLUDE_MOUSE, false); /* Parse key event inclusion flag */ settings->recording_include_keys = - guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_boolean(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_RECORDING_INCLUDE_KEYS, false); /* Parse path creation flag */ settings->create_recording_path = - guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_boolean(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_CREATE_RECORDING_PATH, false); /* Parse backspace key code */ settings->backspace = - guac_user_parse_args_int(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_int(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_BACKSPACE, 127); /* Read terminal emulator type. */ settings->terminal_type = - guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_TERMINAL_TYPE, "linux"); /* Parse clipboard copy disable flag */ settings->disable_copy = - guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_boolean(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_DISABLE_COPY, false); /* Parse clipboard paste disable flag */ settings->disable_paste = - guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv, + guac_user_parse_args_boolean(user, GUAC_TN5250_CLIENT_ARGS, argv, IDX_DISABLE_PASTE, false); /* Parsing was successful */ @@ -459,7 +475,7 @@ guac_telnet_settings* guac_telnet_parse_args(guac_user* user, } -void guac_telnet_settings_free(guac_telnet_settings* settings) { +void guac_tn5250_settings_free(guac_tn5250_settings* settings) { /* Free network connection information */ free(settings->hostname); @@ -470,10 +486,10 @@ void guac_telnet_settings_free(guac_telnet_settings* settings) { free(settings->password); /* Free various regexes */ - guac_telnet_regex_free(&settings->username_regex); - guac_telnet_regex_free(&settings->password_regex); - guac_telnet_regex_free(&settings->login_success_regex); - guac_telnet_regex_free(&settings->login_failure_regex); + guac_tn5250_regex_free(&settings->username_regex); + guac_tn5250_regex_free(&settings->password_regex); + guac_tn5250_regex_free(&settings->login_success_regex); + guac_tn5250_regex_free(&settings->login_failure_regex); /* Free display preferences */ free(settings->font_name); diff --git a/src/protocols/tn5250/settings.h b/src/protocols/tn5250/settings.h index ee77f136..6c36babb 100644 --- a/src/protocols/tn5250/settings.h +++ b/src/protocols/tn5250/settings.h @@ -31,63 +31,170 @@ /** * The name of the font to use for the terminal if no name is specified. */ -#define GUAC_TELNET_DEFAULT_FONT_NAME "monospace" +#define GUAC_TN5250_DEFAULT_FONT_NAME "monospace" /** * The size of the font to use for the terminal if no font size is specified, * in points. */ -#define GUAC_TELNET_DEFAULT_FONT_SIZE 12 +#define GUAC_TN5250_DEFAULT_FONT_SIZE 12 /** - * The port to connect to when initiating any telnet connection, if no other + * The port to connect to when initiating a 5250 telnet connection, if no other * port is specified. */ -#define GUAC_TELNET_DEFAULT_PORT "23" +#define GUAC_TN5250_DEFAULT_PORT "23" + +/** + * The port to connect to when initiating a 5250 telnet connection over SSL, + * if no other port is specified. + */ +#define GUAC_TN5250_DEFAULT_SSL_PORT "992" /** * The filename to use for the typescript, if not specified. */ -#define GUAC_TELNET_DEFAULT_TYPESCRIPT_NAME "typescript" +#define GUAC_TN5250_DEFAULT_TYPESCRIPT_NAME "typescript" /** * The filename to use for the screen recording, if not specified. */ -#define GUAC_TELNET_DEFAULT_RECORDING_NAME "recording" +#define GUAC_TN5250_DEFAULT_RECORDING_NAME "recording" /** * The regular expression to use when searching for the username/login prompt * if no other regular expression is specified. */ -#define GUAC_TELNET_DEFAULT_USERNAME_REGEX "[Ll]ogin:" +#define GUAC_TN5250_DEFAULT_USERNAME_REGEX "[Ll]ogin:" /** * The regular expression to use when searching for the password prompt if no * other regular expression is specified. */ -#define GUAC_TELNET_DEFAULT_PASSWORD_REGEX "[Pp]assword:" +#define GUAC_TN5250_DEFAULT_PASSWORD_REGEX "[Pp]assword:" /** * The default maximum scrollback size in rows. */ -#define GUAC_TELNET_DEFAULT_MAX_SCROLLBACK 1000 +#define GUAC_TN5250_DEFAULT_MAX_SCROLLBACK 1000 /** - * Settings for the telnet connection. The values for this structure are parsed - * from the arguments given during the Guacamole protocol handshake using the - * guac_telnet_parse_args() function. + * The available terminal types for TN5250 connections. These are defined + * in RFC-1205, Section 2. */ -typedef struct guac_telnet_settings { +typedef enum guac_tn5250_terminal_types { + + /** + * IBM-3179-2, 24 x 80 color display + */ + IBM_3179_2, /** - * The hostname of the telnet server to connect to. + * IBM-3180-2, 27 x 132 monochrome display + */ + IBM_3180_2, + + /** + * IBM-3196-A1, 24 x 80 monochrome display + */ + IBM_3196_A1, + + /** + * IBM-3477-FC, 27 x 132 color display + */ + IBM_3477_FC, + + /** + * IBM-3477-FG, 27 x 132 monochrome display + */ + IBM_3477_FG, + + /** + * IBM-5251-11, 24 x 80 monochrome display + */ + IBM_5251_11, + + /** + * IBM-5291-1, 24 x 80 monochrome display + */ + IBM_5291_1, + + /** + * IBM-5292-2, 24 x 80 color display + */ + IBM_5292_2, + + /** + * IBM-5555-B01, 24 x 80 Double-Byte Character Set (DBCS) + */ + IBM_5555_B01, + + /** + * IBM-5555-C01, 24 x 80 Double-Byte Character Set color display + */ + IBM_5555_C01 + +} guac_tn5250_terminal_type; + +typedef struct __guac_tn5250_terminal_params { + + /** + * The type of terminal, as defined in RFC-1205 + */ + guac_tn5250_terminal_type terminal; + + /** + * The number of rows in the terminal + */ + int rows; + + /** + * The number of columns in the terminal + */ + int cols; + + /** + * True if the terminal supports color, false if only monochrome. + */ + bool color; + +} __guac_tn5250_terminal_params; + +__guac_tn5250_terminal_params __guac_tn5250_terminals[] = { + {IBM_3179_2, 24, 80, true }, + {IBM_3180_2, 27, 132, false}, + {IBM_3196_A1, 24, 80, false}, + {IBM_3477_FC, 27, 132, true }, + {IBM_3477_FG, 27, 132, false}, + {IBM_5251_11, 24, 80, false}, + {IBM_5291_1, 24, 80, false}, + {IBM_5292_2, 24, 80, true }, + {IBM_5555_B01, 24, 80, false}, + {IBM_5555_C01, 24, 80, true }, + {NULL, -1, -1, false} +} + +/** + * Settings for the TN5250 connection. The values for this structure are parsed + * from the arguments given during the Guacamole protocol handshake using the + * guac_tn5250_parse_args() function. + */ +typedef struct guac_tn5250_settings { + + /** + * The hostname of the TN5250 server to connect to. */ char* hostname; /** - * The port of the telnet server to connect to. + * The port of the TN5250 server to connect to. */ char* port; + + /** + * Whether or not to use SSL. + */ + bool ssl; /** * The name of the user to login as, if any. If no username is specified, @@ -246,7 +353,7 @@ typedef struct guac_telnet_settings { bool recording_include_keys; /** - * The ASCII code, as an integer, that the telnet client will use when the + * The ASCII code, as an integer, that the 5250 client will use when the * backspace key is pressed. By default, this is 127, ASCII delete, if * not specified in the client settings. */ @@ -255,9 +362,9 @@ typedef struct guac_telnet_settings { /** * The terminal emulator type that is passed to the remote system. */ - char* terminal_type; + guac_tn5250_terminal_type terminal_type; -} guac_telnet_settings; +} guac_tn5250_settings; /** * Parses all given args, storing them in a newly-allocated settings object. If @@ -275,10 +382,10 @@ typedef struct guac_telnet_settings { * * @return * A newly-allocated settings object which must be freed with - * guac_telnet_settings_free() when no longer needed. If the arguments fail + * guac_tn5250_settings_free() when no longer needed. If the arguments fail * to parse, NULL is returned. */ -guac_telnet_settings* guac_telnet_parse_args(guac_user* user, +guac_tn5250_settings* guac_tn5250_parse_args(guac_user* user, int argc, const char** argv); /** @@ -289,21 +396,21 @@ guac_telnet_settings* guac_telnet_parse_args(guac_user* user, * @param regex * The address of the pointer to the regex that should be freed. */ -void guac_telnet_regex_free(regex_t** regex); +void guac_tn5250_regex_free(regex_t** regex); /** - * Frees the given guac_telnet_settings object, having been previously - * allocated via guac_telnet_parse_args(). + * Frees the given guac_tn5250_settings object, having been previously + * allocated via guac_tn5250_parse_args(). * * @param settings * The settings object to free. */ -void guac_telnet_settings_free(guac_telnet_settings* settings); +void guac_tn5250_settings_free(guac_tn5250_settings* settings); /** * NULL-terminated array of accepted client args. */ -extern const char* GUAC_TELNET_CLIENT_ARGS[]; +extern const char* GUAC_TN5250_CLIENT_ARGS[]; #endif diff --git a/src/protocols/tn5250/tn5250.c b/src/protocols/tn5250/tn5250.c index 03e39435..3ec76b5c 100644 --- a/src/protocols/tn5250/tn5250.c +++ b/src/protocols/tn5250/tn5250.c @@ -88,13 +88,13 @@ static int __guac_telnet_write_all(int fd, const char* buffer, int size) { * sent after the value is sent. * * @param client - * The guac_client associated with the telnet session. + * The guac_client associated with the tn5250 session. * * @param regex * The regex to search for within the given line buffer. * * @param value - * The string value to send through STDIN of the telnet session if a + * The string value to send through STDIN of the tn5250 session if a * match is found, or NULL if no value should be sent. * * @param line_buffer @@ -103,18 +103,18 @@ static int __guac_telnet_write_all(int fd, const char* buffer, int size) { * @return * true if a match is found, false otherwise. */ -static bool guac_telnet_regex_exec(guac_client* client, regex_t* regex, +static bool guac_tn5250_regex_exec(guac_client* client, regex_t* regex, const char* value, const char* line_buffer) { - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; /* Send value upon match */ if (regexec(regex, line_buffer, 0, NULL, 0) == 0) { /* Send value */ if (value != NULL) { - guac_terminal_send_string(telnet_client->term, value); - guac_terminal_send_string(telnet_client->term, "\x0D"); + guac_terminal_send_string(tn5250_client->term, value); + guac_terminal_send_string(tn5250_client->term, "\x0D"); } /* Stop searching for prompt */ @@ -134,60 +134,60 @@ static bool guac_telnet_regex_exec(guac_client* client, regex_t* regex, * completed, this function has no effect. * * @param client - * The guac_client associated with the telnet session. + * The guac_client associated with the tn5250 session. * * @param line_buffer * The line of character data to test. */ -static void guac_telnet_search_line(guac_client* client, const char* line_buffer) { +static void guac_tn5250_search_line(guac_client* client, const char* line_buffer) { - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; - guac_telnet_settings* settings = telnet_client->settings; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; + guac_tn5250_settings* settings = tn5250_client->settings; /* Continue search for username prompt */ if (settings->username_regex != NULL) { - if (guac_telnet_regex_exec(client, settings->username_regex, + if (guac_tn5250_regex_exec(client, settings->username_regex, settings->username, line_buffer)) { guac_client_log(client, GUAC_LOG_DEBUG, "Username sent"); - guac_telnet_regex_free(&settings->username_regex); + guac_tn5250_regex_free(&settings->username_regex); } } /* Continue search for password prompt */ if (settings->password_regex != NULL) { - if (guac_telnet_regex_exec(client, settings->password_regex, + if (guac_tn5250_regex_exec(client, settings->password_regex, settings->password, line_buffer)) { guac_client_log(client, GUAC_LOG_DEBUG, "Password sent"); /* Do not continue searching for username/password once password is sent */ - guac_telnet_regex_free(&settings->username_regex); - guac_telnet_regex_free(&settings->password_regex); + guac_tn5250_regex_free(&settings->username_regex); + guac_tn5250_regex_free(&settings->password_regex); } } /* Continue search for login success */ if (settings->login_success_regex != NULL) { - if (guac_telnet_regex_exec(client, settings->login_success_regex, + if (guac_tn5250_regex_exec(client, settings->login_success_regex, NULL, line_buffer)) { /* Allow terminal to render now that login has been deemed successful */ guac_client_log(client, GUAC_LOG_DEBUG, "Login successful"); - guac_terminal_start(telnet_client->term); + guac_terminal_start(tn5250_client->term); /* Stop all searches */ - guac_telnet_regex_free(&settings->username_regex); - guac_telnet_regex_free(&settings->password_regex); - guac_telnet_regex_free(&settings->login_success_regex); - guac_telnet_regex_free(&settings->login_failure_regex); + guac_tn5250_regex_free(&settings->username_regex); + guac_tn5250_regex_free(&settings->password_regex); + guac_tn5250_regex_free(&settings->login_success_regex); + guac_tn5250_regex_free(&settings->login_failure_regex); } } /* Continue search for login failure */ if (settings->login_failure_regex != NULL) { - if (guac_telnet_regex_exec(client, settings->login_failure_regex, + if (guac_tn5250_regex_exec(client, settings->login_failure_regex, NULL, line_buffer)) { /* Advise that login has failed and connection should be closed */ @@ -196,10 +196,10 @@ static void guac_telnet_search_line(guac_client* client, const char* line_buffer "Login failed"); /* Stop all searches */ - guac_telnet_regex_free(&settings->username_regex); - guac_telnet_regex_free(&settings->password_regex); - guac_telnet_regex_free(&settings->login_success_regex); - guac_telnet_regex_free(&settings->login_failure_regex); + guac_tn5250_regex_free(&settings->username_regex); + guac_tn5250_regex_free(&settings->password_regex); + guac_tn5250_regex_free(&settings->login_success_regex); + guac_tn5250_regex_free(&settings->login_failure_regex); } } @@ -214,7 +214,7 @@ static void guac_telnet_search_line(guac_client* client, const char* line_buffer * have completed, this function has no effect. * * @param client - * The guac_client associated with the telnet session. + * The guac_client associated with the tn5250 session. * * @param buffer * The buffer of received data to search through. @@ -222,7 +222,7 @@ static void guac_telnet_search_line(guac_client* client, const char* line_buffer * @param size * The size of the given buffer, in bytes. */ -static void guac_telnet_search(guac_client* client, const char* buffer, int size) { +static void guac_tn5250_search(guac_client* client, const char* buffer, int size) { static char line_buffer[1024] = {0}; static int length = 0; @@ -237,7 +237,7 @@ static void guac_telnet_search(guac_client* client, const char* buffer, int size if (c == '\n') { if (length > 0) { line_buffer[length] = '\0'; - guac_telnet_search_line(client, line_buffer); + guac_tn5250_search_line(client, line_buffer); length = 0; } } @@ -252,7 +252,7 @@ static void guac_telnet_search(guac_client* client, const char* buffer, int size /* Attempt pattern match if an unfinished line remains (may be a prompt) */ if (length > 0) { line_buffer[length] = '\0'; - guac_telnet_search_line(client, line_buffer); + guac_tn5250_search_line(client, line_buffer); } } @@ -262,23 +262,23 @@ static void guac_telnet_search(guac_client* client, const char* buffer, int size * telnet_init() and will be called for every event fired by libtelnet, * including feature enable/disable and receipt/transmission of data. */ -static void __guac_telnet_event_handler(telnet_t* telnet, telnet_event_t* event, void* data) { +static void __guac_tn5250_event_handler(telnet_t* telnet, telnet_event_t* event, void* data) { guac_client* client = (guac_client*) data; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; - guac_telnet_settings* settings = telnet_client->settings; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; + guac_tn5250_settings* settings = tn5250_client->settings; switch (event->type) { /* Terminal output received */ case TELNET_EV_DATA: - guac_terminal_write(telnet_client->term, event->data.buffer, event->data.size); - guac_telnet_search(client, event->data.buffer, event->data.size); + guac_terminal_write(tn5250_client->term, event->data.buffer, event->data.size); + guac_tn5250_search(client, event->data.buffer, event->data.size); break; /* Data destined for remote end */ case TELNET_EV_SEND: - if (__guac_telnet_write_all(telnet_client->socket_fd, event->data.buffer, event->data.size) + if (__guac_tn5250_write_all(tn5250_client->socket_fd, event->data.buffer, event->data.size) != event->data.size) guac_client_stop(client); break; @@ -286,27 +286,27 @@ static void __guac_telnet_event_handler(telnet_t* telnet, telnet_event_t* event, /* Remote feature enabled */ case TELNET_EV_WILL: if (event->neg.telopt == TELNET_TELOPT_ECHO) - telnet_client->echo_enabled = 0; /* Disable local echo, as remote will echo */ + tn5250_client->echo_enabled = 0; /* Disable local echo, as remote will echo */ break; /* Remote feature disabled */ case TELNET_EV_WONT: if (event->neg.telopt == TELNET_TELOPT_ECHO) - telnet_client->echo_enabled = 1; /* Enable local echo, as remote won't echo */ + tn5250_client->echo_enabled = 1; /* Enable local echo, as remote won't echo */ break; /* Local feature enable */ case TELNET_EV_DO: if (event->neg.telopt == TELNET_TELOPT_NAWS) { - telnet_client->naws_enabled = 1; - guac_telnet_send_naws(telnet, telnet_client->term->term_width, telnet_client->term->term_height); + tn5250_client->naws_enabled = 1; + guac_tn5250_send_naws(telnet, tn5250_client->term->term_width, tn5250_client->term->term_height); } break; /* Terminal type request */ case TELNET_EV_TTYPE: if (event->ttype.cmd == TELNET_TTYPE_SEND) - telnet_ttype_is(telnet_client->telnet, settings->terminal_type); + tn5250_ttype_is(tn5250_client->telnet, settings->terminal_type); break; /* Environment request */ @@ -314,7 +314,7 @@ static void __guac_telnet_event_handler(telnet_t* telnet, telnet_event_t* event, /* Only send USER if entire environment was requested */ if (event->environ.size == 0) - guac_telnet_send_user(telnet, settings->username); + guac_tn5250_send_user(telnet, settings->username); break; @@ -345,19 +345,19 @@ static void __guac_telnet_event_handler(telnet_t* telnet, telnet_event_t* event, * @param data The current guac_client instance. * @return Always NULL. */ -static void* __guac_telnet_input_thread(void* data) { +static void* __guac_tn5250_input_thread(void* data) { guac_client* client = (guac_client*) data; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; char buffer[8192]; int bytes_read; /* Write all data read */ - while ((bytes_read = guac_terminal_read_stdin(telnet_client->term, buffer, sizeof(buffer))) > 0) { - telnet_send(telnet_client->telnet, buffer, bytes_read); - if (telnet_client->echo_enabled) - guac_terminal_write(telnet_client->term, buffer, bytes_read); + while ((bytes_read = guac_terminal_read_stdin(tn5250_client->term, buffer, sizeof(buffer))) > 0) { + telnet_send(tn5250_client->telnet, buffer, bytes_read); + if (tn5250_client->echo_enabled) + guac_terminal_write(tn5250_client->term, buffer, bytes_read); } return NULL; @@ -372,7 +372,7 @@ static void* __guac_telnet_input_thread(void* data) { * @return The connected telnet instance, if successful, or NULL if the * connection fails for any reason. */ -static telnet_t* __guac_telnet_create_session(guac_client* client) { +static telnet_t* __guac_tn5250_create_session(guac_client* client) { int retval; @@ -383,8 +383,8 @@ static telnet_t* __guac_telnet_create_session(guac_client* client) { char connected_address[1024]; char connected_port[64]; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; - guac_telnet_settings* settings = telnet_client->settings; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; + guac_tn5250_settings* settings = tn5250_client->settings; struct addrinfo hints = { .ai_family = AF_UNSPEC, @@ -458,7 +458,7 @@ static telnet_t* __guac_telnet_create_session(guac_client* client) { } /* Save file descriptor */ - telnet_client->socket_fd = fd; + tn5250_client->socket_fd = fd; return telnet; @@ -471,7 +471,7 @@ static telnet_t* __guac_telnet_create_session(guac_client* client) { * @param telnet The telnet connection to use. * @param value The value to send. */ -static void __guac_telnet_send_uint16(telnet_t* telnet, uint16_t value) { +static void __guac_tn5250_send_uint16(telnet_t* telnet, uint16_t value) { unsigned char buffer[2]; buffer[0] = (value >> 8) & 0xFF; @@ -487,32 +487,32 @@ static void __guac_telnet_send_uint16(telnet_t* telnet, uint16_t value) { * @param telnet The telnet connection to use. * @param value The value to send. */ -static void __guac_telnet_send_uint8(telnet_t* telnet, uint8_t value) { +static void __guac_tn5250_send_uint8(telnet_t* telnet, uint8_t value) { telnet_send(telnet, (char*) (&value), 1); } -void guac_telnet_send_naws(telnet_t* telnet, uint16_t width, uint16_t height) { +void guac_tn5250_send_naws(telnet_t* telnet, uint16_t width, uint16_t height) { telnet_begin_sb(telnet, TELNET_TELOPT_NAWS); - __guac_telnet_send_uint16(telnet, width); - __guac_telnet_send_uint16(telnet, height); + __guac_tn5250_send_uint16(telnet, width); + __guac_tn5250_send_uint16(telnet, height); telnet_finish_sb(telnet); } -void guac_telnet_send_user(telnet_t* telnet, const char* username) { +void guac_tn5250_send_user(telnet_t* telnet, const char* username) { /* IAC SB NEW-ENVIRON IS */ telnet_begin_sb(telnet, TELNET_TELOPT_NEW_ENVIRON); - __guac_telnet_send_uint8(telnet, TELNET_ENVIRON_IS); + __guac_tn5250_send_uint8(telnet, TELNET_ENVIRON_IS); /* Only send username if defined */ if (username != NULL) { /* VAR "USER" */ - __guac_telnet_send_uint8(telnet, TELNET_ENVIRON_VAR); + __guac_tn5250_send_uint8(telnet, TELNET_ENVIRON_VAR); telnet_send(telnet, "USER", 4); /* VALUE username */ - __guac_telnet_send_uint8(telnet, TELNET_ENVIRON_VALUE); + __guac_tn5250_send_uint8(telnet, TELNET_ENVIRON_VALUE); telnet_send(telnet, username, strlen(username)); } @@ -531,7 +531,7 @@ void guac_telnet_send_user(telnet_t* telnet, const char* username) { * @return A value greater than zero on success, zero on timeout, and * less than zero on error. */ -static int __guac_telnet_wait(int socket_fd) { +static int __guac_tn5250_wait(int socket_fd) { /* Build array of file descriptors */ struct pollfd fds[] = {{ @@ -545,11 +545,11 @@ static int __guac_telnet_wait(int socket_fd) { } -void* guac_telnet_client_thread(void* data) { +void* guac_tn5250_client_thread(void* data) { guac_client* client = (guac_client*) data; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; - guac_telnet_settings* settings = telnet_client->settings; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; + guac_tn5250_settings* settings = tn5250_client->settings; pthread_t input_thread; char buffer[8192]; @@ -557,7 +557,7 @@ void* guac_telnet_client_thread(void* data) { /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { - telnet_client->recording = guac_common_recording_create(client, + tn5250_client->recording = guac_common_recording_create(client, settings->recording_path, settings->recording_name, settings->create_recording_path, @@ -567,14 +567,14 @@ void* guac_telnet_client_thread(void* data) { } /* Create terminal */ - telnet_client->term = guac_terminal_create(client, - telnet_client->clipboard, settings->disable_copy, + tn5250_client->term = guac_terminal_create(client, + tn5250_client->clipboard, settings->disable_copy, settings->max_scrollback, settings->font_name, settings->font_size, settings->resolution, settings->width, settings->height, settings->color_scheme, settings->backspace); /* Fail if terminal init failed */ - if (telnet_client->term == NULL) { + if (tn5250_client->term == NULL) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Terminal initialization failed"); return NULL; @@ -582,46 +582,46 @@ void* guac_telnet_client_thread(void* data) { /* Set up typescript, if requested */ if (settings->typescript_path != NULL) { - guac_terminal_create_typescript(telnet_client->term, + guac_terminal_create_typescript(tn5250_client->term, settings->typescript_path, settings->typescript_name, settings->create_typescript_path); } /* Open telnet session */ - telnet_client->telnet = __guac_telnet_create_session(client); - if (telnet_client->telnet == NULL) { - /* Already aborted within __guac_telnet_create_session() */ + tn5250_client->telnet = __guac_tn5250_create_session(client); + if (tn5250_client->telnet == NULL) { + /* Already aborted within __guac_tn5250_create_session() */ return NULL; } /* Logged in */ - guac_client_log(client, GUAC_LOG_INFO, "Telnet connection successful."); + guac_client_log(client, GUAC_LOG_INFO, "TN5250 connection successful."); /* Allow terminal to render if login success/failure detection is not * enabled */ if (settings->login_success_regex == NULL && settings->login_failure_regex == NULL) - guac_terminal_start(telnet_client->term); + guac_terminal_start(tn5250_client->term); /* Start input thread */ - if (pthread_create(&(input_thread), NULL, __guac_telnet_input_thread, (void*) client)) { + if (pthread_create(&(input_thread), NULL, __guac_tn5250_input_thread, (void*) client)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to start input thread"); return NULL; } /* While data available, write to terminal */ - while ((wait_result = __guac_telnet_wait(telnet_client->socket_fd)) >= 0) { + while ((wait_result = __guac_tn5250_wait(tn5250_client->socket_fd)) >= 0) { /* Resume waiting of no data available */ if (wait_result == 0) continue; - int bytes_read = read(telnet_client->socket_fd, buffer, sizeof(buffer)); + int bytes_read = read(tn5250_client->socket_fd, buffer, sizeof(buffer)); if (bytes_read <= 0) break; - telnet_recv(telnet_client->telnet, buffer, bytes_read); + telnet_recv(tn5250_client->telnet, buffer, bytes_read); } @@ -629,7 +629,7 @@ void* guac_telnet_client_thread(void* data) { guac_client_stop(client); pthread_join(input_thread, NULL); - guac_client_log(client, GUAC_LOG_INFO, "Telnet connection ended."); + guac_client_log(client, GUAC_LOG_INFO, "TN5250 connection ended."); return NULL; } diff --git a/src/protocols/tn5250/tn5250.h b/src/protocols/tn5250/tn5250.h index 0d0913b5..50228797 100644 --- a/src/protocols/tn5250/tn5250.h +++ b/src/protocols/tn5250/tn5250.h @@ -33,12 +33,12 @@ /** * Telnet-specific client data. */ -typedef struct guac_telnet_client { +typedef struct guac_tn5250_client { /** * Telnet connection settings. */ - guac_telnet_settings* settings; + guac_tn5250_settings* settings; /** * The telnet client thread. @@ -83,24 +83,24 @@ typedef struct guac_telnet_client { */ guac_common_recording* recording; -} guac_telnet_client; +} guac_tn5250_client; /** - * Main telnet client thread, handling transfer of telnet output to STDOUT. + * Main tn5250 client thread, handling transfer of tn5250 output to STDOUT. */ -void* guac_telnet_client_thread(void* data); +void* guac_tn5250_client_thread(void* data); /** * Send a telnet NAWS message indicating the given terminal window dimensions * in characters. */ -void guac_telnet_send_naws(telnet_t* telnet, uint16_t width, uint16_t height); +void guac_tn5250_send_naws(telnet_t* telnet, uint16_t width, uint16_t height); /** * Sends the given username by setting the remote USER environment variable - * using the telnet NEW-ENVIRON option. + * using the tn5250 NEW-ENVIRON option. */ -void guac_telnet_send_user(telnet_t* telnet, const char* username); +void guac_tn5250_send_user(telnet_t* telnet, const char* username); #endif diff --git a/src/protocols/tn5250/user.c b/src/protocols/tn5250/user.c index 2d15f9b4..294f4663 100644 --- a/src/protocols/tn5250/user.c +++ b/src/protocols/tn5250/user.c @@ -35,13 +35,13 @@ #include #include -int guac_telnet_user_join_handler(guac_user* user, int argc, char** argv) { +int guac_tn5250_user_join_handler(guac_user* user, int argc, char** argv) { guac_client* client = user->client; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; + guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data; /* Parse provided arguments */ - guac_telnet_settings* settings = guac_telnet_parse_args(user, + guac_tn5250_settings* settings = guac_tn5250_parse_args(user, argc, (const char**) argv); /* Fail if settings cannot be parsed */ @@ -54,17 +54,17 @@ int guac_telnet_user_join_handler(guac_user* user, int argc, char** argv) { /* Store settings at user level */ user->data = settings; - /* Connect via telnet if owner */ + /* Connect via tn5250 if owner */ if (user->owner) { /* Store owner's settings at client level */ - telnet_client->settings = settings; + tn5250_client->settings = settings; /* Start client thread */ - if (pthread_create(&(telnet_client->client_thread), NULL, - guac_telnet_client_thread, (void*) client)) { + if (pthread_create(&(tn5250_client->client_thread), NULL, + guac_tn5250_client_thread, (void*) client)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, - "Unable to start telnet client thread"); + "Unable to start tn5250 client thread"); return 1; } @@ -72,7 +72,7 @@ int guac_telnet_user_join_handler(guac_user* user, int argc, char** argv) { /* If not owner, synchronize with current display */ else { - guac_terminal_dup(telnet_client->term, user, user->socket); + guac_terminal_dup(tn5250_client->term, user, user->socket); guac_socket_flush(user->socket); } @@ -80,21 +80,21 @@ int guac_telnet_user_join_handler(guac_user* user, int argc, char** argv) { if (!settings->read_only) { /* General mouse/keyboard events */ - user->key_handler = guac_telnet_user_key_handler; - user->mouse_handler = guac_telnet_user_mouse_handler; + user->key_handler = guac_tn5250_user_key_handler; + user->mouse_handler = guac_tn5250_user_mouse_handler; /* Inbound (client to server) clipboard transfer */ if (!settings->disable_paste) - user->clipboard_handler = guac_telnet_clipboard_handler; + user->clipboard_handler = guac_tn5250_clipboard_handler; /* STDIN redirection */ - user->pipe_handler = guac_telnet_pipe_handler; + user->pipe_handler = guac_tn5250_pipe_handler; /* Updates to connection parameters */ - user->argv_handler = guac_telnet_argv_handler; + user->argv_handler = guac_tn5250_argv_handler; /* Display size change events */ - user->size_handler = guac_telnet_user_size_handler; + user->size_handler = guac_tn5250_user_size_handler; } @@ -102,18 +102,18 @@ int guac_telnet_user_join_handler(guac_user* user, int argc, char** argv) { } -int guac_telnet_user_leave_handler(guac_user* user) { +int guac_tn5250_user_leave_handler(guac_user* user) { - guac_telnet_client* telnet_client = - (guac_telnet_client*) user->client->data; + guac_tn5250_client* tn5250_client = + (guac_tn5250_client*) user->client->data; /* Update shared cursor state */ - guac_common_cursor_remove_user(telnet_client->term->cursor, user); + guac_common_cursor_remove_user(tn5250_client->term->cursor, user); /* Free settings if not owner (owner settings will be freed with client) */ if (!user->owner) { - guac_telnet_settings* settings = (guac_telnet_settings*) user->data; - guac_telnet_settings_free(settings); + guac_tn5250_settings* settings = (guac_tn5250_settings*) user->data; + guac_tn5250_settings_free(settings); } return 0; diff --git a/src/protocols/tn5250/user.h b/src/protocols/tn5250/user.h index 62fb0edb..d9ec386c 100644 --- a/src/protocols/tn5250/user.h +++ b/src/protocols/tn5250/user.h @@ -27,12 +27,12 @@ /** * Handler for joining users. */ -guac_user_join_handler guac_telnet_user_join_handler; +guac_user_join_handler guac_tn5250_user_join_handler; /** * Handler for leaving users. */ -guac_user_leave_handler guac_telnet_user_leave_handler; +guac_user_leave_handler guac_tn5250_user_leave_handler; #endif