Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9ece4b7a5b | ||
|
39a1c25e9b | ||
|
e1d28d7dee | ||
|
19899756a0 | ||
|
30ec3be924 | ||
|
22fe81913f |
2
.gitignore
vendored
2
.gitignore
vendored
@ -46,3 +46,5 @@ stamp-h1
|
||||
# Generated docs
|
||||
doc/doxygen-output
|
||||
|
||||
# IDE Configuration
|
||||
nbproject/
|
@ -39,6 +39,7 @@ DIST_SUBDIRS = \
|
||||
src/protocols/rdp \
|
||||
src/protocols/ssh \
|
||||
src/protocols/telnet \
|
||||
src/protocols/tn5250 \
|
||||
src/protocols/vnc
|
||||
|
||||
SUBDIRS = \
|
||||
@ -71,6 +72,7 @@ endif
|
||||
|
||||
if ENABLE_TELNET
|
||||
SUBDIRS += src/protocols/telnet
|
||||
SUBDIRS += src/protocols/tn5250
|
||||
endif
|
||||
|
||||
if ENABLE_VNC
|
||||
|
@ -1382,6 +1382,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/protocols/rdp/tests/Makefile
|
||||
src/protocols/ssh/Makefile
|
||||
src/protocols/telnet/Makefile
|
||||
src/protocols/tn5250/Makefile
|
||||
src/protocols/vnc/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
@ -1447,6 +1448,7 @@ $PACKAGE_NAME version $PACKAGE_VERSION
|
||||
RDP ........... ${build_rdp}
|
||||
SSH ........... ${build_ssh}
|
||||
Telnet ........ ${build_telnet}
|
||||
TN5250 ........ ${build_telnet}
|
||||
VNC ........... ${build_vnc}
|
||||
|
||||
Services / tools:
|
||||
|
65
src/protocols/tn5250/Makefile.am
Normal file
65
src/protocols/tn5250/Makefile.am
Normal file
@ -0,0 +1,65 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
|
||||
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
|
||||
# its own license boilerplate to the generated Makefile.in, that boilerplate
|
||||
# does not apply to the transcluded portions of Makefile.am which are licensed
|
||||
# to you by the ASF under the Apache License, Version 2.0, as described above.
|
||||
#
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
lib_LTLIBRARIES = libguac-client-tn5250.la
|
||||
|
||||
libguac_client_tn5250_la_SOURCES = \
|
||||
argv.c \
|
||||
client.c \
|
||||
clipboard.c \
|
||||
input.c \
|
||||
pipe.c \
|
||||
settings.c \
|
||||
tn5250.c \
|
||||
user.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
argv.h \
|
||||
client.h \
|
||||
clipboard.h \
|
||||
input.h \
|
||||
pipe.h \
|
||||
settings.h \
|
||||
tn5250.h \
|
||||
user.h
|
||||
|
||||
libguac_client_tn5250_la_CFLAGS = \
|
||||
-Werror -Wall -Iinclude \
|
||||
@LIBGUAC_INCLUDE@ \
|
||||
@TERMINAL_INCLUDE@
|
||||
|
||||
libguac_client_tn5250_la_LIBADD = \
|
||||
@COMMON_LTLIB@ \
|
||||
@LIBGUAC_LTLIB@ \
|
||||
@TERMINAL_LTLIB@
|
||||
|
||||
libguac_client_tn5250_la_LDFLAGS = \
|
||||
-version-info 0:0:0 \
|
||||
@PTHREAD_LIBS@ \
|
||||
@TN5250_LIBS@
|
||||
|
196
src/protocols/tn5250/argv.c
Normal file
196
src/protocols/tn5250/argv.c
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "argv.h"
|
||||
#include "tn5250.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* All tn5250 connection settings which may be updated by unprivileged users
|
||||
* through "argv" streams.
|
||||
*/
|
||||
typedef enum guac_tn5250_argv_setting {
|
||||
|
||||
/**
|
||||
* The color scheme of the terminal.
|
||||
*/
|
||||
GUAC_TN5250_ARGV_SETTING_COLOR_SCHEME,
|
||||
|
||||
/**
|
||||
* The name of the font family used by the terminal.
|
||||
*/
|
||||
GUAC_TN5250_ARGV_SETTING_FONT_NAME,
|
||||
|
||||
/**
|
||||
* The size of the font used by the terminal, in points.
|
||||
*/
|
||||
GUAC_TN5250_ARGV_SETTING_FONT_SIZE
|
||||
|
||||
} guac_tn5250_argv_setting;
|
||||
|
||||
/**
|
||||
* The value or current status of a connection parameter received over an
|
||||
* "argv" stream.
|
||||
*/
|
||||
typedef struct guac_tn5250_argv {
|
||||
|
||||
/**
|
||||
* The specific setting being updated.
|
||||
*/
|
||||
guac_tn5250_argv_setting setting;
|
||||
|
||||
/**
|
||||
* Buffer space for containing the received argument value.
|
||||
*/
|
||||
char buffer[GUAC_TN5250_ARGV_MAX_LENGTH];
|
||||
|
||||
/**
|
||||
* The number of bytes received so far.
|
||||
*/
|
||||
int length;
|
||||
|
||||
} guac_tn5250_argv;
|
||||
|
||||
/**
|
||||
* Handler for "blob" instructions which appends the data from received blobs
|
||||
* to the end of the in-progress argument value buffer.
|
||||
*
|
||||
* @see guac_user_blob_handler
|
||||
*/
|
||||
static int guac_tn5250_argv_blob_handler(guac_user* user,
|
||||
guac_stream* stream, void* data, int length) {
|
||||
|
||||
guac_tn5250_argv* argv = (guac_tn5250_argv*) stream->data;
|
||||
|
||||
/* Calculate buffer size remaining, including space for null terminator,
|
||||
* adjusting received length accordingly */
|
||||
int remaining = sizeof(argv->buffer) - argv->length - 1;
|
||||
if (length > remaining)
|
||||
length = remaining;
|
||||
|
||||
/* Append received data to end of buffer */
|
||||
memcpy(argv->buffer + argv->length, data, length);
|
||||
argv->length += length;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for "end" instructions which applies the changes specified by the
|
||||
* argument value buffer associated with the stream.
|
||||
*
|
||||
* @see guac_user_end_handler
|
||||
*/
|
||||
static int guac_tn5250_argv_end_handler(guac_user* user,
|
||||
guac_stream* stream) {
|
||||
|
||||
int size;
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data;
|
||||
guac_terminal* terminal = tn5250_client->term;
|
||||
|
||||
/* Append null terminator to value */
|
||||
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_TN5250_ARGV_SETTING_COLOR_SCHEME:
|
||||
guac_terminal_apply_color_scheme(terminal, argv->buffer);
|
||||
break;
|
||||
|
||||
/* Update font name */
|
||||
case GUAC_TN5250_ARGV_SETTING_FONT_NAME:
|
||||
guac_terminal_apply_font(terminal, argv->buffer, -1, 0);
|
||||
break;
|
||||
|
||||
/* Update 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,
|
||||
tn5250_client->settings->resolution);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* Update terminal window size if connected */
|
||||
if (tn5250_client->tn5250 != NULL && tn5250_client->naws_enabled)
|
||||
guac_tn5250_send_naws(tn5250_client->tn5250, terminal->term_width,
|
||||
terminal->term_height);
|
||||
|
||||
free(argv);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_tn5250_argv_handler(guac_user* user, guac_stream* stream,
|
||||
char* mimetype, char* name) {
|
||||
|
||||
guac_tn5250_argv_setting setting;
|
||||
|
||||
/* Allow users to update the color scheme and font details */
|
||||
if (strcmp(name, "color-scheme") == 0)
|
||||
setting = GUAC_TN5250_ARGV_SETTING_COLOR_SCHEME;
|
||||
else if (strcmp(name, "font-name") == 0)
|
||||
setting = GUAC_TN5250_ARGV_SETTING_FONT_NAME;
|
||||
else if (strcmp(name, "font-size") == 0)
|
||||
setting = GUAC_TN5250_ARGV_SETTING_FONT_SIZE;
|
||||
|
||||
/* No other connection parameters may be updated */
|
||||
else {
|
||||
guac_protocol_send_ack(user->socket, stream, "Not allowed.",
|
||||
GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
|
||||
guac_socket_flush(user->socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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_tn5250_argv_blob_handler;
|
||||
stream->end_handler = guac_tn5250_argv_end_handler;
|
||||
stream->data = argv;
|
||||
|
||||
/* Signal stream is ready */
|
||||
guac_protocol_send_ack(user->socket, stream, "Ready for updated "
|
||||
"parameter.", GUAC_PROTOCOL_STATUS_SUCCESS);
|
||||
guac_socket_flush(user->socket);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
41
src/protocols/tn5250/argv.h
Normal file
41
src/protocols/tn5250/argv.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUAC_TN5250_ARGV_H
|
||||
#define GUAC_TN5250_ARGV_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* The maximum number of bytes to allow for any argument value received via an
|
||||
* argv stream, including null terminator.
|
||||
*/
|
||||
#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_tn5250_argv_handler;
|
||||
|
||||
#endif
|
||||
|
100
src/protocols/tn5250/client.c
Normal file
100
src/protocols/tn5250/client.c
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "client.h"
|
||||
#include "common/recording.h"
|
||||
#include "settings.h"
|
||||
#include "tn5250.h"
|
||||
#include "terminal/terminal.h"
|
||||
#include "user.h"
|
||||
|
||||
#include <langinfo.h>
|
||||
#include <locale.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
int guac_client_init(guac_client* client) {
|
||||
|
||||
/* Set client args */
|
||||
client->args = GUAC_TN5250_CLIENT_ARGS;
|
||||
|
||||
/* Allocate client instance data */
|
||||
guac_tn5250_client* tn5250_client = calloc(1, sizeof(guac_tn5250_client));
|
||||
client->data = tn5250_client;
|
||||
|
||||
/* Init clipboard */
|
||||
tn5250_client->clipboard = guac_common_clipboard_alloc(GUAC_TN5250_CLIPBOARD_MAX_LENGTH);
|
||||
|
||||
/* Init tn5250 client */
|
||||
tn5250_client->socket_fd = -1;
|
||||
tn5250_client->naws_enabled = 0;
|
||||
tn5250_client->echo_enabled = 1;
|
||||
|
||||
/* Set handlers */
|
||||
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, "");
|
||||
if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0) {
|
||||
guac_client_log(client, GUAC_LOG_INFO,
|
||||
"Current locale does not use UTF-8. Some characters may "
|
||||
"not render correctly.");
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_tn5250_client_free_handler(guac_client* client) {
|
||||
|
||||
guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data;
|
||||
|
||||
/* Close tn5250 connection */
|
||||
if (tn5250_client->socket_fd != -1)
|
||||
close(tn5250_client->socket_fd);
|
||||
|
||||
/* Clean up recording, if in progress */
|
||||
if (tn5250_client->recording != NULL)
|
||||
guac_common_recording_free(tn5250_client->recording);
|
||||
|
||||
/* Kill terminal */
|
||||
guac_terminal_free(tn5250_client->term);
|
||||
|
||||
/* 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 (tn5250_client->settings != NULL)
|
||||
guac_tn5250_settings_free(tn5250_client->settings);
|
||||
|
||||
guac_common_clipboard_free(tn5250_client->clipboard);
|
||||
free(tn5250_client);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
44
src/protocols/tn5250/client.h
Normal file
44
src/protocols/tn5250/client.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_TN5250_CLIENT_H
|
||||
#define GUAC_TN5250_CLIENT_H
|
||||
|
||||
#include "config.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <regex.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libtelnet.h>
|
||||
|
||||
/**
|
||||
* The maximum number of bytes to allow within the clipboard.
|
||||
*/
|
||||
#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_tn5250_client_free_handler;
|
||||
|
||||
#endif
|
||||
|
62
src/protocols/tn5250/clipboard.c
Normal file
62
src/protocols/tn5250/clipboard.c
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "clipboard.h"
|
||||
#include "common/clipboard.h"
|
||||
#include "tn5250.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
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_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_tn5250_clipboard_blob_handler;
|
||||
stream->end_handler = guac_tn5250_clipboard_end_handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data;
|
||||
guac_common_clipboard_append(tn5250_client->clipboard, data, length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int guac_tn5250_clipboard_end_handler(guac_user* user, guac_stream* stream) {
|
||||
|
||||
/* Nothing to do - clipboard is implemented within client */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
43
src/protocols/tn5250/clipboard.h
Normal file
43
src/protocols/tn5250/clipboard.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_TN5250_CLIPBOARD_H
|
||||
#define GUAC_TN5250_CLIPBOARD_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Handler for inbound clipboard streams.
|
||||
*/
|
||||
guac_user_clipboard_handler guac_tn5250_clipboard_handler;
|
||||
|
||||
/**
|
||||
* Handler for data received along clipboard streams.
|
||||
*/
|
||||
guac_user_blob_handler guac_tn5250_clipboard_blob_handler;
|
||||
|
||||
/**
|
||||
* Handler for end-of-stream related to clipboard.
|
||||
*/
|
||||
guac_user_end_handler guac_tn5250_clipboard_end_handler;
|
||||
|
||||
#endif
|
||||
|
116
src/protocols/tn5250/input.c
Normal file
116
src/protocols/tn5250/input.c
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "common/recording.h"
|
||||
#include "input.h"
|
||||
#include "terminal/terminal.h"
|
||||
#include "tn5250.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/user.h>
|
||||
#include <libtelnet.h>
|
||||
|
||||
#include <regex.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int guac_tn5250_user_mouse_handler(guac_user* user, int x, int y, int mask) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
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 (tn5250_client->recording != NULL)
|
||||
guac_common_recording_report_mouse(tn5250_client->recording, x, y,
|
||||
mask);
|
||||
|
||||
/* Send mouse if not searching for password or username */
|
||||
if (settings->password_regex == NULL && settings->username_regex == NULL)
|
||||
guac_terminal_send_mouse(term, user, x, y, mask);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_tn5250_user_key_handler(guac_user* user, int keysym, int pressed) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
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 (tn5250_client->recording != NULL)
|
||||
guac_common_recording_report_key(tn5250_client->recording,
|
||||
keysym, pressed);
|
||||
|
||||
/* Skip if terminal not yet ready */
|
||||
if (term == NULL)
|
||||
return 0;
|
||||
|
||||
/* Intercept and handle Pause / Break / Ctrl+0 as "IAC BRK" */
|
||||
if (pressed && (
|
||||
keysym == 0xFF13 /* Pause */
|
||||
|| keysym == 0xFF6B /* Break */
|
||||
|| (term->mod_ctrl && keysym == '0') /* Ctrl + 0 */
|
||||
)) {
|
||||
|
||||
/* Send IAC BRK */
|
||||
telnet_iac(tn5250_client->telnet, TELNET_BREAK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send key */
|
||||
guac_terminal_send_key(term, keysym, pressed);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_tn5250_user_size_handler(guac_user* user, int width, int height) {
|
||||
|
||||
/* Get terminal */
|
||||
guac_client* client = user->client;
|
||||
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)
|
||||
return 0;
|
||||
|
||||
/* Resize terminal */
|
||||
guac_terminal_resize(terminal, width, height);
|
||||
|
||||
/* Update terminal window size if connected */
|
||||
if (tn5250_client->telnet != NULL && tn5250_client->naws_enabled)
|
||||
guac_tn5250_send_naws(tn5250_client->telnet, terminal->term_width,
|
||||
terminal->term_height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
46
src/protocols/tn5250/input.h
Normal file
46
src/protocols/tn5250/input.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_TN5250_INPUT_H
|
||||
#define GUAC_TN5250_INPUT_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Handler for key events. Required by libguac and called whenever key events
|
||||
* are received.
|
||||
*/
|
||||
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_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_tn5250_user_size_handler;
|
||||
|
||||
#endif
|
||||
|
50
src/protocols/tn5250/pipe.c
Normal file
50
src/protocols/tn5250/pipe.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pipe.h"
|
||||
#include "tn5250.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int guac_tn5250_pipe_handler(guac_user* user, guac_stream* stream,
|
||||
char* mimetype, char* name) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data;
|
||||
|
||||
/* Redirect STDIN if pipe has required name */
|
||||
if (strcmp(name, GUAC_TN5250_STDIN_PIPE_NAME) == 0) {
|
||||
guac_terminal_send_stream(tn5250_client->term, user, stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No other inbound pipe streams are supported */
|
||||
guac_protocol_send_ack(user->socket, stream, "No such input stream.",
|
||||
GUAC_PROTOCOL_STATUS_RESOURCE_NOT_FOUND);
|
||||
guac_socket_flush(user->socket);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
42
src/protocols/tn5250/pipe.h
Normal file
42
src/protocols/tn5250/pipe.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUAC_TN5250_PIPE_H
|
||||
#define GUAC_TN5250_PIPE_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* The name reserved for the inbound pipe stream which forces the terminal
|
||||
* emulator's STDIN to be received from the pipe.
|
||||
*/
|
||||
#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_tn5250_pipe_handler;
|
||||
|
||||
#endif
|
||||
|
395
src/protocols/tn5250/settings.c
Normal file
395
src/protocols/tn5250/settings.c
Normal file
@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <regex.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
/* Client plugin arguments */
|
||||
const char* GUAC_TN5250_CLIENT_ARGS[] = {
|
||||
"hostname",
|
||||
"port",
|
||||
"ssl",
|
||||
"enhanced",
|
||||
"font-name",
|
||||
"font-size",
|
||||
"color-scheme",
|
||||
"typescript-path",
|
||||
"typescript-name",
|
||||
"create-typescript-path",
|
||||
"recording-path",
|
||||
"recording-name",
|
||||
"recording-exclude-output",
|
||||
"recording-exclude-mouse",
|
||||
"recording-include-keys",
|
||||
"create-recording-path",
|
||||
"read-only",
|
||||
"backspace",
|
||||
"terminal-type",
|
||||
"scrollback",
|
||||
"disable-copy",
|
||||
"disable-paste",
|
||||
NULL
|
||||
};
|
||||
|
||||
enum TN5250_ARGS_IDX {
|
||||
|
||||
/**
|
||||
* The hostname to connect to. Required.
|
||||
*/
|
||||
IDX_HOSTNAME,
|
||||
|
||||
/**
|
||||
* The port to connect to. Optional.
|
||||
*/
|
||||
IDX_PORT,
|
||||
|
||||
/**
|
||||
* Whether or not to use SSL. Optional.
|
||||
*/
|
||||
IDX_SSL,
|
||||
|
||||
/**
|
||||
* Whether or not to use RFC2877 enhanced TN5250. Optional.
|
||||
*/
|
||||
IDX_ENHANCED,
|
||||
|
||||
/**
|
||||
* The name of the font to use within the terminal.
|
||||
*/
|
||||
IDX_FONT_NAME,
|
||||
|
||||
/**
|
||||
* The size of the font to use within the terminal, in points.
|
||||
*/
|
||||
IDX_FONT_SIZE,
|
||||
|
||||
/**
|
||||
* The color scheme to use, as a series of semicolon-separated color-value
|
||||
* pairs: "background: <color>", "foreground: <color>", or
|
||||
* "color<n>: <color>", where <n> is a number from 0 to 255, and <color> is
|
||||
* "color<n>" or an X11 color code (e.g. "aqua" or "rgb:12/34/56").
|
||||
* The color scheme can also be one of the special values: "black-white",
|
||||
* "white-black", "gray-black", or "green-black".
|
||||
*/
|
||||
IDX_COLOR_SCHEME,
|
||||
|
||||
/**
|
||||
* The full absolute path to the directory in which typescripts should be
|
||||
* written.
|
||||
*/
|
||||
IDX_TYPESCRIPT_PATH,
|
||||
|
||||
/**
|
||||
* The name that should be given to typescripts which are written in the
|
||||
* given path. Each typescript will consist of two files: "NAME" and
|
||||
* "NAME.timing".
|
||||
*/
|
||||
IDX_TYPESCRIPT_NAME,
|
||||
|
||||
/**
|
||||
* Whether the specified typescript path should automatically be created
|
||||
* if it does not yet exist.
|
||||
*/
|
||||
IDX_CREATE_TYPESCRIPT_PATH,
|
||||
|
||||
/**
|
||||
* The full absolute path to the directory in which screen recordings
|
||||
* should be written.
|
||||
*/
|
||||
IDX_RECORDING_PATH,
|
||||
|
||||
/**
|
||||
* The name that should be given to screen recordings which are written in
|
||||
* the given path.
|
||||
*/
|
||||
IDX_RECORDING_NAME,
|
||||
|
||||
/**
|
||||
* Whether output which is broadcast to each connected client (graphics,
|
||||
* streams, etc.) should NOT be included in the session recording. Output
|
||||
* is included by default, as it is necessary for any recording which must
|
||||
* later be viewable as video.
|
||||
*/
|
||||
IDX_RECORDING_EXCLUDE_OUTPUT,
|
||||
|
||||
/**
|
||||
* Whether changes to mouse state, such as position and buttons pressed or
|
||||
* released, should NOT be included in the session recording. Mouse state
|
||||
* is included by default, as it is necessary for the mouse cursor to be
|
||||
* rendered in any resulting video.
|
||||
*/
|
||||
IDX_RECORDING_EXCLUDE_MOUSE,
|
||||
|
||||
/**
|
||||
* Whether keys pressed and released should be included in the session
|
||||
* recording. Key events are NOT included by default within the recording,
|
||||
* as doing so has privacy and security implications. Including key events
|
||||
* may be necessary in certain auditing contexts, but should only be done
|
||||
* with caution. Key events can easily contain sensitive information, such
|
||||
* as passwords, credit card numbers, etc.
|
||||
*/
|
||||
IDX_RECORDING_INCLUDE_KEYS,
|
||||
|
||||
/**
|
||||
* Whether the specified screen recording path should automatically be
|
||||
* created if it does not yet exist.
|
||||
*/
|
||||
IDX_CREATE_RECORDING_PATH,
|
||||
|
||||
/**
|
||||
* "true" if this connection should be read-only (user input should be
|
||||
* dropped), "false" or blank otherwise.
|
||||
*/
|
||||
IDX_READ_ONLY,
|
||||
|
||||
/**
|
||||
* ASCII code, as an integer to use for the backspace key, or 127
|
||||
* if not specified.
|
||||
*/
|
||||
IDX_BACKSPACE,
|
||||
|
||||
/**
|
||||
* The terminal emulator type that is passed to the remote system (e.g.
|
||||
* "xterm" or "xterm-256color"). "linux" is used if unspecified.
|
||||
*/
|
||||
IDX_TERMINAL_TYPE,
|
||||
|
||||
/**
|
||||
* The maximum size of the scrollback buffer in rows.
|
||||
*/
|
||||
IDX_SCROLLBACK,
|
||||
|
||||
/**
|
||||
* Whether outbound clipboard access should be blocked. If set to "true",
|
||||
* it will not be possible to copy data from the terminal to the client
|
||||
* using the clipboard. By default, clipboard access is not blocked.
|
||||
*/
|
||||
IDX_DISABLE_COPY,
|
||||
|
||||
/**
|
||||
* Whether inbound clipboard access should be blocked. If set to "true", it
|
||||
* will not be possible to paste data from the client to the terminal using
|
||||
* the clipboard. By default, clipboard access is not blocked.
|
||||
*/
|
||||
IDX_DISABLE_PASTE,
|
||||
|
||||
TN5250_ARGS_COUNT
|
||||
};
|
||||
|
||||
guac_tn5250_settings* guac_tn5250_parse_args(guac_user* user,
|
||||
int argc, const char** argv) {
|
||||
|
||||
/* Validate arg count */
|
||||
if (argc != TN5250_ARGS_COUNT) {
|
||||
guac_user_log(user, GUAC_LOG_WARNING, "Incorrect number of connection "
|
||||
"parameters provided: expected %i, got %i.",
|
||||
TN5250_ARGS_COUNT, argc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
guac_tn5250_settings* settings = calloc(1, sizeof(guac_tn5250_settings));
|
||||
|
||||
/* Read hostname */
|
||||
settings->hostname =
|
||||
guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_HOSTNAME, "");
|
||||
|
||||
/* Read-only mode */
|
||||
settings->read_only =
|
||||
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_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_SCROLLBACK, GUAC_TN5250_DEFAULT_MAX_SCROLLBACK);
|
||||
|
||||
/* Read font name */
|
||||
settings->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_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_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_COLOR_SCHEME, "");
|
||||
|
||||
/* Pull width/height/resolution directly from user */
|
||||
settings->width = user->info.optimal_width;
|
||||
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_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_PORT, defualt_port);
|
||||
|
||||
/* Enhanced mode */
|
||||
settings->enhanced =
|
||||
guac_user_parse_args_boolean(user, GUAC_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_ENHANCED, false);
|
||||
|
||||
/* Read typescript path */
|
||||
settings->typescript_path =
|
||||
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_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_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_CREATE_TYPESCRIPT_PATH, false);
|
||||
|
||||
/* Read recording path */
|
||||
settings->recording_path =
|
||||
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_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_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_RECORDING_EXCLUDE_OUTPUT, false);
|
||||
|
||||
/* Parse mouse exclusion flag */
|
||||
settings->recording_exclude_mouse =
|
||||
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_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_RECORDING_INCLUDE_KEYS, false);
|
||||
|
||||
/* Parse path creation flag */
|
||||
settings->create_recording_path =
|
||||
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_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_BACKSPACE, 127);
|
||||
|
||||
/* Read terminal emulator type. */
|
||||
char* terminal_type = guac_user_parse_args_string(user,
|
||||
GUAC_TN5250_CLIENT_ARGS, argv, IDX_TERMINAL_TYPE, "5251-11");
|
||||
|
||||
if (strcmp(terminal_type, "3179-2") == 0)
|
||||
settings->terminal_type = IBM_3179_2;
|
||||
else if (strcmp(terminal_type, "3180-2") == 0)
|
||||
settings->terminal_type = IBM_3180_2;
|
||||
else if (strcmp(terminal_type, "3196-a1") == 0)
|
||||
settings->terminal_type = IBM_3196_A1;
|
||||
else if (strcmp(terminal_type, "3477-fc") == 0)
|
||||
settings->terminal_type = IBM_3477_FC;
|
||||
else if (strcmp(terminal_type, "3477-fg") == 0)
|
||||
settings->terminal_type = IBM_3477_FG;
|
||||
else if (strcmp(terminal_type, "5251-11") == 0)
|
||||
settings->terminal_type = IBM_5251_11;
|
||||
else if (strcmp(terminal_type, "5291-1") == 0)
|
||||
settings->terminal_type = IBM_5291_1;
|
||||
else if (strcmp(terminal_type, "5292-2") == 0)
|
||||
settings->terminal_type = IBM_5292_2;
|
||||
else if (strcmp(terminal_type, "5555-b01") == 0)
|
||||
settings->terminal_type = IBM_5555_B01;
|
||||
else if (strcmp(terminal_type, "5555-c01") == 0)
|
||||
settings->terminal_type = IBM_5555_C01;
|
||||
else {
|
||||
guac_user_log(user, GUAC_LOG_WARNING,
|
||||
"Invalid terminal type %s, defaulting to 5251-11",
|
||||
terminal_type);
|
||||
settings->terminal_type = IBM_5251_11;
|
||||
}
|
||||
free(terminal_type);
|
||||
|
||||
|
||||
/* Parse clipboard copy disable flag */
|
||||
settings->disable_copy =
|
||||
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_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_DISABLE_PASTE, false);
|
||||
|
||||
/* Parsing was successful */
|
||||
return settings;
|
||||
|
||||
}
|
||||
|
||||
void guac_tn5250_settings_free(guac_tn5250_settings* settings) {
|
||||
|
||||
/* Free network connection information */
|
||||
free(settings->hostname);
|
||||
free(settings->port);
|
||||
|
||||
/* Free display preferences */
|
||||
free(settings->font_name);
|
||||
free(settings->color_scheme);
|
||||
|
||||
/* Free typescript settings */
|
||||
free(settings->typescript_name);
|
||||
free(settings->typescript_path);
|
||||
|
||||
/* Free screen recording settings */
|
||||
free(settings->recording_name);
|
||||
free(settings->recording_path);
|
||||
|
||||
/* Free terminal emulator type. */
|
||||
free(settings->terminal_type);
|
||||
|
||||
/* Free overall structure */
|
||||
free(settings);
|
||||
|
||||
}
|
||||
|
376
src/protocols/tn5250/settings.h
Normal file
376
src/protocols/tn5250/settings.h
Normal file
@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_TN5250_SETTINGS_H
|
||||
#define GUAC_TN5250_SETTINGS_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <regex.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* The name of the font to use for the terminal if no name is specified.
|
||||
*/
|
||||
#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_TN5250_DEFAULT_FONT_SIZE 12
|
||||
|
||||
/**
|
||||
* The port to connect to when initiating a 5250 telnet connection, if no other
|
||||
* port is specified.
|
||||
*/
|
||||
#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_TN5250_DEFAULT_TYPESCRIPT_NAME "typescript"
|
||||
|
||||
/**
|
||||
* The filename to use for the screen recording, if not specified.
|
||||
*/
|
||||
#define GUAC_TN5250_DEFAULT_RECORDING_NAME "recording"
|
||||
|
||||
/**
|
||||
* The default maximum scrollback size in rows.
|
||||
*/
|
||||
#define GUAC_TN5250_DEFAULT_MAX_SCROLLBACK 1000
|
||||
|
||||
/**
|
||||
* The available terminal types for TN5250 connections. These are defined
|
||||
* in RFC-1205, Section 2.
|
||||
*/
|
||||
typedef enum guac_tn5250_terminal_types {
|
||||
|
||||
/**
|
||||
* IBM-3179-2, 24 x 80 color display
|
||||
*/
|
||||
IBM_3179_2,
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Data structure to store all of the characteristics of various types of
|
||||
* 5250-compatible terminals.
|
||||
*/
|
||||
typedef struct __guac_tn5250_terminal_params {
|
||||
|
||||
/**
|
||||
* The type of terminal, as defined in RFC-1205
|
||||
*/
|
||||
char* 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;
|
||||
|
||||
/**
|
||||
* An array of all of the possible terminal types, including the ENUM value,
|
||||
* the height (in rows) and width (in columns), and whether or not the terminal
|
||||
* supports color (true if color, false if monochrome).
|
||||
*/
|
||||
__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 TN5250 server to connect to.
|
||||
*/
|
||||
char* port;
|
||||
|
||||
/**
|
||||
* Whether or not to use SSL.
|
||||
*/
|
||||
bool ssl;
|
||||
|
||||
/**
|
||||
* Whether or not to use enhanced TN5250 mode (RFC2877)
|
||||
*/
|
||||
bool enhanced;
|
||||
|
||||
/**
|
||||
* Whether this connection is read-only, and user input should be dropped.
|
||||
*/
|
||||
bool read_only;
|
||||
|
||||
/**
|
||||
* The maximum size of the scrollback buffer in rows.
|
||||
*/
|
||||
int max_scrollback;
|
||||
|
||||
/**
|
||||
* The name of the font to use for display rendering.
|
||||
*/
|
||||
char* font_name;
|
||||
|
||||
/**
|
||||
* The size of the font to use, in points.
|
||||
*/
|
||||
int font_size;
|
||||
|
||||
/**
|
||||
* The name of the color scheme to use.
|
||||
*/
|
||||
char* color_scheme;
|
||||
|
||||
/**
|
||||
* The desired width of the terminal display, in pixels.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The desired height of the terminal display, in pixels.
|
||||
*/
|
||||
int height;
|
||||
|
||||
/**
|
||||
* The desired screen resolution, in DPI.
|
||||
*/
|
||||
int resolution;
|
||||
|
||||
/**
|
||||
* Whether outbound clipboard access should be blocked. If set, it will not
|
||||
* be possible to copy data from the terminal to the client using the
|
||||
* clipboard.
|
||||
*/
|
||||
bool disable_copy;
|
||||
|
||||
/**
|
||||
* Whether inbound clipboard access should be blocked. If set, it will not
|
||||
* be possible to paste data from the client to the terminal using the
|
||||
* clipboard.
|
||||
*/
|
||||
bool disable_paste;
|
||||
|
||||
/**
|
||||
* The path in which the typescript should be saved, if enabled. If no
|
||||
* typescript should be saved, this will be NULL.
|
||||
*/
|
||||
char* typescript_path;
|
||||
|
||||
/**
|
||||
* The filename to use for the typescript, if enabled.
|
||||
*/
|
||||
char* typescript_name;
|
||||
|
||||
/**
|
||||
* Whether the typescript path should be automatically created if it does
|
||||
* not already exist.
|
||||
*/
|
||||
bool create_typescript_path;
|
||||
|
||||
/**
|
||||
* The path in which the screen recording should be saved, if enabled. If
|
||||
* no screen recording should be saved, this will be NULL.
|
||||
*/
|
||||
char* recording_path;
|
||||
|
||||
/**
|
||||
* The filename to use for the screen recording, if enabled.
|
||||
*/
|
||||
char* recording_name;
|
||||
|
||||
/**
|
||||
* Whether the screen recording path should be automatically created if it
|
||||
* does not already exist.
|
||||
*/
|
||||
bool create_recording_path;
|
||||
|
||||
/**
|
||||
* Whether output which is broadcast to each connected client (graphics,
|
||||
* streams, etc.) should NOT be included in the session recording. Output
|
||||
* is included by default, as it is necessary for any recording which must
|
||||
* later be viewable as video.
|
||||
*/
|
||||
bool recording_exclude_output;
|
||||
|
||||
/**
|
||||
* Whether changes to mouse state, such as position and buttons pressed or
|
||||
* released, should NOT be included in the session recording. Mouse state
|
||||
* is included by default, as it is necessary for the mouse cursor to be
|
||||
* rendered in any resulting video.
|
||||
*/
|
||||
bool recording_exclude_mouse;
|
||||
|
||||
/**
|
||||
* Whether keys pressed and released should be included in the session
|
||||
* recording. Key events are NOT included by default within the recording,
|
||||
* as doing so has privacy and security implications. Including key events
|
||||
* may be necessary in certain auditing contexts, but should only be done
|
||||
* with caution. Key events can easily contain sensitive information, such
|
||||
* as passwords, credit card numbers, etc.
|
||||
*/
|
||||
bool recording_include_keys;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
int backspace;
|
||||
|
||||
/**
|
||||
* The terminal emulator type that is passed to the remote system.
|
||||
*/
|
||||
guac_tn5250_terminal_type terminal_type;
|
||||
|
||||
} guac_tn5250_settings;
|
||||
|
||||
/**
|
||||
* Parses all given args, storing them in a newly-allocated settings object. If
|
||||
* the args fail to parse, NULL is returned.
|
||||
*
|
||||
* @param user
|
||||
* The user who submitted the given arguments while joining the
|
||||
* connection.
|
||||
*
|
||||
* @param argc
|
||||
* The number of arguments within the argv array.
|
||||
*
|
||||
* @param argv
|
||||
* The values of all arguments provided by the user.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated settings object which must be freed with
|
||||
* guac_tn5250_settings_free() when no longer needed. If the arguments fail
|
||||
* to parse, NULL is returned.
|
||||
*/
|
||||
guac_tn5250_settings* guac_tn5250_parse_args(guac_user* user,
|
||||
int argc, const char** argv);
|
||||
|
||||
/**
|
||||
* Frees the regex pointed to by the given pointer, assigning the value NULL to
|
||||
* that pointer once the regex is freed. If the pointer already contains NULL,
|
||||
* this function has no effect.
|
||||
*
|
||||
* @param regex
|
||||
* The address of the pointer to the regex that should be freed.
|
||||
*/
|
||||
void guac_tn5250_regex_free(regex_t** regex);
|
||||
|
||||
/**
|
||||
* 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_tn5250_settings_free(guac_tn5250_settings* settings);
|
||||
|
||||
/**
|
||||
* NULL-terminated array of accepted client args.
|
||||
*/
|
||||
extern const char* GUAC_TN5250_CLIENT_ARGS[];
|
||||
|
||||
#endif
|
||||
|
178
src/protocols/tn5250/sna.h
Normal file
178
src/protocols/tn5250/sna.h
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: sna.h
|
||||
* Author: nick_couchman
|
||||
*
|
||||
* Created on August 4, 2019, 1:43 PM
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SNA_H
|
||||
#define GUAC_SNA_H
|
||||
|
||||
/**
|
||||
* This is the packet header that defines traffic on the TN5250 link as
|
||||
* SNA traffic. It will be present on traffic coming from the mainframe,
|
||||
* and should also be sent for any SNA-specific traffic to the mainframe.
|
||||
*/
|
||||
#define SNA_PACKET_HEADER 0x12a0
|
||||
|
||||
/**
|
||||
* This is a constant header on all SNA packets.
|
||||
*/
|
||||
#define SNA_VAR_HEADER 0x04
|
||||
|
||||
/**
|
||||
* Operational codes as defined in RFC1207.
|
||||
*
|
||||
* No operation.
|
||||
*/
|
||||
#define OPCODE_NOOP 0x00
|
||||
|
||||
/**
|
||||
* Invite operation, sent by server to allow client to talk.
|
||||
*/
|
||||
#define OPCODE_INVITE 0x01
|
||||
|
||||
/**
|
||||
* Output only
|
||||
*/
|
||||
#define OPCODE_OUTPUT 0x02
|
||||
|
||||
/**
|
||||
* Put/get operation
|
||||
*/
|
||||
#define OPCODE_PUT_GET 0x03
|
||||
|
||||
/**
|
||||
* Save screen
|
||||
*/
|
||||
#define OPCODE_SAVE_SCREEN 0x04
|
||||
|
||||
/**
|
||||
* Restore screen
|
||||
*/
|
||||
#define OPCODE_RESTORE_SCREEN 0x05
|
||||
|
||||
/**
|
||||
* Read immediate
|
||||
*/
|
||||
#define OPCODE_READ_IMMEIDATE 0x06
|
||||
|
||||
/**
|
||||
* Read screen
|
||||
*/
|
||||
#define OPCODE_READ_SCREEN 0x08
|
||||
|
||||
/**
|
||||
* Cancel invite
|
||||
*/
|
||||
#define OPCODE_CANCEL_INVITE 0x0a
|
||||
|
||||
/**
|
||||
* Message light on
|
||||
*/
|
||||
#define OPCODE_MSG_ON 0x0b
|
||||
|
||||
/**
|
||||
* Message light off
|
||||
*/
|
||||
#define OPCODE_MSG_OFF 0x0c
|
||||
|
||||
/**
|
||||
* A 16-bit set of flags, as defined in RFC1205, Section 3, for TN5250-specific
|
||||
* data transfer.
|
||||
*/
|
||||
struct sna_flags {
|
||||
|
||||
/**
|
||||
* Indicates data stream output error.
|
||||
*/
|
||||
unsigned int ERR : 1;
|
||||
|
||||
/**
|
||||
* 5250 Attention Key has been pressed.
|
||||
*/
|
||||
unsigned int ATN : 1;
|
||||
|
||||
/**
|
||||
* Reserved/unused.
|
||||
*/
|
||||
unsigned int : 3;
|
||||
|
||||
/**
|
||||
* System Request key was pressed.
|
||||
*/
|
||||
unsigned int SRQ : 1;
|
||||
|
||||
/**
|
||||
* Test Request key was pressed.
|
||||
*/
|
||||
unsigned int TRQ : 1;
|
||||
|
||||
/**
|
||||
* Help in Error State function - error code will follow header in data.
|
||||
*/
|
||||
unsigned int HLP : 1;
|
||||
|
||||
/**
|
||||
* Final 8 bits are reserved/unused.
|
||||
*/
|
||||
unsigned int : 8;
|
||||
|
||||
} sna_flags;
|
||||
|
||||
/**
|
||||
* Defines the structure of a TN5250 (SNA over Telnet) packet, including
|
||||
* the fields and the length of each field, as described in RFC1205.
|
||||
*/
|
||||
struct sna_packet {
|
||||
|
||||
/**
|
||||
* The length of the packet.
|
||||
*/
|
||||
unsigned int len : 16;
|
||||
|
||||
/**
|
||||
* The SNA header marker, 0x12a0
|
||||
*/
|
||||
unsigned int sna_header : 16;
|
||||
|
||||
/**
|
||||
* Reserved portion, should be zeroes.
|
||||
*/
|
||||
unsigned int reserved : 16;
|
||||
|
||||
/**
|
||||
* The variable header length, always 0x04.
|
||||
*/
|
||||
unsigned int varlen : 8;
|
||||
|
||||
/**
|
||||
* SNA flags.
|
||||
*/
|
||||
unsigned int sna_flags : 16;
|
||||
|
||||
/**
|
||||
* The opcode.
|
||||
*/
|
||||
unsigned int opcode : 8;
|
||||
|
||||
/**
|
||||
* Any data sent in the packet.
|
||||
*/
|
||||
void* sna_data;
|
||||
|
||||
/**
|
||||
* IAC and EOR marker.
|
||||
*/
|
||||
unsigned int sna_end : 16;
|
||||
|
||||
} sna_packet;
|
||||
|
||||
#endif /* SNA_H */
|
||||
|
561
src/protocols/tn5250/tn5250.c
Normal file
561
src/protocols/tn5250/tn5250.c
Normal file
@ -0,0 +1,561 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "common/recording.h"
|
||||
#include "tn5250.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <libtelnet.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* Support levels for various telnet options, required for connection
|
||||
* negotiation by telnet_init(), part of libtelnet. The TN5250 specification
|
||||
* requires at EOR, BINARY, and TTYPE.
|
||||
*/
|
||||
static const telnet_telopt_t __telnet_options[] = {
|
||||
{ TELNET_TELOPT_ECHO, TELNET_WONT, TELNET_DO },
|
||||
{ TELNET_TELOPT_TTYPE, TELNET_WILL, TELNET_DO },
|
||||
{ TELNET_TELOPT_COMPRESS2, TELNET_WONT, TELNET_DO },
|
||||
{ TELNET_TELOPT_MSSP, TELNET_WONT, TELNET_DO },
|
||||
{ TELNET_TELOPT_NAWS, TELNET_WONT, TELNET_DONT },
|
||||
{ TELNET_TELOPT_NEW_ENVIRON, TELNET_WILL, TELNET_DONT },
|
||||
{ TELNET_TELOPT_EOR, TELNET_WILL, TELNET_DO },
|
||||
{ TELNET_TELOPT_BINARY, TELNET_WILL, TELNET_DO },
|
||||
{ -1, 0, 0 }
|
||||
};
|
||||
|
||||
/**
|
||||
* ***Should be abstracted to common telnet support.***
|
||||
* Write the entire buffer given to the specified file descriptor, retrying
|
||||
* the write automatically if necessary. This function will return a value
|
||||
* not equal to the buffer's size iff an error occurs which prevents all
|
||||
* future writes.
|
||||
*
|
||||
* @param fd The file descriptor to write to.
|
||||
* @param buffer The buffer to write.
|
||||
* @param size The number of bytes from the buffer to write.
|
||||
*/
|
||||
static int __guac_telnet_write_all(int fd, const char* buffer, int size) {
|
||||
|
||||
int remaining = size;
|
||||
while (remaining > 0) {
|
||||
|
||||
/* Attempt to write data */
|
||||
int ret_val = write(fd, buffer, remaining);
|
||||
if (ret_val <= 0)
|
||||
return -1;
|
||||
|
||||
/* If successful, continue with what data remains (if any) */
|
||||
remaining -= ret_val;
|
||||
buffer += ret_val;
|
||||
|
||||
}
|
||||
|
||||
return size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler, as defined by libtelnet. This function is passed to
|
||||
* telnet_init() and will be called for every event fired by libtelnet,
|
||||
* including feature enable/disable and receipt/transmission of data.
|
||||
*/
|
||||
static void __guac_tn5250_event_handler(telnet_t* telnet, telnet_event_t* event, void* data) {
|
||||
|
||||
guac_client* client = (guac_client*) data;
|
||||
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_tn5250_recv_sna_packet(client, event);
|
||||
// guac_terminal_write(tn5250_client->term, event->data.buffer, event->data.size);
|
||||
break;
|
||||
|
||||
/* Data destined for remote end */
|
||||
case TELNET_EV_SEND:
|
||||
if (__guac_tn5250_send_sna_packet(telnet, event))
|
||||
guac_client_stop(client);
|
||||
if (__guac_tn5250_write_all(tn5250_client->socket_fd, event->data.buffer, event->data.size)
|
||||
!= event->data.size)
|
||||
guac_client_stop(client);
|
||||
break;
|
||||
|
||||
/* Remote feature enabled */
|
||||
case TELNET_EV_WILL:
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received TELNET_EV_WILL "
|
||||
"for option %d", event->neg.telopt);
|
||||
if (event->neg.telopt == TELNET_TELOPT_ECHO)
|
||||
tn5250_client->echo_enabled = 0; /* Disable local echo, as remote will echo */
|
||||
break;
|
||||
|
||||
/* Remote feature disabled */
|
||||
case TELNET_EV_WONT:
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received TELNET_EV_WONT "
|
||||
"for option %d", event->neg.telopt);
|
||||
if (event->neg.telopt == TELNET_TELOPT_ECHO)
|
||||
tn5250_client->echo_enabled = 1; /* Enable local echo, as remote won't echo */
|
||||
break;
|
||||
|
||||
/* Local feature enable */
|
||||
case TELNET_EV_DO:
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received TELNET_EV_DO "
|
||||
"for option %d", event->neg.telopt);
|
||||
break;
|
||||
|
||||
/* Terminal type request */
|
||||
case TELNET_EV_TTYPE:
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received TELNET_EV_TTYPE "
|
||||
"for command %d", event->ttype.cmd);
|
||||
if (event->ttype.cmd == TELNET_TTYPE_SEND)
|
||||
tn5250_ttype_is(tn5250_client->telnet, __guac_tn5250_terminals[settings->terminal_type].terminal);
|
||||
break;
|
||||
|
||||
/* Environment request */
|
||||
case TELNET_EV_ENVIRON:
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received TELNET_EV_ENVIRON "
|
||||
"for size %d", event->environ.size);
|
||||
|
||||
/* Only send USER if entire environment was requested */
|
||||
if (event->environ.size == 0)
|
||||
guac_tn5250_send_user(telnet, settings->username);
|
||||
|
||||
break;
|
||||
|
||||
/* Connection warnings */
|
||||
case TELNET_EV_WARNING:
|
||||
guac_client_log(client, GUAC_LOG_WARNING, "%s", event->error.msg);
|
||||
break;
|
||||
|
||||
/* Connection errors */
|
||||
case TELNET_EV_ERROR:
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
||||
"Telnet connection closing with error: %s", event->error.msg);
|
||||
break;
|
||||
|
||||
/* Ignore other events */
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Input thread, started by the main telnet client thread. This thread
|
||||
* continuously reads from the terminal's STDIN and transfers all read
|
||||
* data to the telnet connection.
|
||||
*
|
||||
* @param data The current guac_client instance.
|
||||
* @return Always NULL.
|
||||
*/
|
||||
static void* __guac_tn5250_input_thread(void* data) {
|
||||
|
||||
guac_client* client = (guac_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(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;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ***Abstract to common telnet code.***
|
||||
* Connects to the telnet server specified within the data associated
|
||||
* with the given guac_client, which will have been populated by
|
||||
* guac_client_init.
|
||||
*
|
||||
* @return The connected telnet instance, if successful, or NULL if the
|
||||
* connection fails for any reason.
|
||||
*/
|
||||
static telnet_t* __guac_tn5250_create_session(guac_client* client) {
|
||||
|
||||
int retval;
|
||||
|
||||
int fd;
|
||||
struct addrinfo* addresses;
|
||||
struct addrinfo* current_address;
|
||||
|
||||
char connected_address[1024];
|
||||
char connected_port[64];
|
||||
|
||||
guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data;
|
||||
guac_tn5250_settings* settings = tn5250_client->settings;
|
||||
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP
|
||||
};
|
||||
|
||||
/* Get socket */
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
/* Get addresses connection */
|
||||
if ((retval = getaddrinfo(settings->hostname, settings->port,
|
||||
&hints, &addresses))) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error parsing given address or port: %s",
|
||||
gai_strerror(retval));
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/* Attempt connection to each address until success */
|
||||
current_address = addresses;
|
||||
while (current_address != NULL) {
|
||||
|
||||
int retval;
|
||||
|
||||
/* Resolve hostname */
|
||||
if ((retval = getnameinfo(current_address->ai_addr,
|
||||
current_address->ai_addrlen,
|
||||
connected_address, sizeof(connected_address),
|
||||
connected_port, sizeof(connected_port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV)))
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Unable to resolve host: %s", gai_strerror(retval));
|
||||
|
||||
/* Connect */
|
||||
if (connect(fd, current_address->ai_addr,
|
||||
current_address->ai_addrlen) == 0) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Successfully connected to "
|
||||
"host %s, port %s", connected_address, connected_port);
|
||||
|
||||
/* Done if successful connect */
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise log information regarding bind failure */
|
||||
else
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Unable to connect to "
|
||||
"host %s, port %s: %s",
|
||||
connected_address, connected_port, strerror(errno));
|
||||
|
||||
current_address = current_address->ai_next;
|
||||
|
||||
}
|
||||
|
||||
/* If unable to connect to anything, fail */
|
||||
if (current_address == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND,
|
||||
"Unable to connect to any addresses.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Free addrinfo */
|
||||
freeaddrinfo(addresses);
|
||||
|
||||
/* Open telnet session */
|
||||
telnet_t* telnet = telnet_init(__telnet_options, __guac_telnet_event_handler, 0, client);
|
||||
if (telnet == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Telnet client allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Save file descriptor */
|
||||
tn5250_client->socket_fd = fd;
|
||||
|
||||
return telnet;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a 16-bit value over the given telnet connection with the byte order
|
||||
* required by the telnet protocol.
|
||||
*
|
||||
* @param telnet The telnet connection to use.
|
||||
* @param value The value to send.
|
||||
*/
|
||||
static void __guac_tn5250_send_uint16(telnet_t* telnet, uint16_t value) {
|
||||
|
||||
unsigned char buffer[2];
|
||||
buffer[0] = (value >> 8) & 0xFF;
|
||||
buffer[1] = value & 0xFF;
|
||||
|
||||
telnet_send(telnet, (char*) buffer, 2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an 8-bit value over the given telnet connection.
|
||||
*
|
||||
* @param telnet The telnet connection to use.
|
||||
*
|
||||
* @param value The value to send.
|
||||
*/
|
||||
static void __guac_tn5250_send_uint8(telnet_t* telnet, uint8_t value) {
|
||||
telnet_send(telnet, (char*) (&value), 1);
|
||||
}
|
||||
|
||||
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_tn5250_send_uint8(telnet, TELNET_ENVIRON_IS);
|
||||
|
||||
/* Only send username if defined */
|
||||
if (username != NULL) {
|
||||
|
||||
/* VAR "USER" */
|
||||
__guac_tn5250_send_uint8(telnet, TELNET_ENVIRON_VAR);
|
||||
telnet_send(telnet, "USER", 4);
|
||||
|
||||
/* VALUE username */
|
||||
__guac_tn5250_send_uint8(telnet, TELNET_ENVIRON_VALUE);
|
||||
telnet_send(telnet, username, strlen(username));
|
||||
|
||||
}
|
||||
|
||||
/* IAC SE */
|
||||
telnet_finish_sb(telnet);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for data on the given file descriptor for up to one second. The
|
||||
* return value is identical to that of select(): 0 on timeout, < 0 on
|
||||
* error, and > 0 on success.
|
||||
*
|
||||
* @param socket_fd The file descriptor to wait for.
|
||||
*
|
||||
* @return A value greater than zero on success, zero on timeout, and
|
||||
* less than zero on error.
|
||||
*/
|
||||
static int __guac_tn5250_wait(int socket_fd) {
|
||||
|
||||
/* Build array of file descriptors */
|
||||
struct pollfd fds[] = {{
|
||||
.fd = socket_fd,
|
||||
.events = POLLIN,
|
||||
.revents = 0,
|
||||
}};
|
||||
|
||||
/* Wait for one second */
|
||||
return poll(fds, 1, 1000);
|
||||
|
||||
}
|
||||
|
||||
void* guac_tn5250_client_thread(void* data) {
|
||||
|
||||
guac_client* client = (guac_client*) data;
|
||||
guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data;
|
||||
guac_tn5250_settings* settings = tn5250_client->settings;
|
||||
|
||||
pthread_t input_thread;
|
||||
char buffer[8192];
|
||||
int wait_result;
|
||||
|
||||
/* Set up screen recording, if requested */
|
||||
if (settings->recording_path != NULL) {
|
||||
tn5250_client->recording = guac_common_recording_create(client,
|
||||
settings->recording_path,
|
||||
settings->recording_name,
|
||||
settings->create_recording_path,
|
||||
!settings->recording_exclude_output,
|
||||
!settings->recording_exclude_mouse,
|
||||
settings->recording_include_keys);
|
||||
}
|
||||
|
||||
/* Calculate required terminal size based on type. */
|
||||
|
||||
/* Create terminal */
|
||||
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 (tn5250_client->term == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Terminal initialization failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fix terminal width/height */
|
||||
tn5250_client->term.term_width = __guac_tn5250_terminals[settings->terminal_type].cols;
|
||||
tn5250_client->term.term_height = __guac_tn5250_terminals[settings->terminal_type].rows;
|
||||
|
||||
/* Set up typescript, if requested */
|
||||
if (settings->typescript_path != NULL) {
|
||||
guac_terminal_create_typescript(tn5250_client->term,
|
||||
settings->typescript_path,
|
||||
settings->typescript_name,
|
||||
settings->create_typescript_path);
|
||||
}
|
||||
|
||||
/* Open telnet 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, "TN5250 connection successful.");
|
||||
|
||||
/* Allow terminal to render */
|
||||
guac_terminal_start(tn5250_client->term);
|
||||
|
||||
/* Start input thread */
|
||||
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_tn5250_wait(tn5250_client->socket_fd)) >= 0) {
|
||||
|
||||
/* Resume waiting of no data available */
|
||||
if (wait_result == 0)
|
||||
continue;
|
||||
|
||||
int bytes_read = read(tn5250_client->socket_fd, buffer, sizeof(buffer));
|
||||
if (bytes_read <= 0)
|
||||
break;
|
||||
|
||||
telnet_recv(tn5250_client->telnet, buffer, bytes_read);
|
||||
|
||||
}
|
||||
|
||||
/* Kill client and Wait for input thread to die */
|
||||
guac_client_stop(client);
|
||||
pthread_join(input_thread, NULL);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_INFO, "TN5250 connection ended.");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void __guac_tn5250_send_sna_packet(void* data, tn5250_flags flags,
|
||||
unsigned char opcode, char* data) {
|
||||
|
||||
/**
|
||||
* Things to do, here:
|
||||
* - Put the TN5250 header on
|
||||
* - Set any flags
|
||||
* - Set the Opcode
|
||||
* - Write data
|
||||
* - Write EOR
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
void __guac_tn5250_recv_sna_packet(guac_client* client, telnet_event_t* event) {
|
||||
|
||||
/**
|
||||
* Things to do, here:
|
||||
* - Check for TN5250 header
|
||||
* - Take off flags and process
|
||||
* - Examine Opcode and handle (switch)
|
||||
* - Read data and handle it (while)
|
||||
* - Look for EOR (while)
|
||||
*/
|
||||
|
||||
/* Look for TN5250 header - abort if not found. */
|
||||
|
||||
/* Grab flags */
|
||||
|
||||
/* Process Opcode */
|
||||
switch (opcode) {
|
||||
|
||||
case OPCODE_NOOP:
|
||||
|
||||
break;
|
||||
|
||||
case OPCODE_INVITE:
|
||||
|
||||
break;
|
||||
|
||||
case OPCODE_OUTPUT:
|
||||
|
||||
break;
|
||||
|
||||
case OPCODE_PUT_GET:
|
||||
|
||||
break;
|
||||
|
||||
case OPCODE_SAVE_SCREEN:
|
||||
|
||||
break;
|
||||
|
||||
case OPCODE_RESTORE_SCREEN:
|
||||
|
||||
break;
|
||||
|
||||
case OPCODE_READ_IMMEDIATE:
|
||||
|
||||
break:
|
||||
|
||||
case OPCODE_READ_SCREEN:
|
||||
|
||||
break;
|
||||
|
||||
case OPCODE_CANCEL_INVITE:
|
||||
|
||||
break;
|
||||
|
||||
case OPCODE_MSG_ON:
|
||||
|
||||
break;
|
||||
|
||||
case OPCODE_MSG_OFF:
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
/* Process data until we get the EOR option */
|
||||
while (packet[i] != TELNET_TELOPT_EOR) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
161
src/protocols/tn5250/tn5250.h
Normal file
161
src/protocols/tn5250/tn5250.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_TN5250_H
|
||||
#define GUAC_TN5250_H
|
||||
|
||||
#include "config.h"
|
||||
#include "common/clipboard.h"
|
||||
#include "common/recording.h"
|
||||
#include "settings.h"
|
||||
#include "sna.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
#include <libtelnet.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Telnet-specific client data.
|
||||
*/
|
||||
typedef struct guac_tn5250_client {
|
||||
|
||||
/**
|
||||
* TN5250 connection settings.
|
||||
*/
|
||||
guac_tn5250_settings* settings;
|
||||
|
||||
/**
|
||||
* The tn5250 client thread.
|
||||
*/
|
||||
pthread_t client_thread;
|
||||
|
||||
/**
|
||||
* The file descriptor of the socket connected to the tn5250 server,
|
||||
* or -1 if no connection has been established.
|
||||
*/
|
||||
int socket_fd;
|
||||
|
||||
/**
|
||||
* telnet connection, used by the tn5250 client thread.
|
||||
*/
|
||||
telnet_t* telnet;
|
||||
|
||||
/**
|
||||
* Whether window size should be sent when the window is resized.
|
||||
*/
|
||||
int naws_enabled;
|
||||
|
||||
/**
|
||||
* Whether all user input should be automatically echoed to the
|
||||
* terminal.
|
||||
*/
|
||||
int echo_enabled;
|
||||
|
||||
/**
|
||||
* The current clipboard contents.
|
||||
*/
|
||||
guac_common_clipboard* clipboard;
|
||||
|
||||
/**
|
||||
* The terminal which will render all output from the tn5250 client.
|
||||
*/
|
||||
guac_terminal* term;
|
||||
|
||||
/**
|
||||
* The in-progress session recording, or NULL if no recording is in
|
||||
* progress.
|
||||
*/
|
||||
guac_common_recording* recording;
|
||||
|
||||
} guac_tn5250_client;
|
||||
|
||||
/**
|
||||
* Possible Opcodes that can be sent by the mainframe or the client.
|
||||
*/
|
||||
unsigned char tn5250_opcodes[] = {
|
||||
OPCODE_NOOP, /* No operation */
|
||||
OPCODE_INVITE, /* Invite */
|
||||
OPCODE_OUTPUT, /* Output only */
|
||||
OPCODE_PUT_GET, /* Put/Get */
|
||||
OPCODE_SAVE_SCREEN, /* Save screen */
|
||||
OPCODE_RESTORE_SCREEN, /* Restore screen */
|
||||
OPCODE_READ_IMMEDIATE, /* Read immediate */
|
||||
0x07, /* Reserved */
|
||||
OPCODE_READ_SCREEN, /* Read screen */
|
||||
0x09, /* Reserved */
|
||||
OPCODE_CANCEL_INVITE, /* Cancel invite */
|
||||
OPCODE_MSG_ON, /* Turn on message light */
|
||||
OPCODE_MSG_OFF, /* Turn off message light */
|
||||
NULL
|
||||
}
|
||||
|
||||
/**
|
||||
* Main tn5250 client thread, handling transfer of tn5250 output to STDOUT.
|
||||
*
|
||||
* @param data
|
||||
* The client data associated with this thread.
|
||||
*/
|
||||
void* guac_tn5250_client_thread(void* data);
|
||||
|
||||
/**
|
||||
* Sends the given username by setting the remote USER environment variable
|
||||
* using the tn5250 NEW-ENVIRON option.
|
||||
*
|
||||
* @param telnet
|
||||
* The telnet connection to send the USER variable to.
|
||||
*
|
||||
* @param username
|
||||
* The username to send.
|
||||
*/
|
||||
void guac_tn5250_send_user(telnet_t* telnet, const char* username);
|
||||
|
||||
/**
|
||||
* Sends the given data in TN5250 mode, creating the necessary packet
|
||||
* structure over the telnet connection to talk to the system.
|
||||
*
|
||||
* @param telnet
|
||||
* The telnet client sending the packet.
|
||||
*
|
||||
* @param sna_flags
|
||||
* Any flags that should be set in the packet.
|
||||
*
|
||||
* @param opcode
|
||||
* Any opcode that should be sent to the mainframe.
|
||||
*
|
||||
* @param data
|
||||
* Data that should be sent to the mainframe.
|
||||
*/
|
||||
void __guac_tn5250_send_sna_packet(telnet_t* telnet, sna_flags flags,
|
||||
unsigned char opcode, char* data);
|
||||
|
||||
/**
|
||||
* Handles a received SNA packet, processing flags and opcodes, and then writing
|
||||
* any output to the terminal.
|
||||
*
|
||||
* @param client
|
||||
* The Guacamole Client that is receiving the packet.
|
||||
*
|
||||
* @param event
|
||||
* The Telnet event that is being processed.
|
||||
*/
|
||||
void __guac_tn5250_recv_sna_packet(guac_client* client, telnet_event_t* event);
|
||||
|
||||
#endif
|
||||
|
121
src/protocols/tn5250/user.c
Normal file
121
src/protocols/tn5250/user.c
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "argv.h"
|
||||
#include "clipboard.h"
|
||||
#include "input.h"
|
||||
#include "pipe.h"
|
||||
#include "settings.h"
|
||||
#include "tn5250.h"
|
||||
#include "terminal/terminal.h"
|
||||
#include "user.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
int guac_tn5250_user_join_handler(guac_user* user, int argc, char** argv) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data;
|
||||
|
||||
/* Parse provided arguments */
|
||||
guac_tn5250_settings* settings = guac_tn5250_parse_args(user,
|
||||
argc, (const char**) argv);
|
||||
|
||||
/* Fail if settings cannot be parsed */
|
||||
if (settings == NULL) {
|
||||
guac_user_log(user, GUAC_LOG_INFO,
|
||||
"Badly formatted client arguments.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Store settings at user level */
|
||||
user->data = settings;
|
||||
|
||||
/* Connect via tn5250 if owner */
|
||||
if (user->owner) {
|
||||
|
||||
/* Store owner's settings at client level */
|
||||
tn5250_client->settings = settings;
|
||||
|
||||
/* Start client thread */
|
||||
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 tn5250 client thread");
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* If not owner, synchronize with current display */
|
||||
else {
|
||||
guac_terminal_dup(tn5250_client->term, user, user->socket);
|
||||
guac_socket_flush(user->socket);
|
||||
}
|
||||
|
||||
/* Only handle events if not read-only */
|
||||
if (!settings->read_only) {
|
||||
|
||||
/* General mouse/keyboard events */
|
||||
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_tn5250_clipboard_handler;
|
||||
|
||||
/* STDIN redirection */
|
||||
user->pipe_handler = guac_tn5250_pipe_handler;
|
||||
|
||||
/* Updates to connection parameters */
|
||||
user->argv_handler = guac_tn5250_argv_handler;
|
||||
|
||||
/* Display size change events */
|
||||
user->size_handler = guac_tn5250_user_size_handler;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_tn5250_user_leave_handler(guac_user* user) {
|
||||
|
||||
guac_tn5250_client* tn5250_client =
|
||||
(guac_tn5250_client*) user->client->data;
|
||||
|
||||
/* Update shared cursor state */
|
||||
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_tn5250_settings* settings = (guac_tn5250_settings*) user->data;
|
||||
guac_tn5250_settings_free(settings);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
38
src/protocols/tn5250/user.h
Normal file
38
src/protocols/tn5250/user.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_TN5250_USER_H
|
||||
#define GUAC_TN5250_USER_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Handler for joining users.
|
||||
*/
|
||||
guac_user_join_handler guac_tn5250_user_join_handler;
|
||||
|
||||
/**
|
||||
* Handler for leaving users.
|
||||
*/
|
||||
guac_user_leave_handler guac_tn5250_user_leave_handler;
|
||||
|
||||
#endif
|
||||
|
@ -824,6 +824,18 @@ int guac_terminal_write(guac_terminal* term, const char* c, int size);
|
||||
|
||||
/**
|
||||
* Sets the character at the given row and column to the specified value.
|
||||
*
|
||||
* @param term
|
||||
* The guac_terminal to manipulate.
|
||||
*
|
||||
* @param row
|
||||
* The row on which the character is located.
|
||||
*
|
||||
* @param col
|
||||
* THe column in which the character is located.
|
||||
*
|
||||
* @param codepoint
|
||||
* The value to set.
|
||||
*/
|
||||
int guac_terminal_set(guac_terminal* term, int row, int col, int codepoint);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user