Compare commits
51 Commits
working/tn
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
47b9360d46 | ||
|
98c2a6adcb | ||
|
3b0a9bac75 | ||
|
f6893ed319 | ||
|
a5214c971a | ||
|
ccfcef8c0f | ||
|
1a7a57ed19 | ||
|
eac064bde9 | ||
|
4afc1d85ce | ||
|
818b5f79df | ||
|
8ef60bfa9d | ||
|
d90e0e97fe | ||
|
ec7964e8fb | ||
|
add7ce361b | ||
|
7d16f67d6d | ||
|
e3adb97085 | ||
|
55941823ec | ||
|
07acce8a76 | ||
|
5b1677f21a | ||
|
623c398005 | ||
|
aa92239edd | ||
|
897712c743 | ||
|
02b24d0101 | ||
|
26eadc37a3 | ||
|
6d7156bc70 | ||
|
6312e1720d | ||
|
cb7ae25177 | ||
|
a4adb3f5c0 | ||
|
5cf408ebbb | ||
|
3ca6bb0a61 | ||
|
457a169c49 | ||
|
bad381cebe | ||
|
6171da6d0b | ||
|
067f2a91a0 | ||
|
bc52485570 | ||
|
b20afa275a | ||
|
b096e47f57 | ||
|
4d211e0c9e | ||
|
dffbeac57a | ||
|
0361adc01f | ||
|
1971a9dad2 | ||
|
5dbf4820ab | ||
|
b2eb13a178 | ||
|
2bc9d5ff01 | ||
|
5918cc9f7c | ||
|
15f6e9f678 | ||
|
b5addfe3da | ||
|
7f4246b6d5 | ||
|
6ab82446bb | ||
|
9c93337d97 | ||
|
cdee93ae25 |
207
Dockerfile
207
Dockerfile
@ -21,25 +21,32 @@
|
||||
# Dockerfile for guacamole-server
|
||||
#
|
||||
|
||||
# The Ubuntu image that should be used as the basis for the guacd image
|
||||
ARG UBUNTU_BASE_IMAGE=21.10
|
||||
# The Alpine Linux image that should be used as the basis for the guacd image
|
||||
ARG ALPINE_BASE_IMAGE=latest
|
||||
FROM alpine:${ALPINE_BASE_IMAGE} AS builder
|
||||
|
||||
# Use Debian as base for the build
|
||||
FROM ubuntu:${UBUNTU_BASE_IMAGE} AS builder
|
||||
# Install build dependencies
|
||||
RUN apk add --no-cache \
|
||||
autoconf \
|
||||
automake \
|
||||
build-base \
|
||||
cairo-dev \
|
||||
cmake \
|
||||
git \
|
||||
grep \
|
||||
libjpeg-turbo-dev \
|
||||
libpng-dev \
|
||||
libtool \
|
||||
libwebp-dev \
|
||||
make \
|
||||
openssl-dev \
|
||||
pango-dev \
|
||||
pulseaudio-dev \
|
||||
util-linux-dev
|
||||
|
||||
#
|
||||
# The Debian repository that should be preferred for dependencies (this will be
|
||||
# added to /etc/apt/sources.list if not already present)
|
||||
#
|
||||
# NOTE: Due to limitations of the Docker image build process, this value is
|
||||
# duplicated in an ARG in the second stage of the build.
|
||||
#
|
||||
ARG UBUNTU_RELEASE=impish-backports
|
||||
|
||||
# Add repository for specified Ubuntu release if not already present in
|
||||
# sources.list
|
||||
RUN grep " ${UBUNTU_RELEASE} " /etc/apt/sources.list || echo >> /etc/apt/sources.list \
|
||||
"deb http://archive.ubuntu.com/ubuntu/ ${UBUNTU_RELEASE} main contrib non-free"
|
||||
# Copy source to container for sake of build
|
||||
ARG BUILD_DIR=/tmp/guacamole-server
|
||||
COPY . ${BUILD_DIR}
|
||||
|
||||
#
|
||||
# Base directory for installed build artifacts.
|
||||
@ -47,70 +54,99 @@ RUN grep " ${UBUNTU_RELEASE} " /etc/apt/sources.list || echo >> /etc/apt/sources
|
||||
# NOTE: Due to limitations of the Docker image build process, this value is
|
||||
# duplicated in an ARG in the second stage of the build.
|
||||
#
|
||||
ARG PREFIX_DIR=/usr/local/guacamole
|
||||
ARG PREFIX_DIR=/opt/guacamole
|
||||
|
||||
# Build arguments
|
||||
ARG BUILD_DIR=/tmp/guacd-docker-BUILD
|
||||
ARG BUILD_DEPENDENCIES=" \
|
||||
autoconf \
|
||||
automake \
|
||||
freerdp2-dev \
|
||||
gcc \
|
||||
libcairo2-dev \
|
||||
libgcrypt-dev \
|
||||
libjpeg-turbo8-dev \
|
||||
libossp-uuid-dev \
|
||||
libpango1.0-dev \
|
||||
libpulse-dev \
|
||||
libssh2-1-dev \
|
||||
libssl-dev \
|
||||
libtelnet-dev \
|
||||
libtool \
|
||||
libvncserver-dev \
|
||||
libwebsockets-dev \
|
||||
libwebp-dev \
|
||||
make"
|
||||
#
|
||||
# Automatically select the latest versions of each core protocol support
|
||||
# library (these can be overridden at build time if a specific version is
|
||||
# needed)
|
||||
#
|
||||
ARG WITH_FREERDP='2(\.\d+)+'
|
||||
ARG WITH_LIBSSH2='libssh2-\d+(\.\d+)+'
|
||||
ARG WITH_LIBTELNET='\d+(\.\d+)+'
|
||||
ARG WITH_LIBVNCCLIENT='LibVNCServer-\d+(\.\d+)+'
|
||||
ARG WITH_LIBWEBSOCKETS='v\d+(\.\d+)+'
|
||||
|
||||
# Do not require interaction during build
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
#
|
||||
# Default build options for each core protocol support library, as well as
|
||||
# guacamole-server itself (these can be overridden at build time if different
|
||||
# options are needed)
|
||||
#
|
||||
|
||||
# Bring build environment up to date and install build dependencies
|
||||
RUN apt-get update && \
|
||||
apt-get install -t ${UBUNTU_RELEASE} -y $BUILD_DEPENDENCIES && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
ARG FREERDP_OPTS="\
|
||||
-DBUILTIN_CHANNELS=OFF \
|
||||
-DCHANNEL_URBDRC=OFF \
|
||||
-DWITH_ALSA=OFF \
|
||||
-DWITH_CAIRO=ON \
|
||||
-DWITH_CHANNELS=ON \
|
||||
-DWITH_CLIENT=ON \
|
||||
-DWITH_CUPS=OFF \
|
||||
-DWITH_DIRECTFB=OFF \
|
||||
-DWITH_FFMPEG=OFF \
|
||||
-DWITH_GSM=OFF \
|
||||
-DWITH_GSSAPI=OFF \
|
||||
-DWITH_IPP=OFF \
|
||||
-DWITH_JPEG=ON \
|
||||
-DWITH_LIBSYSTEMD=OFF \
|
||||
-DWITH_MANPAGES=OFF \
|
||||
-DWITH_OPENH264=OFF \
|
||||
-DWITH_OPENSSL=ON \
|
||||
-DWITH_OSS=OFF \
|
||||
-DWITH_PCSC=OFF \
|
||||
-DWITH_PULSE=OFF \
|
||||
-DWITH_SERVER=OFF \
|
||||
-DWITH_SERVER_INTERFACE=OFF \
|
||||
-DWITH_SHADOW_MAC=OFF \
|
||||
-DWITH_SHADOW_X11=OFF \
|
||||
-DWITH_SSE2=ON \
|
||||
-DWITH_WAYLAND=OFF \
|
||||
-DWITH_X11=OFF \
|
||||
-DWITH_X264=OFF \
|
||||
-DWITH_XCURSOR=ON \
|
||||
-DWITH_XEXT=ON \
|
||||
-DWITH_XI=OFF \
|
||||
-DWITH_XINERAMA=OFF \
|
||||
-DWITH_XKBFILE=ON \
|
||||
-DWITH_XRENDER=OFF \
|
||||
-DWITH_XTEST=OFF \
|
||||
-DWITH_XV=OFF \
|
||||
-DWITH_ZLIB=ON"
|
||||
|
||||
# Add configuration scripts
|
||||
COPY src/guacd-docker/bin "${PREFIX_DIR}/bin/"
|
||||
ARG GUACAMOLE_SERVER_OPTS="\
|
||||
--disable-guaclog"
|
||||
|
||||
# Copy source to container for sake of build
|
||||
COPY . "$BUILD_DIR"
|
||||
ARG LIBSSH2_OPTS="\
|
||||
-DBUILD_EXAMPLES=OFF \
|
||||
-DBUILD_SHARED_LIBS=ON"
|
||||
|
||||
# Build guacamole-server from local source
|
||||
RUN ${PREFIX_DIR}/bin/build-guacd.sh "$BUILD_DIR" "$PREFIX_DIR"
|
||||
ARG LIBTELNET_OPTS="\
|
||||
--disable-static \
|
||||
--disable-util"
|
||||
|
||||
ARG LIBVNCCLIENT_OPTS=""
|
||||
|
||||
ARG LIBWEBSOCKETS_OPTS="\
|
||||
-DDISABLE_WERROR=ON \
|
||||
-DLWS_WITHOUT_SERVER=ON \
|
||||
-DLWS_WITHOUT_TESTAPPS=ON \
|
||||
-DLWS_WITHOUT_TEST_CLIENT=ON \
|
||||
-DLWS_WITHOUT_TEST_PING=ON \
|
||||
-DLWS_WITHOUT_TEST_SERVER=ON \
|
||||
-DLWS_WITHOUT_TEST_SERVER_EXTPOLL=ON \
|
||||
-DLWS_WITH_STATIC=OFF"
|
||||
|
||||
# Build guacamole-server and its core protocol library dependencies
|
||||
RUN ${BUILD_DIR}/src/guacd-docker/bin/build-all.sh
|
||||
|
||||
# Record the packages of all runtime library dependencies
|
||||
RUN ${PREFIX_DIR}/bin/list-dependencies.sh \
|
||||
RUN ${BUILD_DIR}/src/guacd-docker/bin/list-dependencies.sh \
|
||||
${PREFIX_DIR}/sbin/guacd \
|
||||
${PREFIX_DIR}/lib/libguac-client-*.so \
|
||||
${PREFIX_DIR}/lib/freerdp2/*guac*.so \
|
||||
> ${PREFIX_DIR}/DEPENDENCIES
|
||||
|
||||
# Use same Debian as the base for the runtime image
|
||||
FROM ubuntu:${UBUNTU_BASE_IMAGE}
|
||||
|
||||
#
|
||||
# The Debian repository that should be preferred for dependencies (this will be
|
||||
# added to /etc/apt/sources.list if not already present)
|
||||
#
|
||||
# NOTE: Due to limitations of the Docker image build process, this value is
|
||||
# duplicated in an ARG in the first stage of the build.
|
||||
#
|
||||
ARG UBUNTU_RELEASE=impish-backports
|
||||
|
||||
# Add repository for specified Ubuntu release if not already present in
|
||||
# sources.list
|
||||
RUN grep " ${UBUNTU_RELEASE} " /etc/apt/sources.list || echo >> /etc/apt/sources.list \
|
||||
"deb http://archive.ubuntu.com/ubuntu/ ${UBUNTU_RELEASE} main contrib non-free"
|
||||
# Use same Alpine version as the base for the runtime image
|
||||
FROM alpine:${ALPINE_BASE_IMAGE}
|
||||
|
||||
#
|
||||
# Base directory for installed build artifacts. See also the
|
||||
@ -119,36 +155,27 @@ RUN grep " ${UBUNTU_RELEASE} " /etc/apt/sources.list || echo >> /etc/apt/sources
|
||||
# NOTE: Due to limitations of the Docker image build process, this value is
|
||||
# duplicated in an ARG in the first stage of the build.
|
||||
#
|
||||
ARG PREFIX_DIR=/usr/local/guacamole
|
||||
ARG PREFIX_DIR=/opt/guacamole
|
||||
|
||||
# Runtime environment
|
||||
ENV LC_ALL=C.UTF-8
|
||||
ENV LD_LIBRARY_PATH=${PREFIX_DIR}/lib
|
||||
ENV GUACD_LOG_LEVEL=info
|
||||
|
||||
ARG RUNTIME_DEPENDENCIES=" \
|
||||
netcat-openbsd \
|
||||
ca-certificates \
|
||||
ghostscript \
|
||||
fonts-liberation \
|
||||
fonts-dejavu \
|
||||
xfonts-terminus"
|
||||
|
||||
# Do not require interaction during build
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Copy build artifacts into this stage
|
||||
COPY --from=builder ${PREFIX_DIR} ${PREFIX_DIR}
|
||||
|
||||
# Bring runtime environment up to date and install runtime dependencies
|
||||
RUN apt-get update && \
|
||||
apt-get install -t ${UBUNTU_RELEASE} -y --no-install-recommends $RUNTIME_DEPENDENCIES && \
|
||||
apt-get install -t ${UBUNTU_RELEASE} -y --no-install-recommends $(cat "${PREFIX_DIR}"/DEPENDENCIES) && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Link FreeRDP plugins into proper path
|
||||
RUN ${PREFIX_DIR}/bin/link-freerdp-plugins.sh \
|
||||
${PREFIX_DIR}/lib/freerdp2/libguac*.so
|
||||
RUN apk add --no-cache \
|
||||
ca-certificates \
|
||||
ghostscript \
|
||||
netcat-openbsd \
|
||||
shadow \
|
||||
terminus-font \
|
||||
ttf-dejavu \
|
||||
ttf-liberation \
|
||||
util-linux-login && \
|
||||
xargs apk add --no-cache < ${PREFIX_DIR}/DEPENDENCIES
|
||||
|
||||
# Checks the operating status every 5 minutes with a timeout of 5 seconds
|
||||
HEALTHCHECK --interval=5m --timeout=5s CMD nc -z 127.0.0.1 4822 || exit 1
|
||||
@ -157,7 +184,7 @@ HEALTHCHECK --interval=5m --timeout=5s CMD nc -z 127.0.0.1 4822 || exit 1
|
||||
ARG UID=1000
|
||||
ARG GID=1000
|
||||
RUN groupadd --gid $GID guacd
|
||||
RUN useradd --system --create-home --shell /usr/sbin/nologin --uid $UID --gid $GID guacd
|
||||
RUN useradd --system --create-home --shell /sbin/nologin --uid $UID --gid $GID guacd
|
||||
|
||||
# Run with user guacd
|
||||
USER guacd
|
||||
@ -170,5 +197,5 @@ EXPOSE 4822
|
||||
# Note the path here MUST correspond to the value specified in the
|
||||
# PREFIX_DIR build argument.
|
||||
#
|
||||
CMD /usr/local/guacamole/sbin/guacd -b 0.0.0.0 -L $GUACD_LOG_LEVEL -f
|
||||
CMD /opt/guacamole/sbin/guacd -b 0.0.0.0 -L $GUACD_LOG_LEVEL -f
|
||||
|
||||
|
@ -39,7 +39,6 @@ DIST_SUBDIRS = \
|
||||
src/protocols/rdp \
|
||||
src/protocols/ssh \
|
||||
src/protocols/telnet \
|
||||
src/protocols/tn5250 \
|
||||
src/protocols/vnc
|
||||
|
||||
SUBDIRS = \
|
||||
@ -74,10 +73,6 @@ if ENABLE_TELNET
|
||||
SUBDIRS += src/protocols/telnet
|
||||
endif
|
||||
|
||||
if ENABLE_TN5250
|
||||
SUBDIRS += src/protocols/tn5250
|
||||
endif
|
||||
|
||||
if ENABLE_VNC
|
||||
SUBDIRS += src/protocols/vnc
|
||||
endif
|
||||
|
@ -117,7 +117,7 @@ error() {
|
||||
##
|
||||
usage() {
|
||||
cat >&2 <<END
|
||||
guacctl 1.4.0, Apache Guacamole terminal session control utility.
|
||||
guacctl 1.5.0, Apache Guacamole terminal session control utility.
|
||||
Usage: guacctl [OPTION] [FILE or NAME]...
|
||||
|
||||
-d, --download download each of the files listed.
|
||||
|
@ -18,7 +18,7 @@
|
||||
#
|
||||
|
||||
AC_PREREQ([2.61])
|
||||
AC_INIT([guacamole-server], [1.4.0])
|
||||
AC_INIT([guacamole-server], [1.5.0])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
@ -1004,9 +1004,6 @@ fi
|
||||
AM_CONDITIONAL([ENABLE_TELNET], [test "x${have_libtelnet}" = "xyes" \
|
||||
-a "x${have_terminal}" = "xyes"])
|
||||
|
||||
AM_CONDITIONAL([ENABLE_TN5250], [test "x${have_libtelnet}" = "xyes" \
|
||||
-a "x${have_terminal}" = "xyes"])
|
||||
|
||||
AC_SUBST(TELNET_LIBS)
|
||||
|
||||
#
|
||||
@ -1193,7 +1190,6 @@ 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
|
||||
|
||||
@ -1205,7 +1201,6 @@ AM_COND_IF([ENABLE_KUBERNETES], [build_kubernetes=yes], [build_kubernetes=no])
|
||||
AM_COND_IF([ENABLE_RDP], [build_rdp=yes], [build_rdp=no])
|
||||
AM_COND_IF([ENABLE_SSH], [build_ssh=yes], [build_ssh=no])
|
||||
AM_COND_IF([ENABLE_TELNET], [build_telnet=yes], [build_telnet=no])
|
||||
AM_COND_IF([ENABLE_TN5250], [build_tn5250=yes], [build_tn5250=no])
|
||||
AM_COND_IF([ENABLE_VNC], [build_vnc=yes], [build_vnc=no])
|
||||
|
||||
#
|
||||
@ -1267,7 +1262,6 @@ $PACKAGE_NAME version $PACKAGE_VERSION
|
||||
RDP ........... ${build_rdp}
|
||||
SSH ........... ${build_ssh}
|
||||
Telnet ........ ${build_telnet}
|
||||
TN5250 ........ ${build_tn5250}
|
||||
VNC ........... ${build_vnc}
|
||||
|
||||
Services / tools:
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "common-ssh/user.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/fips.h>
|
||||
#include <libssh2.h>
|
||||
|
||||
#ifdef LIBSSH2_USES_GCRYPT
|
||||
@ -46,6 +47,20 @@
|
||||
GCRY_THREAD_OPTION_PTHREAD_IMPL;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A list of all key exchange algorithms that are both FIPS-compliant, and
|
||||
* OpenSSL-supported. Note that "ext-info-c" is also included. While not a key
|
||||
* exchange algorithm per se, it must be in the list to ensure that the server
|
||||
* will send a SSH_MSG_EXT_INFO response, which is required to perform RSA key
|
||||
* upgrades.
|
||||
*/
|
||||
#define FIPS_COMPLIANT_KEX_ALGORITHMS "diffie-hellman-group-exchange-sha256,ext-info-c"
|
||||
|
||||
/**
|
||||
* A list of ciphers that are both FIPS-compliant, and OpenSSL-supported.
|
||||
*/
|
||||
#define FIPS_COMPLIANT_CIPHERS "aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,aes192-cbc,aes256-cbc"
|
||||
|
||||
#ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS
|
||||
/**
|
||||
* Array of mutexes, used by OpenSSL.
|
||||
@ -165,9 +180,11 @@ int guac_common_ssh_init(guac_client* client) {
|
||||
CRYPTO_set_locking_callback(guac_common_ssh_openssl_locking_callback);
|
||||
#endif
|
||||
|
||||
/* Init OpenSSL */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
/* Init OpenSSL - only required for OpenSSL Versions < 1.1.0 */
|
||||
SSL_library_init();
|
||||
ERR_load_crypto_strings();
|
||||
#endif
|
||||
|
||||
/* Init libssh2 */
|
||||
libssh2_init(0);
|
||||
@ -484,6 +501,17 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If FIPS mode is enabled, prefer only FIPS-compatible algorithms and
|
||||
* ciphers that are also supported by libssh2. For more info, see:
|
||||
* https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp2906.pdf
|
||||
*/
|
||||
if (guac_fips_enabled()) {
|
||||
libssh2_session_method_pref(session, LIBSSH2_METHOD_KEX, FIPS_COMPLIANT_KEX_ALGORITHMS);
|
||||
libssh2_session_method_pref(session, LIBSSH2_METHOD_CRYPT_CS, FIPS_COMPLIANT_CIPHERS);
|
||||
libssh2_session_method_pref(session, LIBSSH2_METHOD_CRYPT_SC, FIPS_COMPLIANT_CIPHERS);
|
||||
}
|
||||
|
||||
/* Perform handshake */
|
||||
if (libssh2_session_handshake(session, fd)) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
||||
|
@ -166,6 +166,8 @@ void guac_common_display_free(guac_common_display* display) {
|
||||
void guac_common_display_dup(guac_common_display* display, guac_user* user,
|
||||
guac_socket* socket) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
|
||||
pthread_mutex_lock(&display->_lock);
|
||||
|
||||
/* Sunchronize shared cursor */
|
||||
@ -178,6 +180,9 @@ void guac_common_display_dup(guac_common_display* display, guac_user* user,
|
||||
guac_common_display_dup_layers(display->layers, user, socket);
|
||||
guac_common_display_dup_layers(display->buffers, user, socket);
|
||||
|
||||
/* Sends a sync instruction to mark the boundary of the first frame */
|
||||
guac_protocol_send_sync(socket, client->last_sent_timestamp, 1);
|
||||
|
||||
pthread_mutex_unlock(&display->_lock);
|
||||
|
||||
}
|
||||
@ -384,4 +389,3 @@ void guac_common_display_free_buffer(guac_common_display* display,
|
||||
pthread_mutex_unlock(&display->_lock);
|
||||
|
||||
}
|
||||
|
||||
|
115
src/guacd-docker/bin/build-all.sh
Executable file
115
src/guacd-docker/bin/build-all.sh
Executable file
@ -0,0 +1,115 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
##
|
||||
## @fn build-all.sh
|
||||
##
|
||||
## Builds the source of guacamole-server and its various core protocol library
|
||||
## dependencies.
|
||||
##
|
||||
|
||||
# Pre-populate build control variables such that the custom build prefix is
|
||||
# used for C headers, locating libraries, etc.
|
||||
export CFLAGS="-I${PREFIX_DIR}/include"
|
||||
export LDFLAGS="-L${PREFIX_DIR}/lib"
|
||||
export PKG_CONFIG_PATH="${PREFIX_DIR}/lib/pkgconfig"
|
||||
|
||||
# Ensure thread stack size will be 8 MB (glibc's default on Linux) rather than
|
||||
# 128 KB (musl's default)
|
||||
export LDFLAGS="$LDFLAGS -Wl,-z,stack-size=8388608"
|
||||
|
||||
##
|
||||
## Builds and installs the source at the given git repository, automatically
|
||||
## switching to the version of the source at the tag/commit that matches the
|
||||
## given pattern.
|
||||
##
|
||||
## @param URL
|
||||
## The URL of the git repository that the source should be downloaded from.
|
||||
##
|
||||
## @param PATTERN
|
||||
## The Perl-compatible regular expression that the tag must match. If no
|
||||
## tag matches the regular expression, the pattern is assumed to be an
|
||||
## exact reference to a commit, branch, etc. acceptable by git checkout.
|
||||
##
|
||||
## @param ...
|
||||
## Any additional command-line options that should be provided to CMake or
|
||||
## the configure script.
|
||||
##
|
||||
install_from_git() {
|
||||
|
||||
URL="$1"
|
||||
PATTERN="$2"
|
||||
shift 2
|
||||
|
||||
# Calculate top-level directory name of resulting repository from the
|
||||
# provided URL
|
||||
REPO_DIR="$(basename "$URL" .git)"
|
||||
|
||||
# Allow dependencies to be manually omitted with the tag/commit pattern "NO"
|
||||
if [ "$PATTERN" = "NO" ]; then
|
||||
echo "NOT building $REPO_DIR (explicitly skipped)"
|
||||
return
|
||||
fi
|
||||
|
||||
# Clone repository and change to top-level directory of source
|
||||
cd /tmp
|
||||
git clone "$URL"
|
||||
cd $REPO_DIR/
|
||||
|
||||
# Locate tag/commit based on provided pattern
|
||||
VERSION="$(git tag -l --sort=-v:refname | grep -Px -m1 "$PATTERN" \
|
||||
|| echo "$PATTERN")"
|
||||
|
||||
# Switch to desired version of source
|
||||
echo "Building $REPO_DIR @ $VERSION ..."
|
||||
git -c advice.detachedHead=false checkout "$VERSION"
|
||||
|
||||
# Configure build using CMake or GNU Autotools, whichever happens to be
|
||||
# used by the library being built
|
||||
if [ -e CMakeLists.txt ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX:PATH="$PREFIX_DIR" "$@" .
|
||||
else
|
||||
[ -e configure ] || autoreconf -fi
|
||||
./configure --prefix="$PREFIX_DIR" "$@"
|
||||
fi
|
||||
|
||||
# Build and install
|
||||
make && make install
|
||||
|
||||
}
|
||||
|
||||
#
|
||||
# Build and install core protocol library dependencies
|
||||
#
|
||||
|
||||
install_from_git "https://github.com/FreeRDP/FreeRDP" "$WITH_FREERDP" $FREERDP_OPTS
|
||||
install_from_git "https://github.com/libssh2/libssh2" "$WITH_LIBSSH2" $LIBSSH2_OPTS
|
||||
install_from_git "https://github.com/seanmiddleditch/libtelnet" "$WITH_LIBTELNET" $LIBTELNET_OPTS
|
||||
install_from_git "https://github.com/LibVNC/libvncserver" "$WITH_LIBVNCCLIENT" $LIBVNCCLIENT_OPTS
|
||||
install_from_git "https://libwebsockets.org/repo/libwebsockets" "$WITH_LIBWEBSOCKETS" $LIBWEBSOCKETS_OPTS
|
||||
|
||||
#
|
||||
# Build guacamole-server
|
||||
#
|
||||
|
||||
cd "$BUILD_DIR"
|
||||
autoreconf -fi && ./configure --prefix="$PREFIX_DIR" $GUACAMOLE_SERVER_OPTS
|
||||
make && make install
|
||||
|
@ -1,49 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
##
|
||||
## @fn build-guacd.sh
|
||||
##
|
||||
## Builds the source of guacamole-server, automatically creating any required
|
||||
## symbolic links for the proper loading of FreeRDP plugins.
|
||||
##
|
||||
## @param BUILD_DIR
|
||||
## The directory which currently contains the guacamole-server source and
|
||||
## in which the build should be performed.
|
||||
##
|
||||
## @param PREFIX_DIR
|
||||
## The directory prefix into which the build artifacts should be installed
|
||||
## in which the build should be performed. This is passed to the --prefix
|
||||
## option of `configure`.
|
||||
##
|
||||
|
||||
BUILD_DIR="$1"
|
||||
PREFIX_DIR="$2"
|
||||
|
||||
#
|
||||
# Build guacamole-server
|
||||
#
|
||||
|
||||
cd "$BUILD_DIR"
|
||||
autoreconf -fi
|
||||
./configure --prefix="$PREFIX_DIR" --disable-guaclog --with-freerdp-plugin-dir="$PREFIX_DIR/lib/freerdp2"
|
||||
make
|
||||
make install
|
||||
ldconfig
|
@ -1,76 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
##
|
||||
## @fn link-freerdp-plugins.sh
|
||||
##
|
||||
## Automatically creates any required symbolic links for the proper loading of
|
||||
## the given FreeRDP plugins. If a given plugin is already in the correct
|
||||
## directory, no link is created for that plugin.
|
||||
##
|
||||
## @param ...
|
||||
## The FreeRDP plugins to add links for.
|
||||
##
|
||||
|
||||
##
|
||||
## Locates the base directory of the FreeRDP installation (where the FreeRDP library
|
||||
## .so files are located), printing the result to STDOUT. If the directory cannot be
|
||||
## determined, an error is printed.
|
||||
##
|
||||
where_is_freerdp() {
|
||||
|
||||
# Determine the location of any freerdp2 .so files
|
||||
PATHS="$(find / -iname '*libfreerdp2.so.*' \
|
||||
| xargs -r dirname \
|
||||
| xargs -r realpath \
|
||||
| sort -u)"
|
||||
|
||||
# Verify that exactly one location was found
|
||||
if [ -z "$PATHS" -o "$(echo "$PATHS" | wc -l)" != 1 ]; then
|
||||
echo "$1: Unable to locate FreeRDP install location." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$PATHS"
|
||||
|
||||
}
|
||||
|
||||
#
|
||||
# Create symbolic links as necessary to include all given plugins within the
|
||||
# search path of FreeRDP
|
||||
#
|
||||
|
||||
# Determine correct install location for FreeRDP plugins
|
||||
FREERDP_DIR="$(where_is_freerdp)"
|
||||
FREERDP_PLUGIN_DIR="${FREERDP_DIR}/freerdp2"
|
||||
|
||||
while [ -n "$1" ]; do
|
||||
|
||||
# Add symbolic link if necessary
|
||||
if [ ! -e "$FREERDP_PLUGIN_DIR/$(basename "$1")" ]; then
|
||||
mkdir -p "$FREERDP_PLUGIN_DIR"
|
||||
ln -s "$1" "$FREERDP_PLUGIN_DIR"
|
||||
else
|
||||
echo "$1: Already in correct directory." >&2
|
||||
fi
|
||||
|
||||
shift
|
||||
|
||||
done
|
@ -21,7 +21,7 @@
|
||||
##
|
||||
## @fn list-dependencies.sh
|
||||
##
|
||||
## Lists the Debian/Ubuntu package names for all library dependencies of the
|
||||
## Lists the Alpine Linux package names for all library dependencies of the
|
||||
## given binaries. Each package is only listed once, even if multiple binaries
|
||||
## provided by the same package are given.
|
||||
##
|
||||
@ -35,19 +35,17 @@ while [ -n "$1" ]; do
|
||||
ldd "$1" | grep -v 'libguac' | awk '/=>/{print $(NF-1)}' \
|
||||
| while read LIBRARY; do
|
||||
|
||||
# In some cases, the library that's linked against is a hard link
|
||||
# to the file that's managed by the package, which dpkg doesn't understand.
|
||||
# Searching by */basename ensures the package will be found in these cases.
|
||||
LIBRARY_BASENAME=$(basename "$LIBRARY")
|
||||
|
||||
# Determine the Debian package which is associated with that
|
||||
# library, if any
|
||||
dpkg-query -S "*/$LIBRARY_BASENAME" || true
|
||||
# List the package providing that library, if any
|
||||
apk info -W "$LIBRARY" 2> /dev/null \
|
||||
| grep 'is owned by' | grep -o '[^ ]*$' || true
|
||||
|
||||
done
|
||||
|
||||
# Next binary
|
||||
shift
|
||||
|
||||
done | cut -f1 -d: | sort -u
|
||||
# Strip the "-VERSION" suffix from each package name, listing each resulting
|
||||
# package uniquely ("apk add" cannot handle package names that include the
|
||||
# version number)
|
||||
done | sed 's/\(.*\)-[0-9]\+\..*$/\1/' | sort -u
|
||||
|
||||
|
@ -381,10 +381,15 @@ int main(int argc, char* argv[]) {
|
||||
CRYPTO_set_locking_callback(guacd_openssl_locking_callback);
|
||||
#endif
|
||||
|
||||
/* Init SSL */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
/* Init OpenSSL for OpenSSL Versions < 1.1.0 */
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
ssl_context = SSL_CTX_new(SSLv23_server_method());
|
||||
#else
|
||||
/* Set up OpenSSL for OpenSSL Versions >= 1.1.0 */
|
||||
ssl_context = SSL_CTX_new(TLS_server_method());
|
||||
#endif
|
||||
|
||||
/* Load key */
|
||||
if (config->key_file != NULL) {
|
||||
|
@ -213,7 +213,7 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
|
||||
#endif
|
||||
}
|
||||
|
||||
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec,
|
||||
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* codec,
|
||||
int bitrate, int width, int height, int gop_size, int qmax, int qmin,
|
||||
int pix_fmt, AVRational time_base) {
|
||||
|
||||
@ -249,7 +249,7 @@ AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec,
|
||||
}
|
||||
|
||||
int guacenc_open_avcodec(AVCodecContext *avcodec_context,
|
||||
AVCodec *codec, AVDictionary **options,
|
||||
const AVCodec *codec, AVDictionary **options,
|
||||
AVStream* stream) {
|
||||
|
||||
int ret = avcodec_open2(avcodec_context, codec, options);
|
||||
|
@ -128,7 +128,7 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame);
|
||||
* The pointer to the configured AVCodecContext.
|
||||
*
|
||||
*/
|
||||
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec,
|
||||
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* codec,
|
||||
int bitrate, int width, int height, int gop_size, int qmax, int qmin,
|
||||
int pix_fmt, AVRational time_base);
|
||||
|
||||
@ -158,7 +158,7 @@ AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec,
|
||||
* Zero on success, a negative value on error.
|
||||
*/
|
||||
int guacenc_open_avcodec(AVCodecContext *avcodec_context,
|
||||
AVCodec *codec, AVDictionary **options,
|
||||
const AVCodec *codec, AVDictionary **options,
|
||||
AVStream* stream);
|
||||
|
||||
#endif
|
||||
|
@ -47,7 +47,7 @@
|
||||
guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
||||
int width, int height, int bitrate) {
|
||||
|
||||
AVOutputFormat *container_format;
|
||||
const AVOutputFormat *container_format;
|
||||
AVFormatContext *container_format_context;
|
||||
AVStream *video_stream;
|
||||
int ret;
|
||||
@ -63,7 +63,7 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
||||
container_format = container_format_context->oformat;
|
||||
|
||||
/* Pull codec based on name */
|
||||
AVCodec* codec = avcodec_find_encoder_by_name(codec_name);
|
||||
const AVCodec* codec = avcodec_find_encoder_by_name(codec_name);
|
||||
if (codec == NULL) {
|
||||
guacenc_log(GUAC_LOG_ERROR, "Failed to locate codec \"%s\".",
|
||||
codec_name);
|
||||
|
@ -44,6 +44,7 @@ libguacinc_HEADERS = \
|
||||
guacamole/client-types.h \
|
||||
guacamole/error.h \
|
||||
guacamole/error-types.h \
|
||||
guacamole/fips.h \
|
||||
guacamole/hash.h \
|
||||
guacamole/layer.h \
|
||||
guacamole/layer-types.h \
|
||||
@ -93,6 +94,7 @@ libguac_la_SOURCES = \
|
||||
encode-jpeg.c \
|
||||
encode-png.c \
|
||||
error.c \
|
||||
fips.c \
|
||||
hash.c \
|
||||
id.c \
|
||||
palette.c \
|
||||
@ -100,7 +102,7 @@ libguac_la_SOURCES = \
|
||||
pool.c \
|
||||
protocol.c \
|
||||
raw_encoder.c \
|
||||
recording.c \
|
||||
recording.c \
|
||||
socket.c \
|
||||
socket-broadcast.c \
|
||||
socket-fd.c \
|
||||
@ -137,7 +139,7 @@ libguac_la_CFLAGS = \
|
||||
-Werror -Wall -pedantic
|
||||
|
||||
libguac_la_LDFLAGS = \
|
||||
-version-info 20:0:0 \
|
||||
-version-info 21:0:0 \
|
||||
-no-undefined \
|
||||
@CAIRO_LIBS@ \
|
||||
@DL_LIBS@ \
|
||||
|
@ -307,6 +307,10 @@ int guac_client_add_user(guac_client* client, guac_user* user, int argc, char**
|
||||
|
||||
pthread_rwlock_unlock(&(client->__users_lock));
|
||||
|
||||
/* Notify owner of user joining connection. */
|
||||
if (retval == 0 && !user->owner)
|
||||
guac_client_owner_notify_join(client, user);
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
@ -333,6 +337,10 @@ void guac_client_remove_user(guac_client* client, guac_user* user) {
|
||||
|
||||
pthread_rwlock_unlock(&(client->__users_lock));
|
||||
|
||||
/* Update owner of user having left the connection. */
|
||||
if (!user->owner)
|
||||
guac_client_owner_notify_leave(client, user);
|
||||
|
||||
/* Call handler, if defined */
|
||||
if (user->leave_handler)
|
||||
user->leave_handler(user);
|
||||
@ -675,6 +683,36 @@ static void* __webp_support_callback(guac_user* user, void* data) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A callback function which is invoked by guac_client_owner_supports_msg()
|
||||
* to determine if the owner of a client supports the "msg" instruction,
|
||||
* returning zero if the user does not support the instruction or non-zero if
|
||||
* the user supports it.
|
||||
*
|
||||
* @param user
|
||||
* The guac_user that will be checked for "msg" instruction support.
|
||||
*
|
||||
* @param data
|
||||
* Data provided to the callback. This value is never used within this
|
||||
* callback.
|
||||
*
|
||||
* @return
|
||||
* A non-zero integer if the provided user who owns the connection supports
|
||||
* the "msg" instruction, or zero if the user does not. The integer is cast
|
||||
* as a void*.
|
||||
*/
|
||||
static void* guac_owner_supports_msg_callback(guac_user* user, void* data) {
|
||||
|
||||
return (void*) ((intptr_t) guac_user_supports_msg(user));
|
||||
|
||||
}
|
||||
|
||||
int guac_client_owner_supports_msg(guac_client* client) {
|
||||
|
||||
return (int) ((intptr_t) guac_client_for_owner(client, guac_owner_supports_msg_callback, NULL));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback function which is invoked by guac_client_owner_supports_required()
|
||||
* to determine if the owner of a client supports the "required" instruction,
|
||||
@ -705,6 +743,124 @@ int guac_client_owner_supports_required(guac_client* client) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback function that is invokved by guac_client_owner_notify_join() to
|
||||
* notify the owner of a connection that another user has joined the
|
||||
* connection, returning zero if the message is sent successfully, or non-zero
|
||||
* if an error occurs.
|
||||
*
|
||||
* @param user
|
||||
* The user to send the notification to, which will be the owner of the
|
||||
* connection.
|
||||
*
|
||||
* @param data
|
||||
* The data provided to the callback, which is the user that is joining the
|
||||
* connection.
|
||||
*
|
||||
* @return
|
||||
* Zero if the message is sent successfully to the owner, otherwise
|
||||
* non-zero, cast as a void*.
|
||||
*/
|
||||
static void* guac_client_owner_notify_join_callback(guac_user* user, void* data) {
|
||||
|
||||
const guac_user* joiner = (const guac_user *) data;
|
||||
|
||||
if (user == NULL)
|
||||
return (void*) ((intptr_t) -1);
|
||||
|
||||
char* log_owner = "owner";
|
||||
if (user->info.name != NULL)
|
||||
log_owner = (char *) user->info.name;
|
||||
|
||||
char* log_joiner = "anonymous";
|
||||
char* send_joiner = "";
|
||||
if (joiner->info.name != NULL) {
|
||||
log_joiner = (char *) joiner->info.name;
|
||||
send_joiner = (char *) joiner->info.name;
|
||||
}
|
||||
|
||||
guac_user_log(user, GUAC_LOG_DEBUG, "Notifying owner \"%s\" of \"%s\" joining.",
|
||||
log_owner, log_joiner);
|
||||
|
||||
/* Send user joined notification to owner. */
|
||||
const char* args[] = { (const char*)joiner->user_id, (const char*)send_joiner, NULL };
|
||||
return (void*) ((intptr_t) guac_protocol_send_msg(user->socket, GUAC_MESSAGE_USER_JOINED, args));
|
||||
|
||||
}
|
||||
|
||||
int guac_client_owner_notify_join(guac_client* client, guac_user* joiner) {
|
||||
|
||||
/* Don't send msg instruction if client does not support it. */
|
||||
if (!guac_client_owner_supports_msg(client)) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Client does not support the \"msg\" instruction and "
|
||||
"will not be notified of the user joining the connection.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int) ((intptr_t) guac_client_for_owner(client, guac_client_owner_notify_join_callback, joiner));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback function that is invokved by guac_client_owner_notify_leave() to
|
||||
* notify the owner of a connection that another user has left the connection,
|
||||
* returning zero if the message is sent successfully, or non-zero
|
||||
* if an error occurs.
|
||||
*
|
||||
* @param user
|
||||
* The user to send the notification to, which will be the owner of the
|
||||
* connection.
|
||||
*
|
||||
* @param data
|
||||
* The data provided to the callback, which is the user that is leaving the
|
||||
* connection.
|
||||
*
|
||||
* @return
|
||||
* Zero if the message is sent successfully to the owner, otherwise
|
||||
* non-zero, cast as a void*.
|
||||
*/
|
||||
static void* guac_client_owner_notify_leave_callback(guac_user* user, void* data) {
|
||||
|
||||
const guac_user* quitter = (const guac_user *) data;
|
||||
|
||||
if (user == NULL)
|
||||
return (void*) ((intptr_t) -1);
|
||||
|
||||
char* log_owner = "owner";
|
||||
if (user->info.name != NULL)
|
||||
log_owner = (char *) user->info.name;
|
||||
|
||||
char* log_quitter = "anonymous";
|
||||
char* send_quitter = "";
|
||||
if (quitter->info.name != NULL) {
|
||||
log_quitter = (char *) quitter->info.name;
|
||||
send_quitter = (char *) quitter->info.name;
|
||||
}
|
||||
|
||||
guac_user_log(user, GUAC_LOG_DEBUG, "Notifying owner \"%s\" of \"%s\" leaving.",
|
||||
log_owner, log_quitter);
|
||||
|
||||
/* Send user left notification to owner. */
|
||||
const char* args[] = { (const char*)quitter->user_id, (const char*)send_quitter, NULL };
|
||||
return (void*) ((intptr_t) guac_protocol_send_msg(user->socket, GUAC_MESSAGE_USER_LEFT, args));
|
||||
|
||||
}
|
||||
|
||||
int guac_client_owner_notify_leave(guac_client* client, guac_user* quitter) {
|
||||
|
||||
/* Don't send msg instruction if client does not support it. */
|
||||
if (!guac_client_owner_supports_msg(client)) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Client does not support the \"msg\" instruction and "
|
||||
"will not be notified of the user leaving the connection.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int) ((intptr_t) guac_client_for_owner(client, guac_client_owner_notify_leave_callback, quitter));
|
||||
|
||||
}
|
||||
|
||||
int guac_client_supports_webp(guac_client* client) {
|
||||
|
||||
#ifdef ENABLE_WEBP
|
||||
|
51
src/libguac/fips.c
Normal file
51
src/libguac/fips.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 "guacamole/fips.h"
|
||||
|
||||
/* If OpenSSL is available, include header for version numbers */
|
||||
#ifdef ENABLE_SSL
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
/* OpenSSL versions prior to 0.9.7e did not have FIPS support */
|
||||
#if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x00090705f)
|
||||
#define GUAC_FIPS_ENABLED 0
|
||||
|
||||
/* OpenSSL 3+ uses EVP_default_properties_is_fips_enabled() */
|
||||
#elif defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||
#include <openssl/evp.h>
|
||||
#define GUAC_FIPS_ENABLED EVP_default_properties_is_fips_enabled(NULL)
|
||||
|
||||
/* For OpenSSL versions between 0.9.7e and 3.0, use FIPS_mode() */
|
||||
#else
|
||||
#include <openssl/crypto.h>
|
||||
#define GUAC_FIPS_ENABLED FIPS_mode()
|
||||
#endif
|
||||
|
||||
/* FIPS support does not exist if OpenSSL is not available. */
|
||||
#else
|
||||
#define GUAC_FIPS_ENABLED 0
|
||||
#endif
|
||||
|
||||
int guac_fips_enabled() {
|
||||
|
||||
return GUAC_FIPS_ENABLED;
|
||||
|
||||
}
|
@ -737,6 +737,21 @@ void guac_client_stream_webp(guac_client* client, guac_socket* socket,
|
||||
guac_composite_mode mode, const guac_layer* layer, int x, int y,
|
||||
cairo_surface_t* surface, int quality, int lossless);
|
||||
|
||||
/**
|
||||
* Returns whether the owner of the given client supports the "msg"
|
||||
* instruction, returning non-zero if the client owner does support the
|
||||
* instruction, or zero if the owner does not.
|
||||
*
|
||||
* @param client
|
||||
* The Guacamole client whose owner should be checked for supporting
|
||||
* the "msg" instruction.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if the owner of the given client supports the "msg"
|
||||
* instruction, zero otherwise.
|
||||
*/
|
||||
int guac_client_owner_supports_msg(guac_client* client);
|
||||
|
||||
/**
|
||||
* Returns whether the owner of the given client supports the "required"
|
||||
* instruction, returning non-zero if the client owner does support the
|
||||
@ -752,6 +767,42 @@ void guac_client_stream_webp(guac_client* client, guac_socket* socket,
|
||||
*/
|
||||
int guac_client_owner_supports_required(guac_client* client);
|
||||
|
||||
/**
|
||||
* Notifies the owner of the given client that a user has joined the connection,
|
||||
* and returns zero if the message was sent successfully, or non-zero if the
|
||||
* notification failed.
|
||||
*
|
||||
* @param client
|
||||
* The Guacamole Client whose owner should be notified of a user joining
|
||||
* the connection.
|
||||
*
|
||||
* @param joiner
|
||||
* The Guacamole User who joined the connection.
|
||||
*
|
||||
* @return
|
||||
* Zero if the notification to the owner was sent successfully, or non-zero
|
||||
* if an error occurred.
|
||||
*/
|
||||
int guac_client_owner_notify_join(guac_client* client, guac_user* joiner);
|
||||
|
||||
/**
|
||||
* Notifies the owner of the given client that a user has left the connection,
|
||||
* and returns zero if the message was sent successfully, or non-zero if the
|
||||
* notification failed.
|
||||
*
|
||||
* @param client
|
||||
* The Guacamole Client whose owner should be notified of a user leaving
|
||||
* the connection.
|
||||
*
|
||||
* @param quitter
|
||||
* The Guacamole User who left the connection.
|
||||
*
|
||||
* @return
|
||||
* Zero if the notification to the owner was sent successfully, or non-zero
|
||||
* if an error occurred.
|
||||
*/
|
||||
int guac_client_owner_notify_leave(guac_client* client, guac_user* quitter);
|
||||
|
||||
/**
|
||||
* Returns whether all users of the given client support WebP. If any user does
|
||||
* not support WebP, or the server cannot encode WebP images, zero is returned.
|
||||
|
@ -17,22 +17,17 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_TN5250_USER_H
|
||||
#define GUAC_TN5250_USER_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
#ifndef GUAC_FIPS_H
|
||||
#define GUAC_FIPS_H
|
||||
|
||||
/**
|
||||
* Handler for joining users.
|
||||
* Returns a non-zero value if FIPS mode is enabled, or zero if FIPS mode
|
||||
* is not enabled.
|
||||
*
|
||||
* @return
|
||||
* A non-zero value if FIPS mode is enabled, or zero if FIPS mode is
|
||||
* not enabled.
|
||||
*/
|
||||
guac_user_join_handler guac_tn5250_user_join_handler;
|
||||
|
||||
/**
|
||||
* Handler for leaving users.
|
||||
*/
|
||||
guac_user_leave_handler guac_tn5250_user_leave_handler;
|
||||
int guac_fips_enabled();
|
||||
|
||||
#endif
|
||||
|
@ -38,7 +38,7 @@
|
||||
* This version is passed by the __guac_protocol_send_args() function from the
|
||||
* server to the client during the client/server handshake.
|
||||
*/
|
||||
#define GUACAMOLE_PROTOCOL_VERSION "VERSION_1_3_0"
|
||||
#define GUACAMOLE_PROTOCOL_VERSION "VERSION_1_5_0"
|
||||
|
||||
/**
|
||||
* The maximum number of bytes that should be sent in any one blob instruction
|
||||
|
@ -306,9 +306,40 @@ typedef enum guac_protocol_version {
|
||||
* allowing connections in guacd to request information from the client and
|
||||
* await a response.
|
||||
*/
|
||||
GUAC_PROTOCOL_VERSION_1_3_0 = 0x010300
|
||||
GUAC_PROTOCOL_VERSION_1_3_0 = 0x010300,
|
||||
|
||||
/**
|
||||
* Protocol version 1.5.0, which supports the "msg" instruction, allowing
|
||||
* messages to be sent to the client, and adds support for the "name"
|
||||
* handshake instruction.
|
||||
*/
|
||||
GUAC_PROTOCOL_VERSION_1_5_0 = 0x010500
|
||||
|
||||
} guac_protocol_version;
|
||||
|
||||
/**
|
||||
* A type that represents codes for human-readable messages sent by the "msg"
|
||||
* instruction to the Client, that will be displayed in the client's browser.
|
||||
* The codes will be interpreted by the client into translatable messages, and
|
||||
* make take arguments, as noted below.
|
||||
*/
|
||||
typedef enum guac_message_type {
|
||||
|
||||
/**
|
||||
* A message that notifies the owner of a connection that another user has
|
||||
* joined their connection. There should be a single argument provided, the
|
||||
* name of the user who has joined.
|
||||
*/
|
||||
GUAC_MESSAGE_USER_JOINED = 0x0001,
|
||||
|
||||
/**
|
||||
* A message that notifies the owner of a connection that another user has
|
||||
* left their connection. There should be a single argument provided, the
|
||||
* name of the user who has left.
|
||||
*/
|
||||
GUAC_MESSAGE_USER_LEFT = 0x0002
|
||||
|
||||
} guac_message_type;
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -171,6 +171,27 @@ int guac_protocol_send_log(guac_socket* socket, const char* format, ...);
|
||||
int vguac_protocol_send_log(guac_socket* socket, const char* format,
|
||||
va_list args);
|
||||
|
||||
/**
|
||||
* Sends the given string over the socket to be displayed on the client. Returns
|
||||
* zero if the message was sent successfully or non-zero if an error occurs.
|
||||
*
|
||||
* @param socket
|
||||
* The guac_socket connection to send the message to.
|
||||
*
|
||||
* @param msg
|
||||
* The message code to send to the client.
|
||||
*
|
||||
* @param args
|
||||
* A null-terminated array of strings that will be provided to the client
|
||||
* as part of the message, that the client may then place in the message,
|
||||
* or null if the message requires no arguments.
|
||||
*
|
||||
* @return
|
||||
* Zero if the message is sent successfully; otherwise non-zero.
|
||||
*/
|
||||
int guac_protocol_send_msg(guac_socket* socket, guac_message_type msg,
|
||||
const char** args);
|
||||
|
||||
/**
|
||||
* Sends a mouse instruction over the given guac_socket connection.
|
||||
*
|
||||
|
@ -102,6 +102,14 @@ struct guac_user_info {
|
||||
*/
|
||||
guac_protocol_version protocol_version;
|
||||
|
||||
/**
|
||||
* The human-readable name of the Guacamole user, supplied by the client
|
||||
* during the handshake. This is an arbitrary value, with no requirements or
|
||||
* constraints, including that it need not uniquely identify the user.
|
||||
* If the client does not provide a name then this will be NULL.
|
||||
*/
|
||||
const char* name;
|
||||
|
||||
};
|
||||
|
||||
struct guac_user {
|
||||
@ -850,6 +858,17 @@ void guac_user_stream_webp(guac_user* user, guac_socket* socket,
|
||||
guac_composite_mode mode, const guac_layer* layer, int x, int y,
|
||||
cairo_surface_t* surface, int quality, int lossless);
|
||||
|
||||
/**
|
||||
* Returns whether the given user supports the "msg" instruction.
|
||||
*
|
||||
* @param user
|
||||
* The Guacamole user to check for support of the "msg" instruction.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if the user supports the "msg" instruction, otherwise zero.
|
||||
*/
|
||||
int guac_user_supports_msg(guac_user* user);
|
||||
|
||||
/**
|
||||
* Returns whether the given user supports the "required" instruction.
|
||||
*
|
||||
|
@ -65,6 +65,7 @@ guac_protocol_version_mapping guac_protocol_version_table[] = {
|
||||
{ GUAC_PROTOCOL_VERSION_1_0_0, "VERSION_1_0_0" },
|
||||
{ GUAC_PROTOCOL_VERSION_1_1_0, "VERSION_1_1_0" },
|
||||
{ GUAC_PROTOCOL_VERSION_1_3_0, "VERSION_1_3_0" },
|
||||
{ GUAC_PROTOCOL_VERSION_1_5_0, "VERSION_1_5_0" },
|
||||
{ GUAC_PROTOCOL_VERSION_UNKNOWN, NULL }
|
||||
};
|
||||
|
||||
@ -658,6 +659,23 @@ int guac_protocol_send_log(guac_socket* socket, const char* format, ...) {
|
||||
|
||||
}
|
||||
|
||||
int guac_protocol_send_msg(guac_socket* socket, guac_message_type msg,
|
||||
const char** args) {
|
||||
|
||||
int ret_val;
|
||||
|
||||
guac_socket_instruction_begin(socket);
|
||||
ret_val =
|
||||
guac_socket_write_string(socket, "3.msg,")
|
||||
|| __guac_socket_write_length_int(socket, msg)
|
||||
|| guac_socket_write_array(socket, args)
|
||||
|| guac_socket_write_string(socket, ";");
|
||||
|
||||
guac_socket_instruction_end(socket);
|
||||
return ret_val;
|
||||
|
||||
}
|
||||
|
||||
int guac_protocol_send_file(guac_socket* socket, const guac_stream* stream,
|
||||
const char* mimetype, const char* name) {
|
||||
|
||||
|
@ -27,11 +27,11 @@
|
||||
*/
|
||||
void test_guac_protocol__version_to_string() {
|
||||
|
||||
guac_protocol_version version_a = GUAC_PROTOCOL_VERSION_1_3_0;
|
||||
guac_protocol_version version_a = GUAC_PROTOCOL_VERSION_1_5_0;
|
||||
guac_protocol_version version_b = GUAC_PROTOCOL_VERSION_1_0_0;
|
||||
guac_protocol_version version_c = GUAC_PROTOCOL_VERSION_UNKNOWN;
|
||||
|
||||
CU_ASSERT_STRING_EQUAL(guac_protocol_version_to_string(version_a), "VERSION_1_3_0");
|
||||
CU_ASSERT_STRING_EQUAL(guac_protocol_version_to_string(version_a), "VERSION_1_5_0");
|
||||
CU_ASSERT_STRING_EQUAL(guac_protocol_version_to_string(version_b), "VERSION_1_0_0");
|
||||
CU_ASSERT_PTR_NULL(guac_protocol_version_to_string(version_c));
|
||||
|
||||
|
@ -64,6 +64,7 @@ __guac_instruction_handler_mapping __guac_handshake_handler_map[] = {
|
||||
{"video", __guac_handshake_video_handler},
|
||||
{"image", __guac_handshake_image_handler},
|
||||
{"timezone", __guac_handshake_timezone_handler},
|
||||
{"name", __guac_handshake_name_handler},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@ -684,6 +685,23 @@ int __guac_handshake_image_handler(guac_user* user, int argc, char** argv) {
|
||||
|
||||
}
|
||||
|
||||
int __guac_handshake_name_handler(guac_user* user, int argc, char** argv) {
|
||||
|
||||
/* Free any past value for the user's name */
|
||||
free((char *) user->info.name);
|
||||
|
||||
/* If a value is provided for the name, copy it into guac_user. */
|
||||
if (argc > 0 && strcmp(argv[0], ""))
|
||||
user->info.name = (const char*) strdup(argv[0]);
|
||||
|
||||
/* No or empty value was provided, so make sure this is NULLed out. */
|
||||
else
|
||||
user->info.name = NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int __guac_handshake_timezone_handler(guac_user* user, int argc, char** argv) {
|
||||
|
||||
/* Free any past value */
|
||||
|
@ -218,6 +218,13 @@ __guac_instruction_handler __guac_handshake_video_handler;
|
||||
*/
|
||||
__guac_instruction_handler __guac_handshake_image_handler;
|
||||
|
||||
/**
|
||||
* Internal handler function that is called when the name instruction is
|
||||
* received during the handshake process, specifying the name of the Guacamole
|
||||
* user establishing the connection.
|
||||
*/
|
||||
__guac_instruction_handler __guac_handshake_name_handler;
|
||||
|
||||
/**
|
||||
* Internal handler function that is called when the timezone instruction is
|
||||
* received during the handshake process, specifying the timezone of the
|
||||
|
@ -296,6 +296,7 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) {
|
||||
user->info.audio_mimetypes = NULL;
|
||||
user->info.image_mimetypes = NULL;
|
||||
user->info.video_mimetypes = NULL;
|
||||
user->info.name = NULL;
|
||||
user->info.timezone = NULL;
|
||||
|
||||
/* Count number of arguments. */
|
||||
@ -370,7 +371,8 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) {
|
||||
guac_free_mimetypes((char **) user->info.image_mimetypes);
|
||||
guac_free_mimetypes((char **) user->info.video_mimetypes);
|
||||
|
||||
/* Free timezone info. */
|
||||
/* Free name and timezone info. */
|
||||
free((char *) user->info.name);
|
||||
free((char *) user->info.timezone);
|
||||
|
||||
guac_parser_free(parser);
|
||||
|
@ -316,6 +316,15 @@ void guac_user_stream_webp(guac_user* user, guac_socket* socket,
|
||||
|
||||
}
|
||||
|
||||
int guac_user_supports_msg(guac_user* user) {
|
||||
|
||||
if (user == NULL)
|
||||
return 0;
|
||||
|
||||
return (user->info.protocol_version >= GUAC_PROTOCOL_VERSION_1_5_0);
|
||||
|
||||
}
|
||||
|
||||
int guac_user_supports_required(guac_user* user) {
|
||||
|
||||
if (user == NULL)
|
||||
|
@ -230,6 +230,7 @@ BUILT_SOURCES = \
|
||||
rdp_keymaps = \
|
||||
$(srcdir)/keymaps/base.keymap \
|
||||
$(srcdir)/keymaps/failsafe.keymap \
|
||||
$(srcdir)/keymaps/cs-cz-qwertz.keymap \
|
||||
$(srcdir)/keymaps/de_de_qwertz.keymap \
|
||||
$(srcdir)/keymaps/de_ch_qwertz.keymap \
|
||||
$(srcdir)/keymaps/en_gb_qwerty.keymap \
|
||||
|
79
src/protocols/rdp/keymaps/cs-cz-qwertz.keymap
Normal file
79
src/protocols/rdp/keymaps/cs-cz-qwertz.keymap
Normal file
@ -0,0 +1,79 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "cs-cz-qwertz"
|
||||
freerdp "KBD_CZECH"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0D ~ ";+ěščřžýáíé=´"
|
||||
map -caps -altgr -shift 0x10..0x1B ~ "qwertzuıopú)"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjklů§¨"
|
||||
map -caps -altgr -shift 0x2C..0x35 ~ "yxcvbnm,.-"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0D ~ "°1234567890%ˇ"
|
||||
map -caps -altgr +shift 0x10..0x1B ~ "QWERTZUIOP/("
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKL"!'"
|
||||
map -caps -altgr +shift 0x2C..0x35 ~ "YXCVBNM?:_"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0D ~ ";+ĚŠČŘŽÝÁÍÉ=´"
|
||||
map +caps -altgr -shift 0x10..0x1B ~ "QWERTZUIOPÚ)"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKL٧¨"
|
||||
map +caps -altgr -shift 0x2C..0x35 ~ "YXCVBNM,.-"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0D ~ "°1234567890%ˇ"
|
||||
map +caps -altgr +shift 0x10..0x1B ~ "qwertzuiop/("
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjkl"!'"
|
||||
map +caps -altgr +shift 0x2C..0x35 ~ "yxcvbnm?:_"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x02 ~ "~"
|
||||
|
||||
map +altgr -shift 0x10 ~ "\"
|
||||
map +altgr -shift 0x11 ~ "|"
|
||||
map +altgr -shift 0x12 ~ "€"
|
||||
map +altgr -shift 0x1A ~ "÷"
|
||||
map +altgr -shift 0x1B ~ "×"
|
||||
|
||||
map +altgr -shift 0x1F ~ "đ"
|
||||
map +altgr -shift 0x20 ~ "Đ"
|
||||
map +altgr -shift 0x21 ~ "["
|
||||
map +altgr -shift 0x22 ~ "]"
|
||||
map +altgr -shift 0x25 ~ "ł"
|
||||
map +altgr -shift 0x26 ~ "Ł"
|
||||
map +altgr -shift 0x27 ~ "$"
|
||||
map +altgr -shift 0x28 ~ "ß"
|
||||
map +altgr -shift 0x2B ~ "¤"
|
||||
|
||||
map +altgr -shift 0x2D ~ "#"
|
||||
map +altgr -shift 0x2E ~ "&"
|
||||
map +altgr -shift 0x2F ~ "@"
|
||||
map +altgr -shift 0x30 ~ "{"
|
||||
map +altgr -shift 0x31 ~ "}"
|
||||
map +altgr -shift 0x33 ~ "<"
|
||||
map +altgr -shift 0x34 ~ ">"
|
||||
map +altgr -shift 0x35 ~ "*"
|
||||
|
||||
# END
|
@ -28,6 +28,7 @@
|
||||
#include <freerdp/settings.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/fips.h>
|
||||
#include <guacamole/string.h>
|
||||
#include <guacamole/user.h>
|
||||
#include <guacamole/wol-constants.h>
|
||||
@ -39,6 +40,16 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* A warning to log when NLA mode is selected while FIPS mode is active on the
|
||||
* guacd server.
|
||||
*/
|
||||
const char fips_nla_mode_warning[] = (
|
||||
"NLA security mode was selected, but is known to be currently incompatible "
|
||||
"with FIPS mode (see FreeRDP/FreeRDP#3412). Security negotiation with the "
|
||||
"RDP server may fail unless TLS security mode is selected instead."
|
||||
);
|
||||
|
||||
/* Client plugin arguments */
|
||||
const char* GUAC_RDP_CLIENT_ARGS[] = {
|
||||
"hostname",
|
||||
@ -706,12 +717,27 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
|
||||
if (strcmp(argv[IDX_SECURITY], "nla") == 0) {
|
||||
guac_user_log(user, GUAC_LOG_INFO, "Security mode: NLA");
|
||||
settings->security_mode = GUAC_SECURITY_NLA;
|
||||
|
||||
/*
|
||||
* NLA is known not to work with FIPS; allow the mode selection but
|
||||
* warn that it will not work.
|
||||
*/
|
||||
if (guac_fips_enabled())
|
||||
guac_user_log(user, GUAC_LOG_WARNING, fips_nla_mode_warning);
|
||||
|
||||
}
|
||||
|
||||
/* Extended NLA security */
|
||||
else if (strcmp(argv[IDX_SECURITY], "nla-ext") == 0) {
|
||||
guac_user_log(user, GUAC_LOG_INFO, "Security mode: Extended NLA");
|
||||
settings->security_mode = GUAC_SECURITY_EXTENDED_NLA;
|
||||
|
||||
/*
|
||||
* NLA is known not to work with FIPS; allow the mode selection but
|
||||
* warn that it will not work.
|
||||
*/
|
||||
if (guac_fips_enabled())
|
||||
guac_user_log(user, GUAC_LOG_WARNING, fips_nla_mode_warning);
|
||||
}
|
||||
|
||||
/* TLS security */
|
||||
@ -1529,7 +1555,21 @@ void guac_rdp_push_settings(guac_client* client,
|
||||
case GUAC_SECURITY_ANY:
|
||||
rdp_settings->RdpSecurity = TRUE;
|
||||
rdp_settings->TlsSecurity = TRUE;
|
||||
rdp_settings->NlaSecurity = guac_settings->username && guac_settings->password;
|
||||
|
||||
/* Explicitly disable NLA if FIPS mode is enabled - it won't work */
|
||||
if (guac_fips_enabled()) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_INFO,
|
||||
"FIPS mode is enabled. Excluding NLA security mode from security negotiation "
|
||||
"(see: https://github.com/FreeRDP/FreeRDP/issues/3412).");
|
||||
rdp_settings->NlaSecurity = FALSE;
|
||||
|
||||
}
|
||||
|
||||
/* NLA mode is allowed if FIPS is not enabled */
|
||||
else
|
||||
rdp_settings->NlaSecurity = TRUE;
|
||||
|
||||
rdp_settings->ExtSecurity = FALSE;
|
||||
break;
|
||||
|
||||
|
@ -1,67 +0,0 @@
|
||||
#
|
||||
# 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 \
|
||||
lib5250/lib5250.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
argv.h \
|
||||
client.h \
|
||||
clipboard.h \
|
||||
input.h \
|
||||
pipe.h \
|
||||
settings.h \
|
||||
tn5250.h \
|
||||
user.h \
|
||||
lib5250/lib5250.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@ \
|
||||
@TELNET_LIBS@
|
||||
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int guac_tn5250_argv_callback(guac_user* user, const char* mimetype,
|
||||
const char* name, const char* value, void* data) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_tn5250_client* tn5250_client = (guac_tn5250_client*) client->data;
|
||||
guac_terminal* terminal = tn5250_client->term;
|
||||
|
||||
/* Update color scheme */
|
||||
if (strcmp(name, GUAC_TN5250_ARGV_COLOR_SCHEME) == 0)
|
||||
guac_terminal_apply_color_scheme(terminal, value);
|
||||
|
||||
/* Update font name */
|
||||
else if (strcmp(name, GUAC_TN5250_ARGV_FONT_NAME) == 0)
|
||||
guac_terminal_apply_font(terminal, value, -1, 0);
|
||||
|
||||
/* Update only if font size is sane */
|
||||
else if (strcmp(name, GUAC_TN5250_ARGV_FONT_SIZE) == 0) {
|
||||
int size = atoi(value);
|
||||
if (size > 0)
|
||||
guac_terminal_apply_font(terminal, NULL, size,
|
||||
tn5250_client->settings->resolution);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void* guac_tn5250_send_current_argv(guac_user* user, void* data) {
|
||||
|
||||
guac_tn5250_client* tn5250_client = (guac_tn5250_client*) data;
|
||||
guac_terminal* terminal = tn5250_client->term;
|
||||
|
||||
/* Send current color scheme */
|
||||
guac_user_stream_argv(user, user->socket, "text/plain",
|
||||
GUAC_TN5250_ARGV_COLOR_SCHEME,
|
||||
guac_terminal_get_color_scheme(terminal));
|
||||
|
||||
/* Send current font name */
|
||||
guac_user_stream_argv(user, user->socket, "text/plain",
|
||||
GUAC_TN5250_ARGV_FONT_NAME,
|
||||
guac_terminal_get_font_name(terminal));
|
||||
|
||||
/* Send current font size */
|
||||
char font_size[64];
|
||||
sprintf(font_size, "%i", guac_terminal_get_font_size(terminal));
|
||||
guac_user_stream_argv(user, user->socket, "text/plain",
|
||||
GUAC_TN5250_ARGV_FONT_SIZE, font_size);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* 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/argv.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* The name of the parameter that specifies/updates the color scheme used by
|
||||
* the terminal emulator.
|
||||
*/
|
||||
#define GUAC_TN5250_ARGV_COLOR_SCHEME "color-scheme"
|
||||
|
||||
/**
|
||||
* The name of the parameter that specifies/updates the name of the font used
|
||||
* by the terminal emulator.
|
||||
*/
|
||||
#define GUAC_TN5250_ARGV_FONT_NAME "font-name"
|
||||
|
||||
/**
|
||||
* The name of the parameter that specifies/updates the font size used by the
|
||||
* terminal emulator.
|
||||
*/
|
||||
#define GUAC_TN5250_ARGV_FONT_SIZE "font-size"
|
||||
|
||||
/**
|
||||
* Handles a received argument value from a Guacamole "argv" instruction,
|
||||
* updating the given connection parameter.
|
||||
*/
|
||||
guac_argv_callback guac_tn5250_argv_callback;
|
||||
|
||||
/**
|
||||
* Sends the current values of all non-sensitive parameters which may be set
|
||||
* while the connection is running to the given user. Note that the user
|
||||
* receiving these values will not necessarily be able to set new values
|
||||
* themselves if their connection is read-only. This function can be used as
|
||||
* the callback for guac_client_foreach_user() and guac_client_for_owner()
|
||||
*
|
||||
* @param user
|
||||
* The user that should receive the values of all non-sensitive parameters
|
||||
* which may be set while the connection is running.
|
||||
*
|
||||
* @param data
|
||||
* The guac_n5250_client instance associated with the current connection.
|
||||
*
|
||||
* @return
|
||||
* Always NULL.
|
||||
*/
|
||||
void* guac_tn5250_send_current_argv(guac_user* user, void* data);
|
||||
|
||||
#endif
|
||||
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* 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 "client.h"
|
||||
#include "settings.h"
|
||||
#include "tn5250.h"
|
||||
#include "user.h"
|
||||
|
||||
#include <langinfo.h>
|
||||
#include <locale.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <guacamole/argv.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/recording.h>
|
||||
|
||||
int guac_client_init(guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_INFO, "%s: Starting initialization of TN5250 client.", __func__);
|
||||
|
||||
/* 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 tn5250 client */
|
||||
tn5250_client->socket_fd = -1;
|
||||
tn5250_client->echo_enabled = 1;
|
||||
|
||||
/* Set handlers */
|
||||
client->join_handler = guac_tn5250_user_join_handler;
|
||||
client->free_handler = guac_tn5250_client_free_handler;
|
||||
client->leave_handler = guac_tn5250_user_leave_handler;
|
||||
|
||||
/* Register handlers for argument values that may be sent after the handshake */
|
||||
guac_argv_register(GUAC_TN5250_ARGV_COLOR_SCHEME, guac_tn5250_argv_callback, NULL, GUAC_ARGV_OPTION_ECHO);
|
||||
guac_argv_register(GUAC_TN5250_ARGV_FONT_NAME, guac_tn5250_argv_callback, NULL, GUAC_ARGV_OPTION_ECHO);
|
||||
guac_argv_register(GUAC_TN5250_ARGV_FONT_SIZE, guac_tn5250_argv_callback, NULL, GUAC_ARGV_OPTION_ECHO);
|
||||
|
||||
/* 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_recording_free(tn5250_client->recording);
|
||||
|
||||
/* Kill terminal */
|
||||
guac_terminal_free(tn5250_client->term);
|
||||
|
||||
/* Wait for and free telnet session, if connected */
|
||||
if (tn5250_client->tn5250 != NULL) {
|
||||
pthread_join(tn5250_client->client_thread, NULL);
|
||||
telnet_free(tn5250_client->tn5250);
|
||||
}
|
||||
|
||||
/* Free settings */
|
||||
if (tn5250_client->settings != NULL)
|
||||
guac_tn5250_settings_free(tn5250_client->settings);
|
||||
|
||||
free(tn5250_client);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* 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 "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_terminal_clipboard_reset(tn5250_client->term, 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_terminal_clipboard_append(tn5250_client->term, 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;
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
|
@ -1,138 +0,0 @@
|
||||
/*
|
||||
* 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 "input.h"
|
||||
#include "terminal/terminal.h"
|
||||
#include "tn5250.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/recording.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_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_recording_report_key(tn5250_client->recording,
|
||||
keysym, pressed);
|
||||
|
||||
/* Skip if terminal not yet ready */
|
||||
if (term == NULL)
|
||||
return 0;
|
||||
|
||||
/* Stop searching for password */
|
||||
if (settings->password_regex != NULL) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Stopping password prompt search due to user input.");
|
||||
|
||||
regfree(settings->password_regex);
|
||||
free(settings->password_regex);
|
||||
settings->password_regex = NULL;
|
||||
|
||||
}
|
||||
|
||||
/* Stop searching for username */
|
||||
if (settings->username_regex != NULL) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Stopping username prompt search due to user input.");
|
||||
|
||||
regfree(settings->username_regex);
|
||||
free(settings->username_regex);
|
||||
settings->username_regex = NULL;
|
||||
|
||||
}
|
||||
|
||||
/* Intercept and handle Pause / Break / Ctrl+0 as "IAC BRK" */
|
||||
if (pressed && (
|
||||
keysym == 0xFF13 /* Pause */
|
||||
|| keysym == 0xFF6B /* Break */
|
||||
|| (
|
||||
guac_terminal_get_mod_ctrl(term)
|
||||
&& keysym == '0'
|
||||
) /* Ctrl + 0 */
|
||||
)) {
|
||||
|
||||
/* Send IAC BRK */
|
||||
telnet_iac(tn5250_client->tn5250, 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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* 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 "lib5250.h"
|
||||
#include "tn5250.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
int guac_lib5250_process_packet(const char* data, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "%s: Processing expected TN5250 SNA data.", __func__);
|
||||
|
||||
guac_lib5250_packet* packet = (guac_lib5250_packet*) data;
|
||||
|
||||
if (ntohs(packet->type) != GUAC_LIB5250_SNA_GDS) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
||||
"%s: Unexpected SNA packet typing parsing TN5250 packet: 0x%x",
|
||||
__func__, ntohs(packet->type));
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (packet->opcode) {
|
||||
|
||||
case GUAC_LIB5250_OPCODE_NOOP:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode no-op.", __func__);
|
||||
break;
|
||||
|
||||
case GUAC_LIB5250_OPCODE_INVITE:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode invite.", __func__);
|
||||
break;
|
||||
|
||||
case GUAC_LIB5250_OPCODE_OUTPUT:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode output.", __func__);
|
||||
break;
|
||||
|
||||
case GUAC_LIB5250_OPCODE_PUTGET:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode put/get.", __func__);
|
||||
break;
|
||||
|
||||
case GUAC_LIB5250_OPCODE_SAVESCREEN:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode save screen.", __func__);
|
||||
break;
|
||||
|
||||
case GUAC_LIB5250_OPCODE_RESTORESCREEN:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode restore screen.", __func__);
|
||||
break;
|
||||
|
||||
case GUAC_LIB5250_OPCODE_READIMMEDIATE:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode read immediate.", __func__);
|
||||
break;
|
||||
|
||||
case GUAC_LIB5250_OPCODE_READSCREEN:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode read screen.", __func__);
|
||||
break;
|
||||
|
||||
case GUAC_LIB5250_OPCODE_CANCELINVITE:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode cancel invite.", __func__);
|
||||
break;
|
||||
|
||||
case GUAC_LIB5250_OPCODE_MSGON:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode msg on.", __func__);
|
||||
break;
|
||||
|
||||
case GUAC_LIB5250_OPCODE_MSGOFF:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode msg off.", __func__);
|
||||
break;
|
||||
|
||||
default:
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received unknown opcode.", __func__);
|
||||
|
||||
}
|
||||
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: SNA data length: %d bytes.", __func__, ntohs(packet->len));
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Packet type: 0x%x", __func__, ntohs(packet->type));
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Reserved space: 0x%x", __func__, ntohs(packet->reserved));
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Variable header length: 0x%x.", __func__, packet->varlen);
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: SNA Flags: 0x%x", __func__, packet->flags);
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: SNA Rerved flags: 0x%x", __func__, packet->reserved_flags);
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: SNA Opcode: 0x%x", __func__, packet->opcode);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: WHOLE ENCHILADA: 0x%x", __func__, packet);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_WARNING, "%s: Everything else is unimplemented, now.", __func__);
|
||||
return 0;
|
||||
|
||||
}
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
* 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_LIB5250_H
|
||||
#define GUAC_LIB5250_H
|
||||
|
||||
#include "config.h"
|
||||
#include "tn5250.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* The General Data Stream SNA packet type.
|
||||
*/
|
||||
#define GUAC_LIB5250_SNA_GDS 0x12a0
|
||||
|
||||
/**
|
||||
* An enum that represents all of the available terminal types according to
|
||||
* RFC1205, the specification that documents the Telnet 5250 (TN5250)
|
||||
* standard.
|
||||
*/
|
||||
typedef enum guac_lib5250_terminal {
|
||||
|
||||
/* 24 x 80 Double-Byte Character Set color display */
|
||||
GUAC_LIB5250_TERMINAL_IBM_5555_C01,
|
||||
|
||||
/* 24 x 80 Double-Byte Character Set (DBCS) */
|
||||
GUAC_LIB5250_TERMINAL_IBM_5555_B01,
|
||||
|
||||
/* 27 x 132 color display */
|
||||
GUAC_LIB5250_TERMINAL_IBM_3477_FC,
|
||||
|
||||
/* 27 x 132 monochrome display */
|
||||
GUAC_LIB5250_TERMINAL_IBM_3477_FG,
|
||||
|
||||
/* 27 x 132 monochrome display */
|
||||
GUAC_LIB5250_TERMINAL_IBM_3180_2,
|
||||
|
||||
/* 24 x 80 color display */
|
||||
GUAC_LIB5250_TERMINAL_IBM_3179_2,
|
||||
|
||||
/* 24 x 80 monochrome display */
|
||||
GUAC_LIB5250_TERMINAL_IBM_3196_A1,
|
||||
|
||||
/* 24 x 80 color display */
|
||||
GUAC_LIB5250_TERMINAL_IBM_5292_2,
|
||||
|
||||
/* 24 x 80 monochrome display */
|
||||
GUAC_LIB5250_TERMINAL_IBM_5291_1,
|
||||
|
||||
/* 24 x 80 monochrome display */
|
||||
GUAC_LIB5250_TERMINAL_IBM_5251_11
|
||||
|
||||
} guac_lib5250_terminal;
|
||||
|
||||
/**
|
||||
* A data type that captures a terminal type, from the guac_lib5250_terminal
|
||||
* enum, and the capabilities associated with that terminal.
|
||||
*/
|
||||
typedef struct guac_lib5250_terminal_cap {
|
||||
|
||||
/* The name of the terminal. */
|
||||
guac_lib5250_terminal name;
|
||||
|
||||
/* The number of rows supported on the terminal. */
|
||||
unsigned int rows;
|
||||
|
||||
/* The number of columns supports on the terminal. */
|
||||
unsigned int cols;
|
||||
|
||||
/* 1 if the terminal supports colors, 0 if it is monochrome. */
|
||||
unsigned int color;
|
||||
|
||||
/* The number of bytes-per-character the terminal supports. This must
|
||||
* be either 1 or 2. */
|
||||
unsigned int charbytes;
|
||||
|
||||
} guac_lib5250_terminal_cap;
|
||||
|
||||
/**
|
||||
* A list of the possible TN5250 opcodes, which can be sent to the client to
|
||||
* direct it to do something with the terminal. These are documented in RFC1205.
|
||||
*/
|
||||
typedef enum guac_lib5250_opcode {
|
||||
|
||||
/* No Operation */
|
||||
GUAC_LIB5250_OPCODE_NOOP = 0x00,
|
||||
|
||||
/* Invite terminal */
|
||||
GUAC_LIB5250_OPCODE_INVITE = 0x01,
|
||||
|
||||
/* Output only */
|
||||
GUAC_LIB5250_OPCODE_OUTPUT = 0x02,
|
||||
|
||||
/* Put/Get */
|
||||
GUAC_LIB5250_OPCODE_PUTGET = 0x03,
|
||||
|
||||
/* Save screen */
|
||||
GUAC_LIB5250_OPCODE_SAVESCREEN = 0x04,
|
||||
|
||||
/* Restore screen */
|
||||
GUAC_LIB5250_OPCODE_RESTORESCREEN = 0x05,
|
||||
|
||||
/* Read immediate */
|
||||
GUAC_LIB5250_OPCODE_READIMMEDIATE = 0x06,
|
||||
|
||||
/* Read screen */
|
||||
GUAC_LIB5250_OPCODE_READSCREEN = 0x08,
|
||||
|
||||
/* Cancel invite */
|
||||
GUAC_LIB5250_OPCODE_CANCELINVITE = 0x0A,
|
||||
|
||||
/* Message light on */
|
||||
GUAC_LIB5250_OPCODE_MSGON = 0x0B,
|
||||
|
||||
/* Message light off */
|
||||
GUAC_LIB5250_OPCODE_MSGOFF = 0x0C
|
||||
|
||||
} guac_lib5250_opcode;
|
||||
|
||||
/**
|
||||
* A data type that defines the structure of the packet for 5250 communication
|
||||
* across telnet. The structure of this packet is based off of the definition
|
||||
* in RFC1205.
|
||||
*/
|
||||
typedef struct guac_lib5250_packet {
|
||||
|
||||
/* The length of the entire logical record. */
|
||||
uint16_t len;
|
||||
|
||||
/* The SNA record type. This should always be 0x12A0, which is the
|
||||
* General Data Stream record. */
|
||||
uint16_t type;
|
||||
|
||||
/* Empty space, should be zerod. */
|
||||
uint16_t reserved;
|
||||
|
||||
/* The length of the variable portion of the header, in octets. According
|
||||
* to the RFC, this should always be 0x04. */
|
||||
uint8_t varlen;
|
||||
|
||||
/* Flags associated with the header, as documented in the RFC. The
|
||||
* bits are as follows:
|
||||
* Bit 0: ERR - Data stream output error.
|
||||
* Bit 1: ATN - Indicates Attention key was pressed.
|
||||
* Bit 2-4: Reserved, zeros.
|
||||
* Bit 5: SRQ - System Request key has been pressed.
|
||||
* Bit 6: TRQ - Test Request key has been pressed.
|
||||
* Bit 7: HLP - Help in Error State, with actual help code sent as data after
|
||||
* the header.
|
||||
*/
|
||||
uint8_t flags;
|
||||
|
||||
/* At present, the remaining 8 bits of flags are not used at all. As old
|
||||
* as RFC1205 is, I doubt that's likely to change. These bits should be
|
||||
* all zeroes.
|
||||
*/
|
||||
uint8_t reserved_flags;
|
||||
|
||||
/* The operation code, as requested by the sender. Valid values for this
|
||||
* are in the gauc_lib5250_opcode enum.
|
||||
*/
|
||||
uint8_t opcode;
|
||||
|
||||
/* What remains is the data in the packet, which should consume the
|
||||
* remainder of the space that the header did not take up. The packet
|
||||
* should also be terminated with a Telnet IAC EOR record, 0xffef.
|
||||
*/
|
||||
void* data;
|
||||
|
||||
} guac_lib5250_packet __attribute__ ((aligned));
|
||||
|
||||
/**
|
||||
* Parses the packet that libtelnet has received and then takes action
|
||||
* based on the contents of the packet.
|
||||
*
|
||||
* @param data
|
||||
* The data buffer delivered by libtelnet, which should be binary telnet
|
||||
* data that is the actual TN5250 protocol.
|
||||
*
|
||||
* @param client
|
||||
* The Guacamole client associated with this connection.
|
||||
*
|
||||
* @return
|
||||
* Zero if the data was successfully processed, non-zero otherwise.
|
||||
*/
|
||||
int guac_lib5250_process_packet(const char* data, guac_client* client);
|
||||
|
||||
#endif // GUAC_LIB5250_H
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
}
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
|
@ -1,501 +0,0 @@
|
||||
/*
|
||||
* 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 "common/defaults.h"
|
||||
#include "settings.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
#include <guacamole/wol-constants.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",
|
||||
"username",
|
||||
"username-regex",
|
||||
"password",
|
||||
"password-regex",
|
||||
GUAC_TN5250_ARGV_FONT_NAME,
|
||||
GUAC_TN5250_ARGV_FONT_SIZE,
|
||||
GUAC_TN5250_ARGV_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",
|
||||
"login-success-regex",
|
||||
"login-failure-regex",
|
||||
"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,
|
||||
|
||||
/**
|
||||
* The name of the user to login as. Optional.
|
||||
*/
|
||||
IDX_USERNAME,
|
||||
|
||||
/**
|
||||
* The regular expression to use when searching for the username/login
|
||||
* prompt. Optional.
|
||||
*/
|
||||
IDX_USERNAME_REGEX,
|
||||
|
||||
/**
|
||||
* The password to use when logging in. Optional.
|
||||
*/
|
||||
IDX_PASSWORD,
|
||||
|
||||
/**
|
||||
* The regular expression to use when searching for the password prompt.
|
||||
* Optional.
|
||||
*/
|
||||
IDX_PASSWORD_REGEX,
|
||||
|
||||
/**
|
||||
* 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
|
||||
* GUAC_TERMINAL_DEFAULT_BACKSPACE 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,
|
||||
|
||||
/**
|
||||
* The regular expression to use when searching for whether login was
|
||||
* successful. This parameter is optional. If given, the
|
||||
* "login-failure-regex" parameter must also be specified, and the first
|
||||
* frame of the Guacamole connection will be withheld until login
|
||||
* success/failure has been determined.
|
||||
*/
|
||||
IDX_LOGIN_SUCCESS_REGEX,
|
||||
|
||||
/**
|
||||
* The regular expression to use when searching for whether login was
|
||||
* unsuccessful. This parameter is optional. If given, the
|
||||
* "login-success-regex" parameter must also be specified, and the first
|
||||
* frame of the Guacamole connection will be withheld until login
|
||||
* success/failure has been determined.
|
||||
*/
|
||||
IDX_LOGIN_FAILURE_REGEX,
|
||||
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
|
||||
/**
|
||||
* 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_tn5250_regex_free().
|
||||
*
|
||||
* @param user
|
||||
* The user who provided the setting associated with the given regex
|
||||
* pattern. Error messages will be logged on behalf of this user.
|
||||
*
|
||||
* @param pattern
|
||||
* The regular expression pattern to compile.
|
||||
*
|
||||
* @return
|
||||
* The compiled regular expression, or NULL if compilation fails or NULL
|
||||
* was originally provided for the pattern.
|
||||
*/
|
||||
static regex_t* guac_tn5250_compile_regex(guac_user* user, char* pattern) {
|
||||
|
||||
/* Nothing to compile if no pattern provided */
|
||||
if (pattern == NULL)
|
||||
return NULL;
|
||||
|
||||
int compile_result;
|
||||
regex_t* regex = malloc(sizeof(regex_t));
|
||||
|
||||
/* Compile regular expression */
|
||||
compile_result = regcomp(regex, pattern,
|
||||
REG_EXTENDED | REG_NOSUB | REG_ICASE | REG_NEWLINE);
|
||||
|
||||
/* Notify of failure to parse/compile */
|
||||
if (compile_result != 0) {
|
||||
guac_user_log(user, GUAC_LOG_ERROR, "Regular expression '%s' "
|
||||
"could not be compiled.", pattern);
|
||||
free(regex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return regex;
|
||||
}
|
||||
|
||||
void guac_tn5250_regex_free(regex_t** regex) {
|
||||
if (*regex != NULL) {
|
||||
regfree(*regex);
|
||||
free(*regex);
|
||||
*regex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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 parameters */
|
||||
settings->hostname =
|
||||
guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_HOSTNAME, "");
|
||||
|
||||
/* Read username */
|
||||
settings->username =
|
||||
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_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_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_PASSWORD, NULL);
|
||||
|
||||
/* Read password regex only if password is specified */
|
||||
if (settings->password != NULL) {
|
||||
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_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_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_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_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_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_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_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_TERMINAL_DEFAULT_MAX_SCROLLBACK);
|
||||
|
||||
/* Read font name */
|
||||
settings->font_name =
|
||||
guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_FONT_NAME, GUAC_TERMINAL_DEFAULT_FONT_NAME);
|
||||
|
||||
/* Read font size */
|
||||
settings->font_size =
|
||||
guac_user_parse_args_int(user, GUAC_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_FONT_SIZE, GUAC_TERMINAL_DEFAULT_FONT_SIZE);
|
||||
|
||||
/* Copy requested color scheme */
|
||||
settings->color_scheme =
|
||||
guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_COLOR_SCHEME, GUAC_TERMINAL_DEFAULT_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 port */
|
||||
settings->port =
|
||||
guac_user_parse_args_string(user, GUAC_TN5250_CLIENT_ARGS, argv,
|
||||
IDX_PORT, GUAC_TN5250_DEFAULT_PORT);
|
||||
|
||||
/* 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, GUAC_TERMINAL_DEFAULT_BACKSPACE);
|
||||
|
||||
/* Read terminal emulator type. */
|
||||
settings->terminal_type =
|
||||
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_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 credentials */
|
||||
free(settings->username);
|
||||
free(settings->password);
|
||||
|
||||
/* Free various regexes */
|
||||
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);
|
||||
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);
|
||||
|
||||
}
|
||||
|
@ -1,321 +0,0 @@
|
||||
/*
|
||||
* 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 port to connect to when initiating any tn5250 connection, if no other
|
||||
* port is specified.
|
||||
*/
|
||||
#define GUAC_TN5250_DEFAULT_PORT "23"
|
||||
|
||||
/**
|
||||
* 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 regular expression to use when searching for the username/login prompt
|
||||
* if no other regular expression is specified.
|
||||
*/
|
||||
#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_TN5250_DEFAULT_PASSWORD_REGEX "[Pp]assword:"
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The name of the user to login as, if any. If no username is specified,
|
||||
* this will be NULL.
|
||||
*/
|
||||
char* username;
|
||||
|
||||
/**
|
||||
* The regular expression to use when searching for the username/login
|
||||
* prompt. If no username is specified, this will be NULL. If a username
|
||||
* is specified, this will either be the specified username regex, or the
|
||||
* default username regex.
|
||||
*/
|
||||
regex_t* username_regex;
|
||||
|
||||
/**
|
||||
* The password to give when authenticating, if any. If no password is
|
||||
* specified, this will be NULL.
|
||||
*/
|
||||
char* password;
|
||||
|
||||
/**
|
||||
* The regular expression to use when searching for the password prompt. If
|
||||
* no password is specified, this will be NULL. If a password is specified,
|
||||
* this will either be the specified password regex, or the default
|
||||
* password regex.
|
||||
*/
|
||||
regex_t* password_regex;
|
||||
|
||||
/**
|
||||
* The regular expression to use when searching for whether login was
|
||||
* successful. If no such regex is specified, or if no login failure regex
|
||||
* was specified, this will be NULL.
|
||||
*/
|
||||
regex_t* login_success_regex;
|
||||
|
||||
/**
|
||||
* The regular expression to use when searching for whether login failed.
|
||||
* If no such regex is specified, or if no login success regex was
|
||||
* specified, this will be NULL.
|
||||
*/
|
||||
regex_t* login_failure_regex;
|
||||
|
||||
/**
|
||||
* 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 tn5250 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.
|
||||
*/
|
||||
char* terminal_type;
|
||||
|
||||
/**
|
||||
* Whether or not to send the magic Wake-on-LAN (WoL) packet prior to
|
||||
* continuing the connection.
|
||||
*/
|
||||
bool wol_send_packet;
|
||||
|
||||
/**
|
||||
* The MAC address to put in the magic WoL packet for the remote host to
|
||||
* wake.
|
||||
*/
|
||||
char* wol_mac_addr;
|
||||
|
||||
/**
|
||||
* The broadcast address to which to send the magic WoL packet to wake
|
||||
* the remote host.
|
||||
*/
|
||||
char* wol_broadcast_addr;
|
||||
|
||||
/**
|
||||
* The UDP port to use when sending the WoL packet.
|
||||
*/
|
||||
unsigned short wol_udp_port;
|
||||
|
||||
/**
|
||||
* The number of seconds to wait after sending the magic WoL packet before
|
||||
* continuing the connection.
|
||||
*/
|
||||
int wol_wait_time;
|
||||
|
||||
} 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
|
||||
|
@ -1,770 +0,0 @@
|
||||
/*
|
||||
* 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 "lib5250/lib5250.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/recording.h>
|
||||
#include <guacamole/timestamp.h>
|
||||
#include <guacamole/wol.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. According to RFC1205,
|
||||
* support for BINARY, TERMINAL TYPE (TTYPE), and END OF RECORD (EOR) must be
|
||||
* enabled for TN5250 to operate. TERMINAL is only supported
|
||||
* client-side (WILL), while BINARY and END OF RECORD should be agreed upon
|
||||
* between client and server.
|
||||
*/
|
||||
static const telnet_telopt_t __telnet_options[] = {
|
||||
{ TELNET_TELOPT_BINARY, TELNET_WILL, TELNET_DO },
|
||||
{ TELNET_TELOPT_ECHO, TELNET_WONT, TELNET_DO },
|
||||
{ TELNET_TELOPT_EOR, TELNET_WILL, TELNET_DO },
|
||||
{ TELNET_TELOPT_TTYPE, TELNET_WILL, TELNET_DONT },
|
||||
{ TELNET_TELOPT_NEW_ENVIRON, TELNET_WILL, TELNET_DONT },
|
||||
{ -1, 0, 0 }
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 if 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.
|
||||
*
|
||||
* @return
|
||||
* Return a value equal to the buffer's size on success, or a value not
|
||||
* equal to the buffer's size or a negative value on failure.
|
||||
*/
|
||||
static int __guac_tn5250_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, contine with what data remains (if any) */
|
||||
remaining -= ret_val;
|
||||
buffer += ret_val;
|
||||
|
||||
}
|
||||
|
||||
return size;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the given line against the given regex, returning true and sending
|
||||
* the given value if a match is found. An enter keypress is automatically
|
||||
* sent after the value is sent.
|
||||
*
|
||||
* @param client
|
||||
* 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 tn5250 session if a
|
||||
* match is found, or NULL if no value should be sent.
|
||||
*
|
||||
* @param line_buffer
|
||||
* The line of character data to test.
|
||||
*
|
||||
* @return
|
||||
* true if a match is found, false otherwise.
|
||||
*/
|
||||
static bool guac_tn5250_regex_exec(guac_client* client, regex_t* regex,
|
||||
const char* value, const char* line_buffer) {
|
||||
|
||||
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(tn5250_client->term, value);
|
||||
guac_terminal_send_string(tn5250_client->term, "\x0D");
|
||||
}
|
||||
|
||||
/* Stop searching for prompt */
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the given line against the various stored regexes, automatically
|
||||
* sending the configured username, password, or reporting login
|
||||
* success/failure depending on context. If no search is in progress, either
|
||||
* because no regexes have been defined or because all applicable searches have
|
||||
* completed, this function has no effect.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with the tn5250 session.
|
||||
*
|
||||
* @param line_buffer
|
||||
* The line of character data to test.
|
||||
*/
|
||||
static void guac_tn5250_search_line(guac_client* client, const char* line_buffer) {
|
||||
|
||||
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_tn5250_regex_exec(client, settings->username_regex,
|
||||
settings->username, line_buffer)) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Username sent");
|
||||
guac_tn5250_regex_free(&settings->username_regex);
|
||||
}
|
||||
}
|
||||
|
||||
/* Continue search for password prompt */
|
||||
if (settings->password_regex != NULL) {
|
||||
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_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_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(tn5250_client->term);
|
||||
|
||||
/* Stop all searches */
|
||||
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_tn5250_regex_exec(client, settings->login_failure_regex,
|
||||
NULL, line_buffer)) {
|
||||
|
||||
/* Advise that login has failed and connection should be closed */
|
||||
guac_client_abort(client,
|
||||
GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
|
||||
"Login failed");
|
||||
|
||||
/* Stop all searches */
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a line matching the various stored regexes, automatically
|
||||
* sending the configured username, password, or reporting login
|
||||
* success/failure depending on context. If no search is in progress, either
|
||||
* because no regexes have been defined or because all applicable searches
|
||||
* have completed, this function has no effect.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with the tn5250 session.
|
||||
*
|
||||
* @param buffer
|
||||
* The buffer of received data to search through.
|
||||
*
|
||||
* @param size
|
||||
* The size of the given buffer, in bytes.
|
||||
*/
|
||||
static void guac_tn5250_search(guac_client* client, const char* buffer, int size) {
|
||||
|
||||
static char line_buffer[1024] = {0};
|
||||
static int length = 0;
|
||||
|
||||
/* Append all characters in buffer to current line */
|
||||
const char* current = buffer;
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
||||
char c = *(current++);
|
||||
|
||||
/* Attempt pattern match and clear buffer upon reading newline */
|
||||
if (c == '\n') {
|
||||
if (length > 0) {
|
||||
line_buffer[length] = '\0';
|
||||
guac_tn5250_search_line(client, line_buffer);
|
||||
length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append all non-newline characters to line buffer as long as space
|
||||
* remains */
|
||||
else if (length < sizeof(line_buffer) - 1)
|
||||
line_buffer[length++] = c;
|
||||
|
||||
}
|
||||
|
||||
/* Attempt pattern match if an unfinished line remains (may be a prompt) */
|
||||
if (length > 0) {
|
||||
line_buffer[length] = '\0';
|
||||
guac_tn5250_search_line(client, line_buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param tn5250
|
||||
* The telnet_t object associated with the event.
|
||||
*
|
||||
* @param event
|
||||
* The telnet_event_t that has fired.
|
||||
*
|
||||
* @param data
|
||||
* User data provided to the event.
|
||||
*/
|
||||
static void __guac_tn5250_event_handler(telnet_t* tn5250, 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_client_log(client, GUAC_LOG_TRACE,
|
||||
"%s: Received %d bytes of data from remote side.", __func__, event->data.size);
|
||||
if (tn5250_client->binary_mode) {
|
||||
guac_client_log(client, GUAC_LOG_TRACE,
|
||||
"%s: Receiving binary data, which will not go directly to the terminal.",
|
||||
__func__);
|
||||
if (guac_lib5250_process_packet(event->data.buffer, client)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
guac_client_log(client, GUAC_LOG_TRACE,
|
||||
"%s: Writing ASCII output directly to terminal.", __func__);
|
||||
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:
|
||||
guac_client_log(client, GUAC_LOG_TRACE,
|
||||
"%s: Sending %d bytes of data to remote side.", __func__, 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;
|
||||
|
||||
/* Remote feature enabled */
|
||||
case TELNET_EV_WILL:
|
||||
if (event->neg.telopt == TELNET_TELOPT_ECHO)
|
||||
tn5250_client->echo_enabled = 0; /* Disable local echo, as remote will echo */
|
||||
|
||||
if (event->neg.telopt == TELNET_TELOPT_EOR) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"%s: Received End of Record support from remote side.",
|
||||
__func__);
|
||||
}
|
||||
if (event->neg.telopt == TELNET_TELOPT_BINARY) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"%s: Received Binary support from remote side.",
|
||||
__func__);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Remote feature disabled */
|
||||
case TELNET_EV_WONT:
|
||||
if (event->neg.telopt == TELNET_TELOPT_ECHO)
|
||||
tn5250_client->echo_enabled = 1; /* Enable local echo, as remote won't echo */
|
||||
|
||||
/* END OF RECORD are require for TN5250 - stop if remote
|
||||
* side does not support it. */
|
||||
if (event->neg.telopt == TELNET_TELOPT_EOR) {
|
||||
guac_client_log(client, GUAC_LOG_ERROR, "%s: Unexpected lack of "
|
||||
" END OF RECORD support on the remote side.", __func__);
|
||||
guac_client_stop(client);
|
||||
|
||||
}
|
||||
|
||||
if (event->neg.telopt == TELNET_TELOPT_BINARY) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "%s: End of binary data.",
|
||||
__func__);
|
||||
tn5250_client->binary_mode = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Local feature enable */
|
||||
case TELNET_EV_DO:
|
||||
if (event->neg.telopt == TELNET_TELOPT_EOR)
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"%s: Local EOR support enabled.",
|
||||
__func__);
|
||||
|
||||
/* Sending a DO BINARY means the next data we receive from the
|
||||
* server should be binary data. */
|
||||
if (event->neg.telopt == TELNET_TELOPT_BINARY) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"%s: Local BINARY support enabled, "
|
||||
"expecting next data to be binary.",
|
||||
__func__);
|
||||
tn5250_client->binary_mode = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Terminal type request */
|
||||
case TELNET_EV_TTYPE:
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"%s: Received TERMINAL TYPE request from the remote side.", __func__);
|
||||
if (event->ttype.cmd == TELNET_TTYPE_SEND) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"%s: Sending terminal type \"%s\" to remote side.", __func__, settings->terminal_type);
|
||||
|
||||
/* Apparently sending the TERMINAL TYPE to an IBMi system over
|
||||
* telnet requires both sending the TERM environment variable
|
||||
* and responding to the actual telnet TTYPE inquiry. */
|
||||
telnet_begin_newenviron(tn5250, TELNET_ENVIRON_IS);
|
||||
telnet_newenviron_value(tn5250, TELNET_ENVIRON_VAR, "TERM");
|
||||
telnet_newenviron_value(tn5250, TELNET_ENVIRON_VALUE, settings->terminal_type);
|
||||
telnet_finish_sb(tn5250);
|
||||
telnet_ttype_is(tn5250_client->tn5250, settings->terminal_type);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Environment request */
|
||||
case TELNET_EV_ENVIRON:
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"%s: Received environment request from the remote side.",
|
||||
__func__);
|
||||
/* Only send USER if entire environment was requested */
|
||||
if (event->environ.size == 0) {
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Sending username to remote server: %s", __func__, settings->username);
|
||||
guac_tn5250_send_user(tn5250, settings->username);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* Generic IAC received */
|
||||
case TELNET_EV_IAC:
|
||||
if (event->iac.cmd == TELNET_EOR) {
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "%s: Receive END OF RECORD from remote side.", __func__);
|
||||
break;
|
||||
}
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"%s: Received generic IAC data: 0x%x",
|
||||
__func__, event->iac.cmd);
|
||||
break;
|
||||
|
||||
/* For subnegotiation, we need to break and let the libtelnet internals
|
||||
* finish handling the request. */
|
||||
case TELNET_EV_SUBNEGOTIATION:
|
||||
guac_client_log(client, GUAC_LOG_TRACE,
|
||||
"%s: Received subnegotiation, sending on to libtelnet.",
|
||||
__func__);
|
||||
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:
|
||||
guac_client_log(client, GUAC_LOG_WARNING,
|
||||
"%s: Unknown or unsupported telnet command received: 0x%x",
|
||||
__func__, event->type);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Input thread, started by the main tn5250 client thread. This thread
|
||||
* continuously reads from the terminal's STDIN and transfers all read
|
||||
* data to the tn5250 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->tn5250, buffer, bytes_read);
|
||||
if (tn5250_client->echo_enabled)
|
||||
guac_terminal_write(tn5250_client->term, buffer, bytes_read);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the tn5250 server specified within the data associated
|
||||
* with the given guac_client, which will have been populated by
|
||||
* guac_client_init.
|
||||
*
|
||||
* @return
|
||||
* The connected tn5250 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 tn5250 session */
|
||||
telnet_t* tn5250 = telnet_init(__telnet_options, __guac_tn5250_event_handler, 0, client);
|
||||
if (tn5250 == 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 tn5250;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a 16-bit value over the given tn5250 connection with the byte order
|
||||
* required by the tn5250 protocol.
|
||||
*
|
||||
* @param tn5250
|
||||
* The tn5250 connection to use.
|
||||
*
|
||||
* @param value
|
||||
* The value to send.
|
||||
*/
|
||||
/*
|
||||
static void __guac_tn5250_send_uint16(telnet_t* tn5250, uint16_t value) {
|
||||
|
||||
unsigned char buffer[2];
|
||||
buffer[0] = (value >> 8) & 0xFF;
|
||||
buffer[1] = value & 0xFF;
|
||||
|
||||
telnet_send(tn5250, (char*) buffer, 2);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sends an 8-bit value over the given tn5250 connection.
|
||||
*
|
||||
* @param tn5250
|
||||
* The tn5250 connection to use.
|
||||
*
|
||||
* @param value
|
||||
* The value to send.
|
||||
*/
|
||||
/*
|
||||
static void __guac_tn5250_send_uint8(telnet_t* tn5250, uint8_t value) {
|
||||
telnet_send(tn5250, (char*) (&value), 1);
|
||||
}
|
||||
*/
|
||||
|
||||
void guac_tn5250_send_user(telnet_t* tn5250, const char* username) {
|
||||
|
||||
/* IAC SB NEW-ENVIRON IS */
|
||||
telnet_begin_newenviron(tn5250, TELNET_ENVIRON_IS);
|
||||
|
||||
/* Only send username if defined */
|
||||
if (username != NULL) {
|
||||
|
||||
telnet_newenviron_value(tn5250, TELNET_ENVIRON_VAR, "USER");
|
||||
telnet_newenviron_value(tn5250, TELNET_ENVIRON_VALUE, username);
|
||||
|
||||
}
|
||||
|
||||
/* IAC SB */
|
||||
telnet_finish_sb(tn5250);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_recording_create(client,
|
||||
settings->recording_path,
|
||||
settings->recording_name,
|
||||
settings->create_recording_path,
|
||||
!settings->recording_exclude_output,
|
||||
!settings->recording_exclude_mouse,
|
||||
0, /* Touch events not supported */
|
||||
settings->recording_include_keys);
|
||||
}
|
||||
|
||||
/* Create terminal options with required parameters */
|
||||
guac_terminal_options* options = guac_terminal_options_create(
|
||||
settings->width, settings->height, settings->resolution);
|
||||
|
||||
/* Set optional parameters */
|
||||
options->disable_copy = settings->disable_copy;
|
||||
options->max_scrollback = settings->max_scrollback;
|
||||
options->font_name = settings->font_name;
|
||||
options->font_size = settings->font_size;
|
||||
options->color_scheme = settings->color_scheme;
|
||||
options->backspace = settings->backspace;
|
||||
|
||||
/* Create terminal */
|
||||
tn5250_client->term = guac_terminal_create(client, options);
|
||||
|
||||
/* Free options struct now that it's been used */
|
||||
free(options);
|
||||
|
||||
/* Fail if terminal init failed */
|
||||
if (tn5250_client->term == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Terminal initialization failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Send current values of exposed arguments to owner only */
|
||||
guac_client_for_owner(client, guac_tn5250_send_current_argv,
|
||||
tn5250_client);
|
||||
|
||||
/* 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 tn5250 session */
|
||||
tn5250_client->tn5250 = __guac_tn5250_create_session(client);
|
||||
if (tn5250_client->tn5250 == NULL) {
|
||||
/* Already aborted within __guac_tn5250_create_session() */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Logged in */
|
||||
guac_client_log(client, GUAC_LOG_INFO, "Telnet 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(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->tn5250, 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, "Telnet connection ended.");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* 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 "settings.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
#include <guacamole/recording.h>
|
||||
#include <libtelnet.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* TN5250-specific client data.
|
||||
*/
|
||||
typedef struct guac_tn5250_client {
|
||||
|
||||
/**
|
||||
* Telnet 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;
|
||||
|
||||
/**
|
||||
* TN5250 connection, used by the telnet client thread.
|
||||
*/
|
||||
telnet_t* tn5250;
|
||||
|
||||
/**
|
||||
* Whether all user input should be automatically echoed to the
|
||||
* terminal.
|
||||
*/
|
||||
int echo_enabled;
|
||||
|
||||
/**
|
||||
* 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_recording* recording;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the TN5250 client is now in binary mode and
|
||||
* subsequent data should be binary.
|
||||
*/
|
||||
int binary_mode;
|
||||
|
||||
} guac_tn5250_client;
|
||||
|
||||
/**
|
||||
* Main tn5250 client thread, handling transfer of TN5250 output to STDOUT.
|
||||
*/
|
||||
void* guac_tn5250_client_thread(void* data);
|
||||
|
||||
/**
|
||||
* Sends the given username by setting the remote USER environment variable
|
||||
* using the telnet NEW-ENVIRON option.
|
||||
*/
|
||||
void guac_tn5250_send_user(telnet_t* tn5250, const char* username);
|
||||
|
||||
#endif
|
||||
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* 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_tn5250_send_current_argv(user, tn5250_client);
|
||||
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_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;
|
||||
|
||||
/* Remove the user from the terminal */
|
||||
guac_terminal_remove_user(tn5250_client->term, 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;
|
||||
}
|
||||
|
@ -77,6 +77,8 @@ libguac_terminal_la_LIBADD = \
|
||||
@LIBGUAC_LTLIB@
|
||||
|
||||
libguac_terminal_la_LDFLAGS = \
|
||||
-version-info 0:0:0 \
|
||||
-no-undefined \
|
||||
@CAIRO_LIBS@ \
|
||||
@MATH_LIBS@ \
|
||||
@PANGO_LIBS@ \
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "common/clipboard.h"
|
||||
#include "common/cursor.h"
|
||||
#include "common/iconv.h"
|
||||
#include "terminal/buffer.h"
|
||||
#include "terminal/color-scheme.h"
|
||||
#include "terminal/common.h"
|
||||
@ -936,14 +937,13 @@ void guac_terminal_commit_cursor(guac_terminal* term) {
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_write(guac_terminal* term, const char* c, int size) {
|
||||
int guac_terminal_write(guac_terminal* term, const char* buffer, int length) {
|
||||
|
||||
guac_terminal_lock(term);
|
||||
while (size > 0) {
|
||||
for (int written = 0; written < length; written++) {
|
||||
|
||||
/* Read and advance to next character */
|
||||
char current = *(c++);
|
||||
size--;
|
||||
char current = *(buffer++);
|
||||
|
||||
/* Write character to typescript, if any */
|
||||
if (term->typescript != NULL)
|
||||
@ -956,7 +956,7 @@ int guac_terminal_write(guac_terminal* term, const char* c, int size) {
|
||||
guac_terminal_unlock(term);
|
||||
|
||||
guac_terminal_notify(term);
|
||||
return 0;
|
||||
return length;
|
||||
|
||||
}
|
||||
|
||||
@ -2165,7 +2165,16 @@ void guac_terminal_clipboard_reset(guac_terminal* terminal,
|
||||
|
||||
void guac_terminal_clipboard_append(guac_terminal* terminal,
|
||||
const char* data, int length) {
|
||||
guac_common_clipboard_append(terminal->clipboard, data, length);
|
||||
|
||||
/* Allocate and clear space for the converted data */
|
||||
char output_data[GUAC_COMMON_CLIPBOARD_MAX_LENGTH];
|
||||
char* output = output_data;
|
||||
|
||||
/* Convert clipboard contents */
|
||||
guac_iconv(GUAC_READ_UTF8_NORMALIZED, &data, length,
|
||||
GUAC_WRITE_UTF8, &output, GUAC_COMMON_CLIPBOARD_MAX_LENGTH);
|
||||
|
||||
guac_common_clipboard_append(terminal->clipboard, output_data, output - output_data);
|
||||
}
|
||||
|
||||
void guac_terminal_remove_user(guac_terminal* terminal, guac_user* user) {
|
||||
|
@ -29,6 +29,22 @@
|
||||
#include "terminal.h"
|
||||
#include "typescript.h"
|
||||
|
||||
/**
|
||||
* Handler for characters printed to the terminal. When a character is printed,
|
||||
* the current char handler for the terminal is called and given that
|
||||
* character.
|
||||
*
|
||||
* @param term
|
||||
* The terminal receiving the character.
|
||||
*
|
||||
* @param c
|
||||
* The received character.
|
||||
*
|
||||
* @return
|
||||
* Zero if the character was handled successfully, non-zero otherwise.
|
||||
*/
|
||||
typedef int guac_terminal_char_handler(guac_terminal* term, unsigned char c);
|
||||
|
||||
struct guac_terminal {
|
||||
|
||||
/**
|
||||
|
@ -141,19 +141,35 @@ typedef enum guac_terminal_cursor_type {
|
||||
} guac_terminal_cursor_type;
|
||||
|
||||
/**
|
||||
* Handler for characters printed to the terminal. When a character is printed,
|
||||
* the current char handler for the terminal is called and given that
|
||||
* character.
|
||||
*/
|
||||
typedef int guac_terminal_char_handler(guac_terminal* term, unsigned char c);
|
||||
|
||||
/**
|
||||
* Handler for setting the destination path for file uploads.
|
||||
* Handler that is invoked whenever the necessary terminal codes are sent to
|
||||
* to the given terminal to change the path for future file uploads.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with the terminal receiving the upload path
|
||||
* change terminal code.
|
||||
*
|
||||
* @param path
|
||||
* The requested path.
|
||||
*/
|
||||
typedef void guac_terminal_upload_path_handler(guac_client* client, char* path);
|
||||
|
||||
/**
|
||||
* Handler for creating an outbound file download stream for a specified file.
|
||||
* Handler that is invoked whenever the necessary terminal codes are sent to
|
||||
* initiate a download of a given remote file.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with the terminal receiving the file download
|
||||
* terminal code.
|
||||
*
|
||||
* @param filename
|
||||
* The name of the requested file. This may be a relative or absolute path,
|
||||
* and it is up to the implementation to define how this value is
|
||||
* interpreted.
|
||||
*
|
||||
* @return
|
||||
* The file stream created for the file download, already configured to
|
||||
* properly handle "ack" responses, etc. from the client, or NULL if the
|
||||
* stream could not be created.
|
||||
*/
|
||||
typedef guac_stream* guac_terminal_file_download_handler(guac_client* client, char* filename);
|
||||
|
||||
@ -276,11 +292,16 @@ guac_terminal_options* guac_terminal_options_create(
|
||||
|
||||
/**
|
||||
* Frees all resources associated with the given terminal.
|
||||
*
|
||||
* @param term
|
||||
* The terminal to free.
|
||||
*/
|
||||
void guac_terminal_free(guac_terminal* term);
|
||||
|
||||
/**
|
||||
* Set the upload path handler for the given terminal.
|
||||
* Sets the upload path handler for the given terminal. The upload path handler
|
||||
* is invoked whenever the terminal codes requesting an upload path change are
|
||||
* sent.
|
||||
*
|
||||
* @param terminal
|
||||
* The terminal to set the upload path handler for.
|
||||
@ -293,12 +314,14 @@ void guac_terminal_set_upload_path_handler(guac_terminal* terminal,
|
||||
guac_terminal_upload_path_handler* upload_path_handler);
|
||||
|
||||
/**
|
||||
* Set the file download handler for the given terminal.
|
||||
* Sets the file download handler for the given terminal. The file download
|
||||
* handler is invoked whenever the terminal codes requesting download of a
|
||||
* given remote file are sent.
|
||||
*
|
||||
* @param terminal
|
||||
* The terminal to set the file download handler for.
|
||||
*
|
||||
* @param upload_path_handler
|
||||
* @param file_download_handler
|
||||
* The handler to be called whenever the necessary terminal codes are sent to
|
||||
* the given terminal to initiate a download of a given remote file.
|
||||
*/
|
||||
@ -308,6 +331,13 @@ void guac_terminal_set_file_download_handler(guac_terminal* terminal,
|
||||
/**
|
||||
* Renders a single frame of terminal data. If data is not yet available,
|
||||
* this function will block until data is written.
|
||||
*
|
||||
* @param terminal
|
||||
* The terminal that should be rendered.
|
||||
*
|
||||
* @return
|
||||
* Zero if the frame was rendered successfully, non-zero if an error
|
||||
* occurred.
|
||||
*/
|
||||
int guac_terminal_render_frame(guac_terminal* terminal);
|
||||
|
||||
@ -316,6 +346,19 @@ int guac_terminal_render_frame(guac_terminal* terminal);
|
||||
* supplied by calls to guac_terminal_send_key(),
|
||||
* guac_terminal_send_mouse(), and guac_terminal_send_stream(). If input is not
|
||||
* yet available, this function will block.
|
||||
*
|
||||
* @param terminal
|
||||
* The terminal to read from.
|
||||
*
|
||||
* @param c
|
||||
* The buffer that should receive the bytes read.
|
||||
*
|
||||
* @param size
|
||||
* The number of bytes available within the buffer.
|
||||
*
|
||||
* @return
|
||||
* The number of bytes read into the buffer, zero if end-of-file is reached
|
||||
* (STDIN has been closed), or a negative value if an error occurs.
|
||||
*/
|
||||
int guac_terminal_read_stdin(guac_terminal* terminal, char* c, int size);
|
||||
|
||||
@ -377,8 +420,23 @@ char* guac_terminal_prompt(guac_terminal* terminal, const char* title,
|
||||
|
||||
/**
|
||||
* Writes the given format string and arguments to this terminal's STDOUT in
|
||||
* the same manner as printf(). This function may block until space is
|
||||
* the same manner as printf(). The entire populated format string will always
|
||||
* be written unless an error occurs. This function may block until space is
|
||||
* freed in the output buffer by guac_terminal_render_frame().
|
||||
*
|
||||
* @param terminal
|
||||
* The terminal to write to.
|
||||
*
|
||||
* @param format
|
||||
* A printf-style format string describing the data to be written to
|
||||
* STDOUT.
|
||||
*
|
||||
* @param ...
|
||||
* Any arguments to use when filling the format string.
|
||||
*
|
||||
* @return
|
||||
* The number of bytes written to STDOUT, or a negative value if an error
|
||||
* occurs preventing the data from being written in its entirety.
|
||||
*/
|
||||
int guac_terminal_printf(guac_terminal* terminal, const char* format, ...);
|
||||
|
||||
@ -486,9 +544,24 @@ int guac_terminal_send_data(guac_terminal* term, const char* data, int length);
|
||||
int guac_terminal_send_string(guac_terminal* term, const char* data);
|
||||
|
||||
/**
|
||||
* Writes the given string of characters to the terminal.
|
||||
* Writes the given buffer to the given terminal's STDOUT. All requested bytes
|
||||
* will be written unless an error occurs. This function may block until space
|
||||
* is freed in the output buffer by guac_terminal_render_frame().
|
||||
*
|
||||
* @param term
|
||||
* The terminal to write to.
|
||||
*
|
||||
* @param buffer
|
||||
* A buffer containing the characters to be written to the terminal.
|
||||
*
|
||||
* @param length
|
||||
* The number of bytes within the given string to write to the terminal.
|
||||
*
|
||||
* @return
|
||||
* The number of bytes written to STDOUT, or a negative value if an error
|
||||
* occurs preventing the data from being written in its entirety.
|
||||
*/
|
||||
int guac_terminal_write(guac_terminal* term, const char* c, int size);
|
||||
int guac_terminal_write(guac_terminal* term, const char* buffer, int length);
|
||||
|
||||
/**
|
||||
* Initializes the handlers of the given guac_stream such that it serves as the
|
||||
@ -532,7 +605,7 @@ int guac_terminal_send_stream(guac_terminal* term, guac_user* user,
|
||||
* STDIN.
|
||||
*
|
||||
* @param ...
|
||||
* Any srguments to use when filling the format string.
|
||||
* Any arguments to use when filling the format string.
|
||||
*
|
||||
* @return
|
||||
* The number of bytes written to STDIN, or a negative value if an error
|
||||
@ -560,7 +633,20 @@ void guac_terminal_dup(guac_terminal* term, guac_user* user,
|
||||
guac_socket* socket);
|
||||
|
||||
/**
|
||||
* Resize the terminal to the given dimensions.
|
||||
* Resize the client display and terminal to the given pixel dimensions.
|
||||
*
|
||||
* @param term
|
||||
* The terminal to resize.
|
||||
*
|
||||
* @param width
|
||||
* The new terminal width, in pixels.
|
||||
*
|
||||
* @param height
|
||||
* The new terminal height, in pixels.
|
||||
*
|
||||
* @return
|
||||
* Zero if the terminal was successfully resized to the given dimensions,
|
||||
* non-zero otherwise.
|
||||
*/
|
||||
int guac_terminal_resize(guac_terminal* term, int width, int height);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user