Compare commits
1 Commits
master
...
working/re
Author | SHA1 | Date | |
---|---|---|---|
|
36b46e63c2 |
@ -56,5 +56,5 @@ tests/test_*
|
|||||||
!tests/test_*.[ch]
|
!tests/test_*.[ch]
|
||||||
|
|
||||||
# Generated docs
|
# Generated docs
|
||||||
doc/*/doxygen-output
|
doc/doxygen-output
|
||||||
|
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -44,7 +44,7 @@ configure
|
|||||||
stamp-h1
|
stamp-h1
|
||||||
|
|
||||||
# Generated docs
|
# Generated docs
|
||||||
doc/*/doxygen-output
|
doc/doxygen-output
|
||||||
|
|
||||||
# IDE metadata
|
# IDE metadata
|
||||||
nbproject/
|
nbproject/
|
||||||
|
207
Dockerfile
207
Dockerfile
@ -21,32 +21,25 @@
|
|||||||
# Dockerfile for guacamole-server
|
# Dockerfile for guacamole-server
|
||||||
#
|
#
|
||||||
|
|
||||||
# The Alpine Linux image that should be used as the basis for the guacd image
|
# The Debian image that should be used as the basis for the guacd image
|
||||||
ARG ALPINE_BASE_IMAGE=latest
|
ARG DEBIAN_BASE_IMAGE=buster-slim
|
||||||
FROM alpine:${ALPINE_BASE_IMAGE} AS builder
|
|
||||||
|
|
||||||
# Install build dependencies
|
# Use Debian as base for the build
|
||||||
RUN apk add --no-cache \
|
FROM debian:${DEBIAN_BASE_IMAGE} AS builder
|
||||||
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
|
|
||||||
|
|
||||||
# Copy source to container for sake of build
|
#
|
||||||
ARG BUILD_DIR=/tmp/guacamole-server
|
# The Debian repository that should be preferred for dependencies (this will be
|
||||||
COPY . ${BUILD_DIR}
|
# 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 DEBIAN_RELEASE=buster-backports
|
||||||
|
|
||||||
|
# Add repository for specified Debian release if not already present in
|
||||||
|
# sources.list
|
||||||
|
RUN grep " ${DEBIAN_RELEASE} " /etc/apt/sources.list || echo >> /etc/apt/sources.list \
|
||||||
|
"deb http://deb.debian.org/debian ${DEBIAN_RELEASE} main contrib non-free"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Base directory for installed build artifacts.
|
# Base directory for installed build artifacts.
|
||||||
@ -54,99 +47,70 @@ COPY . ${BUILD_DIR}
|
|||||||
# NOTE: Due to limitations of the Docker image build process, this value is
|
# NOTE: Due to limitations of the Docker image build process, this value is
|
||||||
# duplicated in an ARG in the second stage of the build.
|
# duplicated in an ARG in the second stage of the build.
|
||||||
#
|
#
|
||||||
ARG PREFIX_DIR=/opt/guacamole
|
ARG PREFIX_DIR=/usr/local/guacamole
|
||||||
|
|
||||||
#
|
# Build arguments
|
||||||
# Automatically select the latest versions of each core protocol support
|
ARG BUILD_DIR=/tmp/guacd-docker-BUILD
|
||||||
# library (these can be overridden at build time if a specific version is
|
ARG BUILD_DEPENDENCIES=" \
|
||||||
# needed)
|
autoconf \
|
||||||
#
|
automake \
|
||||||
ARG WITH_FREERDP='2(\.\d+)+'
|
freerdp2-dev \
|
||||||
ARG WITH_LIBSSH2='libssh2-\d+(\.\d+)+'
|
gcc \
|
||||||
ARG WITH_LIBTELNET='\d+(\.\d+)+'
|
libcairo2-dev \
|
||||||
ARG WITH_LIBVNCCLIENT='LibVNCServer-\d+(\.\d+)+'
|
libgcrypt-dev \
|
||||||
ARG WITH_LIBWEBSOCKETS='v\d+(\.\d+)+'
|
libjpeg62-turbo-dev \
|
||||||
|
libossp-uuid-dev \
|
||||||
|
libpango1.0-dev \
|
||||||
|
libpulse-dev \
|
||||||
|
libssh2-1-dev \
|
||||||
|
libssl-dev \
|
||||||
|
libtelnet-dev \
|
||||||
|
libtool \
|
||||||
|
libvncserver-dev \
|
||||||
|
libwebsockets-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
make"
|
||||||
|
|
||||||
#
|
# Do not require interaction during build
|
||||||
# Default build options for each core protocol support library, as well as
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
# guacamole-server itself (these can be overridden at build time if different
|
|
||||||
# options are needed)
|
|
||||||
#
|
|
||||||
|
|
||||||
ARG FREERDP_OPTS="\
|
# Bring build environment up to date and install build dependencies
|
||||||
-DBUILTIN_CHANNELS=OFF \
|
RUN apt-get update && \
|
||||||
-DCHANNEL_URBDRC=OFF \
|
apt-get install -t ${DEBIAN_RELEASE} -y $BUILD_DEPENDENCIES && \
|
||||||
-DWITH_ALSA=OFF \
|
rm -rf /var/lib/apt/lists/*
|
||||||
-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"
|
|
||||||
|
|
||||||
ARG GUACAMOLE_SERVER_OPTS="\
|
# Add configuration scripts
|
||||||
--disable-guaclog"
|
COPY src/guacd-docker/bin "${PREFIX_DIR}/bin/"
|
||||||
|
|
||||||
ARG LIBSSH2_OPTS="\
|
# Copy source to container for sake of build
|
||||||
-DBUILD_EXAMPLES=OFF \
|
COPY . "$BUILD_DIR"
|
||||||
-DBUILD_SHARED_LIBS=ON"
|
|
||||||
|
|
||||||
ARG LIBTELNET_OPTS="\
|
# Build guacamole-server from local source
|
||||||
--disable-static \
|
RUN ${PREFIX_DIR}/bin/build-guacd.sh "$BUILD_DIR" "$PREFIX_DIR"
|
||||||
--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
|
# Record the packages of all runtime library dependencies
|
||||||
RUN ${BUILD_DIR}/src/guacd-docker/bin/list-dependencies.sh \
|
RUN ${PREFIX_DIR}/bin/list-dependencies.sh \
|
||||||
${PREFIX_DIR}/sbin/guacd \
|
${PREFIX_DIR}/sbin/guacd \
|
||||||
${PREFIX_DIR}/lib/libguac-client-*.so \
|
${PREFIX_DIR}/lib/libguac-client-*.so \
|
||||||
${PREFIX_DIR}/lib/freerdp2/*guac*.so \
|
${PREFIX_DIR}/lib/freerdp2/*guac*.so \
|
||||||
> ${PREFIX_DIR}/DEPENDENCIES
|
> ${PREFIX_DIR}/DEPENDENCIES
|
||||||
|
|
||||||
# Use same Alpine version as the base for the runtime image
|
# Use same Debian as the base for the runtime image
|
||||||
FROM alpine:${ALPINE_BASE_IMAGE}
|
FROM debian:${DEBIAN_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 DEBIAN_RELEASE=buster-backports
|
||||||
|
|
||||||
|
# Add repository for specified Debian release if not already present in
|
||||||
|
# sources.list
|
||||||
|
RUN grep " ${DEBIAN_RELEASE} " /etc/apt/sources.list || echo >> /etc/apt/sources.list \
|
||||||
|
"deb http://deb.debian.org/debian ${DEBIAN_RELEASE} main contrib non-free"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Base directory for installed build artifacts. See also the
|
# Base directory for installed build artifacts. See also the
|
||||||
@ -155,27 +119,36 @@ FROM alpine:${ALPINE_BASE_IMAGE}
|
|||||||
# NOTE: Due to limitations of the Docker image build process, this value is
|
# NOTE: Due to limitations of the Docker image build process, this value is
|
||||||
# duplicated in an ARG in the first stage of the build.
|
# duplicated in an ARG in the first stage of the build.
|
||||||
#
|
#
|
||||||
ARG PREFIX_DIR=/opt/guacamole
|
ARG PREFIX_DIR=/usr/local/guacamole
|
||||||
|
|
||||||
# Runtime environment
|
# Runtime environment
|
||||||
ENV LC_ALL=C.UTF-8
|
ENV LC_ALL=C.UTF-8
|
||||||
ENV LD_LIBRARY_PATH=${PREFIX_DIR}/lib
|
ENV LD_LIBRARY_PATH=${PREFIX_DIR}/lib
|
||||||
ENV GUACD_LOG_LEVEL=info
|
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 build artifacts into this stage
|
||||||
COPY --from=builder ${PREFIX_DIR} ${PREFIX_DIR}
|
COPY --from=builder ${PREFIX_DIR} ${PREFIX_DIR}
|
||||||
|
|
||||||
# Bring runtime environment up to date and install runtime dependencies
|
# Bring runtime environment up to date and install runtime dependencies
|
||||||
RUN apk add --no-cache \
|
RUN apt-get update && \
|
||||||
ca-certificates \
|
apt-get install -t ${DEBIAN_RELEASE} -y --no-install-recommends $RUNTIME_DEPENDENCIES && \
|
||||||
ghostscript \
|
apt-get install -t ${DEBIAN_RELEASE} -y --no-install-recommends $(cat "${PREFIX_DIR}"/DEPENDENCIES) && \
|
||||||
netcat-openbsd \
|
rm -rf /var/lib/apt/lists/*
|
||||||
shadow \
|
|
||||||
terminus-font \
|
# Link FreeRDP plugins into proper path
|
||||||
ttf-dejavu \
|
RUN ${PREFIX_DIR}/bin/link-freerdp-plugins.sh \
|
||||||
ttf-liberation \
|
${PREFIX_DIR}/lib/freerdp2/libguac*.so
|
||||||
util-linux-login && \
|
|
||||||
xargs apk add --no-cache < ${PREFIX_DIR}/DEPENDENCIES
|
|
||||||
|
|
||||||
# Checks the operating status every 5 minutes with a timeout of 5 seconds
|
# 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
|
HEALTHCHECK --interval=5m --timeout=5s CMD nc -z 127.0.0.1 4822 || exit 1
|
||||||
@ -184,7 +157,7 @@ HEALTHCHECK --interval=5m --timeout=5s CMD nc -z 127.0.0.1 4822 || exit 1
|
|||||||
ARG UID=1000
|
ARG UID=1000
|
||||||
ARG GID=1000
|
ARG GID=1000
|
||||||
RUN groupadd --gid $GID guacd
|
RUN groupadd --gid $GID guacd
|
||||||
RUN useradd --system --create-home --shell /sbin/nologin --uid $UID --gid $GID guacd
|
RUN useradd --system --create-home --shell /usr/sbin/nologin --uid $UID --gid $GID guacd
|
||||||
|
|
||||||
# Run with user guacd
|
# Run with user guacd
|
||||||
USER guacd
|
USER guacd
|
||||||
@ -197,5 +170,5 @@ EXPOSE 4822
|
|||||||
# Note the path here MUST correspond to the value specified in the
|
# Note the path here MUST correspond to the value specified in the
|
||||||
# PREFIX_DIR build argument.
|
# PREFIX_DIR build argument.
|
||||||
#
|
#
|
||||||
CMD /opt/guacamole/sbin/guacd -b 0.0.0.0 -L $GUACD_LOG_LEVEL -f
|
CMD /usr/local/guacamole/sbin/guacd -b 0.0.0.0 -L $GUACD_LOG_LEVEL -f
|
||||||
|
|
||||||
|
19
Makefile.am
19
Makefile.am
@ -89,15 +89,14 @@ if ENABLE_GUACLOG
|
|||||||
SUBDIRS += src/guaclog
|
SUBDIRS += src/guaclog
|
||||||
endif
|
endif
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
.dockerignore \
|
.dockerignore \
|
||||||
CONTRIBUTING \
|
CONTRIBUTING \
|
||||||
Dockerfile \
|
Dockerfile \
|
||||||
LICENSE \
|
LICENSE \
|
||||||
NOTICE \
|
NOTICE \
|
||||||
bin/guacctl \
|
bin/guacctl \
|
||||||
doc/libguac/Doxyfile.in \
|
doc/Doxyfile.in \
|
||||||
doc/libguac-terminal/Doxyfile.in \
|
src/guacd-docker \
|
||||||
src/guacd-docker \
|
|
||||||
util/generate-test-runner.pl
|
util/generate-test-runner.pl
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ error() {
|
|||||||
##
|
##
|
||||||
usage() {
|
usage() {
|
||||||
cat >&2 <<END
|
cat >&2 <<END
|
||||||
guacctl 1.5.0, Apache Guacamole terminal session control utility.
|
guacctl 1.4.0, Apache Guacamole terminal session control utility.
|
||||||
Usage: guacctl [OPTION] [FILE or NAME]...
|
Usage: guacctl [OPTION] [FILE or NAME]...
|
||||||
|
|
||||||
-d, --download download each of the files listed.
|
-d, --download download each of the files listed.
|
||||||
|
38
configure.ac
38
configure.ac
@ -18,7 +18,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
AC_PREREQ([2.61])
|
AC_PREREQ([2.61])
|
||||||
AC_INIT([guacamole-server], [1.5.0])
|
AC_INIT([guacamole-server], [1.4.0])
|
||||||
AC_CONFIG_AUX_DIR([build-aux])
|
AC_CONFIG_AUX_DIR([build-aux])
|
||||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
|
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
@ -160,11 +160,6 @@ AC_CHECK_DECL([strlcat],
|
|||||||
[Whether strlcat() is defined])],,
|
[Whether strlcat() is defined])],,
|
||||||
[#include <string.h>])
|
[#include <string.h>])
|
||||||
|
|
||||||
AC_CHECK_DECL([strnstr],
|
|
||||||
[AC_DEFINE([HAVE_STRNSTR],,
|
|
||||||
[Whether strnstr() is defined])],,
|
|
||||||
[#include <string.h>])
|
|
||||||
|
|
||||||
# Typedefs
|
# Typedefs
|
||||||
AC_TYPE_SIZE_T
|
AC_TYPE_SIZE_T
|
||||||
AC_TYPE_SSIZE_T
|
AC_TYPE_SSIZE_T
|
||||||
@ -194,7 +189,7 @@ AC_SUBST([LIBGUAC_CLIENT_RDP_LTLIB], '$(top_builddir)/src/protocols/rdp/libgua
|
|||||||
AC_SUBST([LIBGUAC_CLIENT_RDP_INCLUDE], '-I$(top_srcdir)/src/protocols/rdp')
|
AC_SUBST([LIBGUAC_CLIENT_RDP_INCLUDE], '-I$(top_srcdir)/src/protocols/rdp')
|
||||||
|
|
||||||
# Terminal emulator
|
# Terminal emulator
|
||||||
AC_SUBST([TERMINAL_LTLIB], '$(top_builddir)/src/terminal/libguac-terminal.la')
|
AC_SUBST([TERMINAL_LTLIB], '$(top_builddir)/src/terminal/libguac_terminal.la')
|
||||||
AC_SUBST([TERMINAL_INCLUDE], '-I$(top_srcdir)/src/terminal $(PANGO_CFLAGS) $(PANGOCAIRO_CFLAGS) $(COMMON_INCLUDE)')
|
AC_SUBST([TERMINAL_INCLUDE], '-I$(top_srcdir)/src/terminal $(PANGO_CFLAGS) $(PANGOCAIRO_CFLAGS) $(COMMON_INCLUDE)')
|
||||||
|
|
||||||
# Init directory
|
# Init directory
|
||||||
@ -325,6 +320,30 @@ then
|
|||||||
else
|
else
|
||||||
AC_DEFINE([ENABLE_SSL],, [Whether SSL-related support is enabled])
|
AC_DEFINE([ENABLE_SSL],, [Whether SSL-related support is enabled])
|
||||||
|
|
||||||
|
# OpenSSL 1.1 accessor function for DSA signature values
|
||||||
|
AC_CHECK_DECL([DSA_SIG_get0],
|
||||||
|
[AC_DEFINE([HAVE_DSA_SIG_GET0],,
|
||||||
|
[Whether libssl provides DSA_SIG_get0()])],,
|
||||||
|
[#include <openssl/dsa.h>])
|
||||||
|
|
||||||
|
# OpenSSL 1.1 accessor function for DSA public key parameters
|
||||||
|
AC_CHECK_DECL([DSA_get0_pqg],
|
||||||
|
[AC_DEFINE([HAVE_DSA_GET0_PQG],,
|
||||||
|
[Whether libssl provides DSA_get0_pqg()])],,
|
||||||
|
[#include <openssl/dsa.h>])
|
||||||
|
|
||||||
|
# OpenSSL 1.1 accessor function for DSA public/private key values
|
||||||
|
AC_CHECK_DECL([DSA_get0_key],
|
||||||
|
[AC_DEFINE([HAVE_DSA_GET0_KEY],,
|
||||||
|
[Whether libssl provides DSA_get0_key()])],,
|
||||||
|
[#include <openssl/dsa.h>])
|
||||||
|
|
||||||
|
# OpenSSL 1.1 accessor function for RSA public/private key values
|
||||||
|
AC_CHECK_DECL([RSA_get0_key],
|
||||||
|
[AC_DEFINE([HAVE_RSA_GET0_KEY],,
|
||||||
|
[Whether libssl provides RSA_get0_key()])],,
|
||||||
|
[#include <openssl/rsa.h>])
|
||||||
|
|
||||||
# OpenSSL 1.1 does away with explicit threading callbacks
|
# OpenSSL 1.1 does away with explicit threading callbacks
|
||||||
AC_MSG_CHECKING([whether libssl requires threading callbacks])
|
AC_MSG_CHECKING([whether libssl requires threading callbacks])
|
||||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
|
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
|
||||||
@ -913,7 +932,7 @@ if test "x$with_ssh" != "xno"
|
|||||||
then
|
then
|
||||||
have_libssh2=yes
|
have_libssh2=yes
|
||||||
|
|
||||||
AC_CHECK_LIB([ssh2], [libssh2_userauth_publickey_frommemory],
|
AC_CHECK_LIB([ssh2], [libssh2_session_init_ex],
|
||||||
[SSH_LIBS="$SSH_LIBS -lssh2"],
|
[SSH_LIBS="$SSH_LIBS -lssh2"],
|
||||||
[have_libssh2=no])
|
[have_libssh2=no])
|
||||||
fi
|
fi
|
||||||
@ -1167,8 +1186,7 @@ AM_CONDITIONAL([ENABLE_GUACLOG], [test "x${enable_guaclog}" = "xyes"])
|
|||||||
#
|
#
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile
|
AC_CONFIG_FILES([Makefile
|
||||||
doc/libguac/Doxyfile
|
doc/Doxyfile
|
||||||
doc/libguac-terminal/Doxyfile
|
|
||||||
src/common/Makefile
|
src/common/Makefile
|
||||||
src/common/tests/Makefile
|
src/common/tests/Makefile
|
||||||
src/common-ssh/Makefile
|
src/common-ssh/Makefile
|
||||||
|
@ -52,9 +52,9 @@ SHOW_INCLUDE_FILES = NO
|
|||||||
CASE_SENSE_NAMES = YES
|
CASE_SENSE_NAMES = YES
|
||||||
EXCLUDE_SYMBOLS = __* guac_palette*
|
EXCLUDE_SYMBOLS = __* guac_palette*
|
||||||
FILE_PATTERNS = *.h
|
FILE_PATTERNS = *.h
|
||||||
INPUT = ../../src/libguac/guacamole
|
INPUT = ../src/libguac/guacamole
|
||||||
JAVADOC_AUTOBRIEF = YES
|
JAVADOC_AUTOBRIEF = YES
|
||||||
STRIP_FROM_PATH = ../../src/libguac
|
STRIP_FROM_PATH = ../src/libguac
|
||||||
TAB_SIZE = 4
|
TAB_SIZE = 4
|
||||||
TYPEDEF_HIDES_STRUCT = YES
|
TYPEDEF_HIDES_STRUCT = YES
|
||||||
|
|
@ -31,6 +31,8 @@ SUBDIRS = . tests
|
|||||||
|
|
||||||
libguac_common_ssh_la_SOURCES = \
|
libguac_common_ssh_la_SOURCES = \
|
||||||
buffer.c \
|
buffer.c \
|
||||||
|
dsa-compat.c \
|
||||||
|
rsa-compat.c \
|
||||||
sftp.c \
|
sftp.c \
|
||||||
ssh.c \
|
ssh.c \
|
||||||
key.c \
|
key.c \
|
||||||
@ -38,6 +40,8 @@ libguac_common_ssh_la_SOURCES = \
|
|||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
common-ssh/buffer.h \
|
common-ssh/buffer.h \
|
||||||
|
common-ssh/dsa-compat.h \
|
||||||
|
common-ssh/rsa-compat.h \
|
||||||
common-ssh/key.h \
|
common-ssh/key.h \
|
||||||
common-ssh/sftp.h \
|
common-ssh/sftp.h \
|
||||||
common-ssh/ssh.h \
|
common-ssh/ssh.h \
|
||||||
|
61
src/common-ssh/common-ssh/dsa-compat.h
Normal file
61
src/common-ssh/common-ssh/dsa-compat.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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_COMMON_SSH_DSA_COMPAT_H
|
||||||
|
#define GUAC_COMMON_SSH_DSA_COMPAT_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/dsa.h>
|
||||||
|
|
||||||
|
#ifndef HAVE_DSA_GET0_PQG
|
||||||
|
/**
|
||||||
|
* DSA_get0_pqg() implementation for versions of OpenSSL which lack this
|
||||||
|
* function (pre 1.1).
|
||||||
|
*
|
||||||
|
* See: https://www.openssl.org/docs/man1.1.0/crypto/DSA_get0_pqg.html
|
||||||
|
*/
|
||||||
|
void DSA_get0_pqg(const DSA* dsa_key, const BIGNUM** p,
|
||||||
|
const BIGNUM** q, const BIGNUM** g);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_DSA_GET0_KEY
|
||||||
|
/**
|
||||||
|
* DSA_get0_key() implementation for versions of OpenSSL which lack this
|
||||||
|
* function (pre 1.1).
|
||||||
|
*
|
||||||
|
* See: https://www.openssl.org/docs/man1.1.0/crypto/DSA_get0_key.html
|
||||||
|
*/
|
||||||
|
void DSA_get0_key(const DSA* dsa_key, const BIGNUM** pub_key,
|
||||||
|
const BIGNUM** priv_key);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_DSA_SIG_GET0
|
||||||
|
/**
|
||||||
|
* DSA_SIG_get0() implementation for versions of OpenSSL which lack this
|
||||||
|
* function (pre 1.1).
|
||||||
|
*
|
||||||
|
* See: https://www.openssl.org/docs/man1.1.0/crypto/DSA_SIG_get0.html
|
||||||
|
*/
|
||||||
|
void DSA_SIG_get0(const DSA_SIG* dsa_sig, const BIGNUM** r, const BIGNUM** s);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -25,27 +25,75 @@
|
|||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <libssh2.h>
|
#include <libssh2.h>
|
||||||
|
|
||||||
/**
|
#include <openssl/ossl_typ.h>
|
||||||
* OpenSSH v1 private keys are PEM-wrapped base64-encoded blobs. The encoded data begins with:
|
|
||||||
* "openssh-key-v1\0"
|
|
||||||
*/
|
|
||||||
#define OPENSSH_V1_KEY_HEADER "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEA"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base64-encoded prefix indicating an OpenSSH v1 private key is NOT protected by a
|
* The expected header of RSA private keys.
|
||||||
* passphrase. Specifically, it is the following data fields and values:
|
|
||||||
* pascal string: cipher name ("none")
|
|
||||||
* pascal string: kdf name ("none")
|
|
||||||
* pascal string: kdf params (NULL)
|
|
||||||
* 32-bit int: number of keys (1)
|
|
||||||
*/
|
*/
|
||||||
#define OPENSSH_V1_UNENCRYPTED_KEY "AAAABG5vbmUAAAAEbm9uZQAAAAAAAAAB"
|
#define SSH_RSA_KEY_HEADER "-----BEGIN RSA PRIVATE KEY-----"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The expected header of DSA private keys.
|
||||||
|
*/
|
||||||
|
#define SSH_DSA_KEY_HEADER "-----BEGIN DSA PRIVATE KEY-----"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of single number within a DSA signature, in bytes.
|
||||||
|
*/
|
||||||
|
#define DSA_SIG_NUMBER_SIZE 20
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of a DSA signature, in bytes.
|
||||||
|
*/
|
||||||
|
#define DSA_SIG_SIZE DSA_SIG_NUMBER_SIZE*2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of an SSH key.
|
||||||
|
*/
|
||||||
|
typedef enum guac_common_ssh_key_type {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RSA key.
|
||||||
|
*/
|
||||||
|
SSH_KEY_RSA,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DSA key.
|
||||||
|
*/
|
||||||
|
SSH_KEY_DSA
|
||||||
|
|
||||||
|
} guac_common_ssh_key_type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstraction of a key used for SSH authentication.
|
* Abstraction of a key used for SSH authentication.
|
||||||
*/
|
*/
|
||||||
typedef struct guac_common_ssh_key {
|
typedef struct guac_common_ssh_key {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this key.
|
||||||
|
*/
|
||||||
|
guac_common_ssh_key_type type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Underlying RSA private key, if any.
|
||||||
|
*/
|
||||||
|
RSA* rsa;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Underlying DSA private key, if any.
|
||||||
|
*/
|
||||||
|
DSA* dsa;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated public key, encoded as necessary for SSH.
|
||||||
|
*/
|
||||||
|
char* public_key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of the public key, in bytes.
|
||||||
|
*/
|
||||||
|
int public_key_length;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The private key, encoded as necessary for SSH.
|
* The private key, encoded as necessary for SSH.
|
||||||
*/
|
*/
|
||||||
@ -56,11 +104,6 @@ typedef struct guac_common_ssh_key {
|
|||||||
*/
|
*/
|
||||||
int private_key_length;
|
int private_key_length;
|
||||||
|
|
||||||
/**
|
|
||||||
* The private key's passphrase, if any.
|
|
||||||
*/
|
|
||||||
char *passphrase;
|
|
||||||
|
|
||||||
} guac_common_ssh_key;
|
} guac_common_ssh_key;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,6 +144,31 @@ const char* guac_common_ssh_key_error();
|
|||||||
*/
|
*/
|
||||||
void guac_common_ssh_key_free(guac_common_ssh_key* key);
|
void guac_common_ssh_key_free(guac_common_ssh_key* key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signs the given data using the given key, returning the length of the
|
||||||
|
* signature in bytes, or a value less than zero on error.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* The key to use when signing the given data.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* The arbitrary data to sign.
|
||||||
|
*
|
||||||
|
* @param length
|
||||||
|
* The length of the arbitrary data being signed, in bytes.
|
||||||
|
*
|
||||||
|
* @param sig
|
||||||
|
* The buffer into which the signature should be written. The buffer must
|
||||||
|
* be at least DSA_SIG_SIZE for DSA keys. For RSA keys, the signature size
|
||||||
|
* is dependent only on key size, and is equal to the length of the
|
||||||
|
* modulus, in bytes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The number of bytes in the resulting signature.
|
||||||
|
*/
|
||||||
|
int guac_common_ssh_key_sign(guac_common_ssh_key* key, const char* data,
|
||||||
|
int length, unsigned char* sig);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies the host key for the given hostname/port combination against
|
* Verifies the host key for the given hostname/port combination against
|
||||||
* one or more known_hosts entries. The known_host entries can either be a
|
* one or more known_hosts entries. The known_host entries can either be a
|
||||||
|
40
src/common-ssh/common-ssh/rsa-compat.h
Normal file
40
src/common-ssh/common-ssh/rsa-compat.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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_COMMON_SSH_RSA_COMPAT_H
|
||||||
|
#define GUAC_COMMON_SSH_RSA_COMPAT_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
|
||||||
|
#ifndef HAVE_RSA_GET0_KEY
|
||||||
|
/**
|
||||||
|
* RSA_get0_key() implementation for versions of OpenSSL which lack this
|
||||||
|
* function (pre 1.1).
|
||||||
|
*
|
||||||
|
* See: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html
|
||||||
|
*/
|
||||||
|
void RSA_get0_key(const RSA* rsa_key, const BIGNUM** n,
|
||||||
|
const BIGNUM** e, const BIGNUM**d);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
59
src/common-ssh/dsa-compat.c
Normal file
59
src/common-ssh/dsa-compat.c
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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 <openssl/bn.h>
|
||||||
|
#include <openssl/dsa.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifndef HAVE_DSA_GET0_PQG
|
||||||
|
void DSA_get0_pqg(const DSA* dsa_key, const BIGNUM** p,
|
||||||
|
const BIGNUM** q, const BIGNUM** g) {
|
||||||
|
|
||||||
|
/* Retrieve all requested internal values */
|
||||||
|
if (p != NULL) *p = dsa_key->p;
|
||||||
|
if (q != NULL) *q = dsa_key->q;
|
||||||
|
if (g != NULL) *g = dsa_key->g;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_DSA_GET0_KEY
|
||||||
|
void DSA_get0_key(const DSA* dsa_key, const BIGNUM** pub_key,
|
||||||
|
const BIGNUM** priv_key) {
|
||||||
|
|
||||||
|
/* Retrieve all requested internal values */
|
||||||
|
if (pub_key != NULL) *pub_key = dsa_key->pub_key;
|
||||||
|
if (priv_key != NULL) *priv_key = dsa_key->priv_key;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_DSA_SIG_GET0
|
||||||
|
void DSA_SIG_get0(const DSA_SIG* dsa_sig, const BIGNUM** r, const BIGNUM** s) {
|
||||||
|
|
||||||
|
/* Retrieve all requested internal values */
|
||||||
|
if (r != NULL) *r = dsa_sig->r;
|
||||||
|
if (s != NULL) *s = dsa_sig->s;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -20,9 +20,9 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "common-ssh/buffer.h"
|
#include "common-ssh/buffer.h"
|
||||||
|
#include "common-ssh/dsa-compat.h"
|
||||||
#include "common-ssh/key.h"
|
#include "common-ssh/key.h"
|
||||||
|
#include "common-ssh/rsa-compat.h"
|
||||||
#include <guacamole/string.h>
|
|
||||||
|
|
||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
@ -33,118 +33,119 @@
|
|||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for a PKCS#1/PKCS#8 ENCRYPTED marker.
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* The buffer to scan.
|
|
||||||
* @param length
|
|
||||||
* The length of the buffer.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* True if the buffer contains the marker, false otherwise.
|
|
||||||
*/
|
|
||||||
static bool is_pkcs_encrypted_key(char* data, int length) {
|
|
||||||
return guac_strnstr(data, "ENCRYPTED", length) != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for a PEM header & initial base64-encoded data indicating this is an
|
|
||||||
* OpenSSH v1 key.
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* The buffer to scan.
|
|
||||||
* @param length
|
|
||||||
* The length of the buffer.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* True if the buffer contains a private key, false otherwise.
|
|
||||||
*/
|
|
||||||
static bool is_ssh_private_key(char* data, int length) {
|
|
||||||
if (length < sizeof(OPENSSH_V1_KEY_HEADER) - 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !strncmp(data, OPENSSH_V1_KEY_HEADER, sizeof(OPENSSH_V1_KEY_HEADER) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assuming an offset into a key past the header, check for the base64-encoded
|
|
||||||
* data indicating this key is not protected by a passphrase.
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* The buffer to scan.
|
|
||||||
* @param length
|
|
||||||
* The length of the buffer.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* True if the buffer contains an unencrypted key, false otherwise.
|
|
||||||
*/
|
|
||||||
static bool is_ssh_key_unencrypted(char* data, int length) {
|
|
||||||
if (length < sizeof(OPENSSH_V1_UNENCRYPTED_KEY) - 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !strncmp(data, OPENSSH_V1_UNENCRYPTED_KEY, sizeof(OPENSSH_V1_UNENCRYPTED_KEY) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A passphrase is needed if the key is an encrypted PKCS#1/PKCS#8 key OR if
|
|
||||||
* the key is both an OpenSSH v1 key AND there isn't a marker indicating the
|
|
||||||
* key is unprotected.
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* The buffer to scan.
|
|
||||||
* @param length
|
|
||||||
* The length of the buffer.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* True if the buffer contains a key needing a passphrase, false otherwise.
|
|
||||||
*/
|
|
||||||
static bool is_passphrase_needed(char* data, int length) {
|
|
||||||
/* Is this an encrypted PKCS#1/PKCS#8 key? */
|
|
||||||
if (is_pkcs_encrypted_key(data, length)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Is this an OpenSSH v1 key? */
|
|
||||||
if (is_ssh_private_key(data, length)) {
|
|
||||||
/* This is safe due to the check in is_ssh_private_key. */
|
|
||||||
data += sizeof(OPENSSH_V1_KEY_HEADER) - 1;
|
|
||||||
length -= sizeof(OPENSSH_V1_KEY_HEADER) - 1;
|
|
||||||
/* If this is NOT unprotected, we need a passphrase. */
|
|
||||||
if (!is_ssh_key_unencrypted(data, length)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
guac_common_ssh_key* guac_common_ssh_key_alloc(char* data, int length,
|
guac_common_ssh_key* guac_common_ssh_key_alloc(char* data, int length,
|
||||||
char* passphrase) {
|
char* passphrase) {
|
||||||
|
|
||||||
/* Because libssh2 will do the actual key parsing (to let it deal with
|
guac_common_ssh_key* key;
|
||||||
* different key algorithms) we need to perform a heuristic here to check
|
BIO* key_bio;
|
||||||
* if a passphrase is needed. This could allow junk keys through that
|
|
||||||
* would never be able to auth. libssh2 should display errors to help
|
|
||||||
* admins track down malformed keys and delete or replace them.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (is_passphrase_needed(data, length) && (passphrase == NULL || *passphrase == '\0'))
|
char* public_key;
|
||||||
|
char* pos;
|
||||||
|
|
||||||
|
/* Create BIO for reading key from memory */
|
||||||
|
key_bio = BIO_new_mem_buf(data, length);
|
||||||
|
|
||||||
|
/* If RSA key, load RSA */
|
||||||
|
if (length > sizeof(SSH_RSA_KEY_HEADER)-1
|
||||||
|
&& memcmp(SSH_RSA_KEY_HEADER, data,
|
||||||
|
sizeof(SSH_RSA_KEY_HEADER)-1) == 0) {
|
||||||
|
|
||||||
|
RSA* rsa_key;
|
||||||
|
|
||||||
|
const BIGNUM* key_e;
|
||||||
|
const BIGNUM* key_n;
|
||||||
|
|
||||||
|
/* Read key */
|
||||||
|
rsa_key = PEM_read_bio_RSAPrivateKey(key_bio, NULL, NULL, passphrase);
|
||||||
|
if (rsa_key == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Allocate key */
|
||||||
|
key = malloc(sizeof(guac_common_ssh_key));
|
||||||
|
key->rsa = rsa_key;
|
||||||
|
|
||||||
|
/* Set type */
|
||||||
|
key->type = SSH_KEY_RSA;
|
||||||
|
|
||||||
|
/* Allocate space for public key */
|
||||||
|
public_key = malloc(4096);
|
||||||
|
pos = public_key;
|
||||||
|
|
||||||
|
/* Retrieve public key */
|
||||||
|
RSA_get0_key(rsa_key, &key_n, &key_e, NULL);
|
||||||
|
|
||||||
|
/* Send public key formatted for SSH */
|
||||||
|
guac_common_ssh_buffer_write_string(&pos, "ssh-rsa", sizeof("ssh-rsa")-1);
|
||||||
|
guac_common_ssh_buffer_write_bignum(&pos, key_e);
|
||||||
|
guac_common_ssh_buffer_write_bignum(&pos, key_n);
|
||||||
|
|
||||||
|
/* Save public key to structure */
|
||||||
|
key->public_key = public_key;
|
||||||
|
key->public_key_length = pos - public_key;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If DSA key, load DSA */
|
||||||
|
else if (length > sizeof(SSH_DSA_KEY_HEADER)-1
|
||||||
|
&& memcmp(SSH_DSA_KEY_HEADER, data,
|
||||||
|
sizeof(SSH_DSA_KEY_HEADER)-1) == 0) {
|
||||||
|
|
||||||
|
DSA* dsa_key;
|
||||||
|
|
||||||
|
const BIGNUM* key_p;
|
||||||
|
const BIGNUM* key_q;
|
||||||
|
const BIGNUM* key_g;
|
||||||
|
const BIGNUM* pub_key;
|
||||||
|
|
||||||
|
/* Read key */
|
||||||
|
dsa_key = PEM_read_bio_DSAPrivateKey(key_bio, NULL, NULL, passphrase);
|
||||||
|
if (dsa_key == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Allocate key */
|
||||||
|
key = malloc(sizeof(guac_common_ssh_key));
|
||||||
|
key->dsa = dsa_key;
|
||||||
|
|
||||||
|
/* Set type */
|
||||||
|
key->type = SSH_KEY_DSA;
|
||||||
|
|
||||||
|
/* Allocate space for public key */
|
||||||
|
public_key = malloc(4096);
|
||||||
|
pos = public_key;
|
||||||
|
|
||||||
|
/* Retrieve public key */
|
||||||
|
DSA_get0_pqg(dsa_key, &key_p, &key_q, &key_g);
|
||||||
|
DSA_get0_key(dsa_key, &pub_key, NULL);
|
||||||
|
|
||||||
|
/* Send public key formatted for SSH */
|
||||||
|
guac_common_ssh_buffer_write_string(&pos, "ssh-dss", sizeof("ssh-dss")-1);
|
||||||
|
guac_common_ssh_buffer_write_bignum(&pos, key_p);
|
||||||
|
guac_common_ssh_buffer_write_bignum(&pos, key_q);
|
||||||
|
guac_common_ssh_buffer_write_bignum(&pos, key_g);
|
||||||
|
guac_common_ssh_buffer_write_bignum(&pos, pub_key);
|
||||||
|
|
||||||
|
/* Save public key to structure */
|
||||||
|
key->public_key = public_key;
|
||||||
|
key->public_key_length = pos - public_key;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, unsupported type */
|
||||||
|
else {
|
||||||
|
BIO_free(key_bio);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
guac_common_ssh_key* key = malloc(sizeof(guac_common_ssh_key));
|
|
||||||
|
|
||||||
/* Copy private key to structure */
|
/* Copy private key to structure */
|
||||||
key->private_key_length = length;
|
key->private_key_length = length;
|
||||||
key->private_key = malloc(length);
|
key->private_key = malloc(length);
|
||||||
memcpy(key->private_key, data, length);
|
memcpy(key->private_key, data, length);
|
||||||
key->passphrase = strdup(passphrase);
|
|
||||||
|
|
||||||
|
BIO_free(key_bio);
|
||||||
return key;
|
return key;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -158,11 +159,93 @@ const char* guac_common_ssh_key_error() {
|
|||||||
|
|
||||||
void guac_common_ssh_key_free(guac_common_ssh_key* key) {
|
void guac_common_ssh_key_free(guac_common_ssh_key* key) {
|
||||||
|
|
||||||
|
/* Free key-specific data */
|
||||||
|
if (key->type == SSH_KEY_RSA)
|
||||||
|
RSA_free(key->rsa);
|
||||||
|
else if (key->type == SSH_KEY_DSA)
|
||||||
|
DSA_free(key->dsa);
|
||||||
|
|
||||||
free(key->private_key);
|
free(key->private_key);
|
||||||
free(key->passphrase);
|
free(key->public_key);
|
||||||
free(key);
|
free(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guac_common_ssh_key_sign(guac_common_ssh_key* key, const char* data,
|
||||||
|
int length, unsigned char* sig) {
|
||||||
|
|
||||||
|
const EVP_MD* md;
|
||||||
|
|
||||||
|
unsigned char digest[EVP_MAX_MD_SIZE];
|
||||||
|
unsigned int dlen, len;
|
||||||
|
|
||||||
|
/* Get SHA1 digest */
|
||||||
|
if ((md = EVP_get_digestbynid(NID_sha1)) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Allocate digest context */
|
||||||
|
EVP_MD_CTX* md_ctx = EVP_MD_CTX_create();
|
||||||
|
if (md_ctx == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Digest data */
|
||||||
|
EVP_DigestInit(md_ctx, md);
|
||||||
|
EVP_DigestUpdate(md_ctx, data, length);
|
||||||
|
EVP_DigestFinal(md_ctx, digest, &dlen);
|
||||||
|
|
||||||
|
/* Digest context no longer needed */
|
||||||
|
EVP_MD_CTX_destroy(md_ctx);
|
||||||
|
|
||||||
|
/* Sign with key */
|
||||||
|
switch (key->type) {
|
||||||
|
|
||||||
|
case SSH_KEY_RSA:
|
||||||
|
if (RSA_sign(NID_sha1, digest, dlen, sig, &len, key->rsa) == 1)
|
||||||
|
return len;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_KEY_DSA: {
|
||||||
|
|
||||||
|
DSA_SIG* dsa_sig = DSA_do_sign(digest, dlen, key->dsa);
|
||||||
|
if (dsa_sig != NULL) {
|
||||||
|
|
||||||
|
const BIGNUM* sig_r;
|
||||||
|
const BIGNUM* sig_s;
|
||||||
|
|
||||||
|
/* Retrieve DSA signature values */
|
||||||
|
DSA_SIG_get0(dsa_sig, &sig_r, &sig_s);
|
||||||
|
|
||||||
|
/* Compute size of each half of signature */
|
||||||
|
int rlen = BN_num_bytes(sig_r);
|
||||||
|
int slen = BN_num_bytes(sig_s);
|
||||||
|
|
||||||
|
/* Ensure each number is within the required size */
|
||||||
|
if (rlen > DSA_SIG_NUMBER_SIZE || slen > DSA_SIG_NUMBER_SIZE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Init to all zeroes */
|
||||||
|
memset(sig, 0, DSA_SIG_SIZE);
|
||||||
|
|
||||||
|
/* Add R at the end of the first block of the signature */
|
||||||
|
BN_bn2bin(sig_r, sig + DSA_SIG_SIZE
|
||||||
|
- DSA_SIG_NUMBER_SIZE - rlen);
|
||||||
|
|
||||||
|
/* Add S at the end of the second block of the signature */
|
||||||
|
BN_bn2bin(sig_s, sig + DSA_SIG_SIZE - slen);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
DSA_SIG_free(dsa_sig);
|
||||||
|
return DSA_SIG_SIZE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int guac_common_ssh_verify_host_key(LIBSSH2_SESSION* session, guac_client* client,
|
int guac_common_ssh_verify_host_key(LIBSSH2_SESSION* session, guac_client* client,
|
||||||
const char* host_key, const char* hostname, int port, const char* remote_hostkey,
|
const char* host_key, const char* hostname, int port, const char* remote_hostkey,
|
||||||
const size_t remote_hostkey_len) {
|
const size_t remote_hostkey_len) {
|
||||||
|
@ -17,17 +17,22 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef GUAC_FIPS_H
|
#include "config.h"
|
||||||
#define GUAC_FIPS_H
|
|
||||||
|
|
||||||
/**
|
#include <openssl/bn.h>
|
||||||
* Returns a non-zero value if FIPS mode is enabled, or zero if FIPS mode
|
#include <openssl/rsa.h>
|
||||||
* is not enabled.
|
|
||||||
*
|
#include <stdlib.h>
|
||||||
* @return
|
|
||||||
* A non-zero value if FIPS mode is enabled, or zero if FIPS mode is
|
#ifndef HAVE_RSA_GET0_KEY
|
||||||
* not enabled.
|
void RSA_get0_key(const RSA* rsa_key, const BIGNUM** n,
|
||||||
*/
|
const BIGNUM** e, const BIGNUM**d) {
|
||||||
int guac_fips_enabled();
|
|
||||||
|
/* Retrieve all requested internal values */
|
||||||
|
if (n != NULL) *n = rsa_key->n;
|
||||||
|
if (e != NULL) *e = rsa_key->e;
|
||||||
|
if (d != NULL) *d = rsa_key->d;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
|
@ -22,7 +22,6 @@
|
|||||||
#include "common-ssh/user.h"
|
#include "common-ssh/user.h"
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/fips.h>
|
|
||||||
#include <libssh2.h>
|
#include <libssh2.h>
|
||||||
|
|
||||||
#ifdef LIBSSH2_USES_GCRYPT
|
#ifdef LIBSSH2_USES_GCRYPT
|
||||||
@ -47,20 +46,6 @@
|
|||||||
GCRY_THREAD_OPTION_PTHREAD_IMPL;
|
GCRY_THREAD_OPTION_PTHREAD_IMPL;
|
||||||
#endif
|
#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
|
#ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS
|
||||||
/**
|
/**
|
||||||
* Array of mutexes, used by OpenSSL.
|
* Array of mutexes, used by OpenSSL.
|
||||||
@ -180,11 +165,9 @@ int guac_common_ssh_init(guac_client* client) {
|
|||||||
CRYPTO_set_locking_callback(guac_common_ssh_openssl_locking_callback);
|
CRYPTO_set_locking_callback(guac_common_ssh_openssl_locking_callback);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
/* Init OpenSSL */
|
||||||
/* Init OpenSSL - only required for OpenSSL Versions < 1.1.0 */
|
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
ERR_load_crypto_strings();
|
ERR_load_crypto_strings();
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Init libssh2 */
|
/* Init libssh2 */
|
||||||
libssh2_init(0);
|
libssh2_init(0);
|
||||||
@ -200,6 +183,55 @@ void guac_common_ssh_uninit() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked by libssh2 when libssh2_userauth_publickkey() is invoked.
|
||||||
|
* This callback must sign the given data, returning the signature as newly-
|
||||||
|
* allocated buffer space.
|
||||||
|
*
|
||||||
|
* @param session
|
||||||
|
* The SSH session for which the signature is being generated.
|
||||||
|
*
|
||||||
|
* @param sig
|
||||||
|
* A pointer to the buffer space containing the signature. This callback
|
||||||
|
* MUST allocate and assign this space.
|
||||||
|
*
|
||||||
|
* @param sig_len
|
||||||
|
* The length of the signature within the allocated buffer space, in bytes.
|
||||||
|
* This value must be set to the size of the signature after the signing
|
||||||
|
* operation completes.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* The arbitrary data that must be signed.
|
||||||
|
*
|
||||||
|
* @param data_len
|
||||||
|
* The length of the arbitrary data to be signed, in bytes.
|
||||||
|
*
|
||||||
|
* @param abstract
|
||||||
|
* The value of the abstract parameter provided with the corresponding call
|
||||||
|
* to libssh2_userauth_publickey().
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero if the signing operation failed.
|
||||||
|
*/
|
||||||
|
static int guac_common_ssh_sign_callback(LIBSSH2_SESSION* session,
|
||||||
|
unsigned char** sig, size_t* sig_len,
|
||||||
|
const unsigned char* data, size_t data_len, void **abstract) {
|
||||||
|
|
||||||
|
guac_common_ssh_key* key = (guac_common_ssh_key*) abstract;
|
||||||
|
int length;
|
||||||
|
|
||||||
|
/* Allocate space for signature */
|
||||||
|
*sig = malloc(4096);
|
||||||
|
|
||||||
|
/* Sign with key */
|
||||||
|
length = guac_common_ssh_key_sign(key, (const char*) data, data_len, *sig);
|
||||||
|
if (length < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
*sig_len = length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for the keyboard-interactive authentication method. Currently
|
* Callback for the keyboard-interactive authentication method. Currently
|
||||||
* supports just one prompt for the password. This callback is invoked as
|
* supports just one prompt for the password. This callback is invoked as
|
||||||
@ -292,9 +324,8 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get list of supported authentication methods */
|
/* Get list of supported authentication methods */
|
||||||
size_t username_len = strlen(user->username);
|
|
||||||
char* user_authlist = libssh2_userauth_list(session, user->username,
|
char* user_authlist = libssh2_userauth_list(session, user->username,
|
||||||
username_len);
|
strlen(user->username));
|
||||||
|
|
||||||
/* If auth list is NULL, then authentication has succeeded with NONE */
|
/* If auth list is NULL, then authentication has succeeded with NONE */
|
||||||
if (user_authlist == NULL) {
|
if (user_authlist == NULL) {
|
||||||
@ -318,9 +349,9 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt public key auth */
|
/* Attempt public key auth */
|
||||||
if (libssh2_userauth_publickey_frommemory(session, user->username,
|
if (libssh2_userauth_publickey(session, user->username,
|
||||||
username_len, NULL, 0, key->private_key,
|
(unsigned char*) key->public_key, key->public_key_length,
|
||||||
key->private_key_length, key->passphrase)) {
|
guac_common_ssh_sign_callback, (void**) key)) {
|
||||||
|
|
||||||
/* Abort on failure */
|
/* Abort on failure */
|
||||||
char* error_message;
|
char* error_message;
|
||||||
@ -501,17 +532,6 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
|||||||
return NULL;
|
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 */
|
/* Perform handshake */
|
||||||
if (libssh2_session_handshake(session, fd)) {
|
if (libssh2_session_handshake(session, fd)) {
|
||||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
||||||
|
@ -42,6 +42,7 @@ noinst_HEADERS = \
|
|||||||
common/json.h \
|
common/json.h \
|
||||||
common/list.h \
|
common/list.h \
|
||||||
common/pointer_cursor.h \
|
common/pointer_cursor.h \
|
||||||
|
common/recording.h \
|
||||||
common/rect.h \
|
common/rect.h \
|
||||||
common/string.h \
|
common/string.h \
|
||||||
common/surface.h
|
common/surface.h
|
||||||
@ -58,6 +59,7 @@ libguac_common_la_SOURCES = \
|
|||||||
json.c \
|
json.c \
|
||||||
list.c \
|
list.c \
|
||||||
pointer_cursor.c \
|
pointer_cursor.c \
|
||||||
|
recording.c \
|
||||||
rect.c \
|
rect.c \
|
||||||
string.c \
|
string.c \
|
||||||
surface.c
|
surface.c
|
||||||
|
@ -29,15 +29,15 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
guac_common_clipboard* guac_common_clipboard_alloc() {
|
guac_common_clipboard* guac_common_clipboard_alloc(int size) {
|
||||||
|
|
||||||
guac_common_clipboard* clipboard = malloc(sizeof(guac_common_clipboard));
|
guac_common_clipboard* clipboard = malloc(sizeof(guac_common_clipboard));
|
||||||
|
|
||||||
/* Init clipboard */
|
/* Init clipboard */
|
||||||
clipboard->mimetype[0] = '\0';
|
clipboard->mimetype[0] = '\0';
|
||||||
clipboard->buffer = malloc(GUAC_COMMON_CLIPBOARD_MAX_LENGTH);
|
clipboard->buffer = malloc(size);
|
||||||
clipboard->available = GUAC_COMMON_CLIPBOARD_MAX_LENGTH;
|
|
||||||
clipboard->length = 0;
|
clipboard->length = 0;
|
||||||
|
clipboard->available = size;
|
||||||
|
|
||||||
pthread_mutex_init(&(clipboard->lock), NULL);
|
pthread_mutex_init(&(clipboard->lock), NULL);
|
||||||
|
|
||||||
|
@ -31,11 +31,6 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_COMMON_CLIPBOARD_BLOCK_SIZE 4096
|
#define GUAC_COMMON_CLIPBOARD_BLOCK_SIZE 4096
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum number of bytes to allow within the clipboard.
|
|
||||||
*/
|
|
||||||
#define GUAC_COMMON_CLIPBOARD_MAX_LENGTH 262144
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic clipboard structure.
|
* Generic clipboard structure.
|
||||||
*/
|
*/
|
||||||
@ -71,9 +66,12 @@ typedef struct guac_common_clipboard {
|
|||||||
} guac_common_clipboard;
|
} guac_common_clipboard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new clipboard.
|
* Creates a new clipboard having the given initial size.
|
||||||
|
*
|
||||||
|
* @param size The maximum number of bytes to allow within the clipboard.
|
||||||
|
* @return A newly-allocated clipboard.
|
||||||
*/
|
*/
|
||||||
guac_common_clipboard* guac_common_clipboard_alloc();
|
guac_common_clipboard* guac_common_clipboard_alloc(int size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frees the given clipboard.
|
* Frees the given clipboard.
|
||||||
|
@ -17,17 +17,11 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef GUAC_RECORDING_H
|
#ifndef GUAC_COMMON_RECORDING_H
|
||||||
#define GUAC_RECORDING_H
|
#define GUAC_COMMON_RECORDING_H
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides functions and structures to be use for session recording.
|
|
||||||
*
|
|
||||||
* @file recording.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum numeric value allowed for the .1, .2, .3, etc. suffix appended
|
* The maximum numeric value allowed for the .1, .2, .3, etc. suffix appended
|
||||||
* to the end of the session recording filename if a recording having the
|
* to the end of the session recording filename if a recording having the
|
||||||
@ -53,7 +47,7 @@
|
|||||||
* that output Guacamole instructions may be dynamically intercepted and
|
* that output Guacamole instructions may be dynamically intercepted and
|
||||||
* written to a file.
|
* written to a file.
|
||||||
*/
|
*/
|
||||||
typedef struct guac_recording {
|
typedef struct guac_common_recording {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The guac_socket which writes directly to the recording file, rather than
|
* The guac_socket which writes directly to the recording file, rather than
|
||||||
@ -95,7 +89,7 @@ typedef struct guac_recording {
|
|||||||
*/
|
*/
|
||||||
int include_keys;
|
int include_keys;
|
||||||
|
|
||||||
} guac_recording;
|
} guac_common_recording;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces the socket of the given client such that all further Guacamole
|
* Replaces the socket of the given client such that all further Guacamole
|
||||||
@ -149,11 +143,11 @@ typedef struct guac_recording {
|
|||||||
* passwords, credit card numbers, etc.
|
* passwords, credit card numbers, etc.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* A new guac_recording structure representing the in-progress
|
* A new guac_common_recording structure representing the in-progress
|
||||||
* recording if the recording file has been successfully created and a
|
* recording if the recording file has been successfully created and a
|
||||||
* recording will be written, NULL otherwise.
|
* recording will be written, NULL otherwise.
|
||||||
*/
|
*/
|
||||||
guac_recording* guac_recording_create(guac_client* client,
|
guac_common_recording* guac_common_recording_create(guac_client* client,
|
||||||
const char* path, const char* name, int create_path,
|
const char* path, const char* name, int create_path,
|
||||||
int include_output, int include_mouse, int include_touch,
|
int include_output, int include_mouse, int include_touch,
|
||||||
int include_keys);
|
int include_keys);
|
||||||
@ -165,15 +159,15 @@ guac_recording* guac_recording_create(guac_client* client,
|
|||||||
* freed when the guac_client is freed.
|
* freed when the guac_client is freed.
|
||||||
*
|
*
|
||||||
* @param recording
|
* @param recording
|
||||||
* The guac_recording to free.
|
* The guac_common_recording to free.
|
||||||
*/
|
*/
|
||||||
void guac_recording_free(guac_recording* recording);
|
void guac_common_recording_free(guac_common_recording* recording);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reports the current mouse position and button state within the recording.
|
* Reports the current mouse position and button state within the recording.
|
||||||
*
|
*
|
||||||
* @param recording
|
* @param recording
|
||||||
* The guac_recording associated with the mouse that has moved.
|
* The guac_common_recording associated with the mouse that has moved.
|
||||||
*
|
*
|
||||||
* @param x
|
* @param x
|
||||||
* The new X coordinate of the mouse cursor, in pixels.
|
* The new X coordinate of the mouse cursor, in pixels.
|
||||||
@ -194,14 +188,14 @@ void guac_recording_free(guac_recording* recording);
|
|||||||
* @see GUAC_CLIENT_MOUSE_SCROLL_UP
|
* @see GUAC_CLIENT_MOUSE_SCROLL_UP
|
||||||
* @see GUAC_CLIENT_MOUSE_SCROLL_DOWN
|
* @see GUAC_CLIENT_MOUSE_SCROLL_DOWN
|
||||||
*/
|
*/
|
||||||
void guac_recording_report_mouse(guac_recording* recording,
|
void guac_common_recording_report_mouse(guac_common_recording* recording,
|
||||||
int x, int y, int button_mask);
|
int x, int y, int button_mask);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reports the current state of a touch contact within the recording.
|
* Reports the current state of a touch contact within the recording.
|
||||||
*
|
*
|
||||||
* @param recording
|
* @param recording
|
||||||
* The guac_recording associated with the touch contact that
|
* The guac_common_recording associated with the touch contact that
|
||||||
* has changed state.
|
* has changed state.
|
||||||
*
|
*
|
||||||
* @param id
|
* @param id
|
||||||
@ -231,7 +225,7 @@ void guac_recording_report_mouse(guac_recording* recording,
|
|||||||
* (the touch has been lifted) and 1 is maximum force (the maximum amount
|
* (the touch has been lifted) and 1 is maximum force (the maximum amount
|
||||||
* of force representable by the device).
|
* of force representable by the device).
|
||||||
*/
|
*/
|
||||||
void guac_recording_report_touch(guac_recording* recording,
|
void guac_common_recording_report_touch(guac_common_recording* recording,
|
||||||
int id, int x, int y, int x_radius, int y_radius,
|
int id, int x, int y, int x_radius, int y_radius,
|
||||||
double angle, double force);
|
double angle, double force);
|
||||||
|
|
||||||
@ -239,7 +233,7 @@ void guac_recording_report_touch(guac_recording* recording,
|
|||||||
* Reports a change in the state of an individual key within the recording.
|
* Reports a change in the state of an individual key within the recording.
|
||||||
*
|
*
|
||||||
* @param recording
|
* @param recording
|
||||||
* The guac_recording associated with the key that was pressed or
|
* The guac_common_recording associated with the key that was pressed or
|
||||||
* released.
|
* released.
|
||||||
*
|
*
|
||||||
* @param keysym
|
* @param keysym
|
||||||
@ -249,7 +243,7 @@ void guac_recording_report_touch(guac_recording* recording,
|
|||||||
* Non-zero if the key represented by the given keysym is currently
|
* Non-zero if the key represented by the given keysym is currently
|
||||||
* pressed, zero if it is released.
|
* pressed, zero if it is released.
|
||||||
*/
|
*/
|
||||||
void guac_recording_report_key(guac_recording* recording,
|
void guac_common_recording_report_key(guac_common_recording* recording,
|
||||||
int keysym, int pressed);
|
int keysym, int pressed);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -166,8 +166,6 @@ void guac_common_display_free(guac_common_display* display) {
|
|||||||
void guac_common_display_dup(guac_common_display* display, guac_user* user,
|
void guac_common_display_dup(guac_common_display* display, guac_user* user,
|
||||||
guac_socket* socket) {
|
guac_socket* socket) {
|
||||||
|
|
||||||
guac_client* client = user->client;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&display->_lock);
|
pthread_mutex_lock(&display->_lock);
|
||||||
|
|
||||||
/* Sunchronize shared cursor */
|
/* Sunchronize shared cursor */
|
||||||
@ -180,9 +178,6 @@ 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->layers, user, socket);
|
||||||
guac_common_display_dup_layers(display->buffers, 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);
|
pthread_mutex_unlock(&display->_lock);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -389,3 +384,4 @@ void guac_common_display_free_buffer(guac_common_display* display,
|
|||||||
pthread_mutex_unlock(&display->_lock);
|
pthread_mutex_unlock(&display->_lock);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,11 +17,12 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "guacamole/client.h"
|
#include "common/recording.h"
|
||||||
#include "guacamole/protocol.h"
|
|
||||||
#include "guacamole/recording.h"
|
#include <guacamole/client.h>
|
||||||
#include "guacamole/socket.h"
|
#include <guacamole/protocol.h>
|
||||||
#include "guacamole/timestamp.h"
|
#include <guacamole/socket.h>
|
||||||
|
#include <guacamole/timestamp.h>
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
@ -63,7 +64,7 @@
|
|||||||
* The file descriptor of the open data file if open succeeded, or -1 on
|
* The file descriptor of the open data file if open succeeded, or -1 on
|
||||||
* failure.
|
* failure.
|
||||||
*/
|
*/
|
||||||
static int guac_recording_open(const char* path,
|
static int guac_common_recording_open(const char* path,
|
||||||
const char* name, char* basename, int basename_size) {
|
const char* name, char* basename, int basename_size) {
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
@ -83,7 +84,7 @@ static int guac_recording_open(const char* path,
|
|||||||
/* Attempt to open recording */
|
/* Attempt to open recording */
|
||||||
int fd = open(basename,
|
int fd = open(basename,
|
||||||
O_CREAT | O_EXCL | O_WRONLY,
|
O_CREAT | O_EXCL | O_WRONLY,
|
||||||
S_IRUSR | S_IWUSR | S_IRGRP);
|
S_IRUSR | S_IWUSR);
|
||||||
|
|
||||||
/* Continuously retry with alternate names on failure */
|
/* Continuously retry with alternate names on failure */
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
@ -102,7 +103,7 @@ static int guac_recording_open(const char* path,
|
|||||||
/* Retry with newly-suffixed filename */
|
/* Retry with newly-suffixed filename */
|
||||||
fd = open(basename,
|
fd = open(basename,
|
||||||
O_CREAT | O_EXCL | O_WRONLY,
|
O_CREAT | O_EXCL | O_WRONLY,
|
||||||
S_IRUSR | S_IWUSR | S_IRGRP);
|
S_IRUSR | S_IWUSR);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +135,7 @@ static int guac_recording_open(const char* path,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
guac_recording* guac_recording_create(guac_client* client,
|
guac_common_recording* guac_common_recording_create(guac_client* client,
|
||||||
const char* path, const char* name, int create_path,
|
const char* path, const char* name, int create_path,
|
||||||
int include_output, int include_mouse, int include_touch,
|
int include_output, int include_mouse, int include_touch,
|
||||||
int include_keys) {
|
int include_keys) {
|
||||||
@ -143,8 +144,7 @@ guac_recording* guac_recording_create(guac_client* client,
|
|||||||
|
|
||||||
/* Create path if it does not exist, fail if impossible */
|
/* Create path if it does not exist, fail if impossible */
|
||||||
#ifndef __MINGW32__
|
#ifndef __MINGW32__
|
||||||
if (create_path && mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP)
|
if (create_path && mkdir(path, S_IRWXU) && errno != EEXIST) {
|
||||||
&& errno != EEXIST) {
|
|
||||||
#else
|
#else
|
||||||
if (create_path && _mkdir(path) && errno != EEXIST) {
|
if (create_path && _mkdir(path) && errno != EEXIST) {
|
||||||
#endif
|
#endif
|
||||||
@ -154,7 +154,7 @@ guac_recording* guac_recording_create(guac_client* client,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt to open recording file */
|
/* Attempt to open recording file */
|
||||||
int fd = guac_recording_open(path, name, filename, sizeof(filename));
|
int fd = guac_common_recording_open(path, name, filename, sizeof(filename));
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
guac_client_log(client, GUAC_LOG_ERROR,
|
guac_client_log(client, GUAC_LOG_ERROR,
|
||||||
"Creation of recording failed: %s", strerror(errno));
|
"Creation of recording failed: %s", strerror(errno));
|
||||||
@ -162,7 +162,7 @@ guac_recording* guac_recording_create(guac_client* client,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Create recording structure with reference to underlying socket */
|
/* Create recording structure with reference to underlying socket */
|
||||||
guac_recording* recording = malloc(sizeof(guac_recording));
|
guac_common_recording* recording = malloc(sizeof(guac_common_recording));
|
||||||
recording->socket = guac_socket_open(fd);
|
recording->socket = guac_socket_open(fd);
|
||||||
recording->include_output = include_output;
|
recording->include_output = include_output;
|
||||||
recording->include_mouse = include_mouse;
|
recording->include_mouse = include_mouse;
|
||||||
@ -183,7 +183,7 @@ guac_recording* guac_recording_create(guac_client* client,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_recording_free(guac_recording* recording) {
|
void guac_common_recording_free(guac_common_recording* recording) {
|
||||||
|
|
||||||
/* If not including broadcast output, the output socket is not associated
|
/* If not including broadcast output, the output socket is not associated
|
||||||
* with the client, and must be freed manually */
|
* with the client, and must be freed manually */
|
||||||
@ -195,7 +195,7 @@ void guac_recording_free(guac_recording* recording) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_recording_report_mouse(guac_recording* recording,
|
void guac_common_recording_report_mouse(guac_common_recording* recording,
|
||||||
int x, int y, int button_mask) {
|
int x, int y, int button_mask) {
|
||||||
|
|
||||||
/* Report mouse location only if recording should contain mouse events */
|
/* Report mouse location only if recording should contain mouse events */
|
||||||
@ -205,7 +205,7 @@ void guac_recording_report_mouse(guac_recording* recording,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_recording_report_touch(guac_recording* recording,
|
void guac_common_recording_report_touch(guac_common_recording* recording,
|
||||||
int id, int x, int y, int x_radius, int y_radius,
|
int id, int x, int y, int x_radius, int y_radius,
|
||||||
double angle, double force) {
|
double angle, double force) {
|
||||||
|
|
||||||
@ -216,7 +216,7 @@ void guac_recording_report_touch(guac_recording* recording,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_recording_report_key(guac_recording* recording,
|
void guac_common_recording_report_key(guac_common_recording* recording,
|
||||||
int keysym, int pressed) {
|
int keysym, int pressed) {
|
||||||
|
|
||||||
/* Report key state only if recording should contain key events */
|
/* Report key state only if recording should contain key events */
|
@ -1,115 +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-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
|
|
||||||
|
|
59
doc/libguac-terminal/Doxyfile.in → src/guacd-docker/bin/build-guacd.sh
Normal file → Executable file
59
doc/libguac-terminal/Doxyfile.in → src/guacd-docker/bin/build-guacd.sh
Normal file → Executable file
@ -1,3 +1,4 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
#
|
#
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
# or more contributor license agreements. See the NOTICE file
|
# or more contributor license agreements. See the NOTICE file
|
||||||
@ -17,42 +18,32 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
##
|
||||||
# Project name / version
|
## @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`.
|
||||||
|
##
|
||||||
|
|
||||||
PROJECT_NAME = libguac-terminal
|
BUILD_DIR="$1"
|
||||||
PROJECT_NUMBER = @PACKAGE_VERSION@
|
PREFIX_DIR="$2"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Warn about undocumented parameters and return values, but do not fill output
|
# Build guacamole-server
|
||||||
# with verbose progress info.
|
|
||||||
#
|
#
|
||||||
|
|
||||||
QUIET = YES
|
cd "$BUILD_DIR"
|
||||||
WARN_NO_PARAMDOC = YES
|
autoreconf -fi
|
||||||
|
./configure --prefix="$PREFIX_DIR" --disable-guaclog --with-freerdp-plugin-dir="$PREFIX_DIR/lib/freerdp2"
|
||||||
#
|
make
|
||||||
# Output format
|
make install
|
||||||
#
|
ldconfig
|
||||||
|
|
||||||
ALPHABETICAL_INDEX = YES
|
|
||||||
GENERATE_HTML = YES
|
|
||||||
GENERATE_LATEX = NO
|
|
||||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
|
||||||
OUTPUT_DIRECTORY = doxygen-output
|
|
||||||
RECURSIVE = YES
|
|
||||||
SHOW_INCLUDE_FILES = NO
|
|
||||||
|
|
||||||
#
|
|
||||||
# Input format
|
|
||||||
#
|
|
||||||
|
|
||||||
CASE_SENSE_NAMES = YES
|
|
||||||
FILE_PATTERNS = *.h
|
|
||||||
STRIP_FROM_PATH = ../../src/terminal
|
|
||||||
INPUT = ../../src/terminal/terminal/terminal.h
|
|
||||||
JAVADOC_AUTOBRIEF = YES
|
|
||||||
TAB_SIZE = 4
|
|
||||||
TYPEDEF_HIDES_STRUCT = YES
|
|
||||||
|
|
86
src/guacd-docker/bin/link-freerdp-plugins.sh
Executable file
86
src/guacd-docker/bin/link-freerdp-plugins.sh
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
#!/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.
|
||||||
|
##
|
||||||
|
|
||||||
|
##
|
||||||
|
## Given the full path to a FreeRDP plugin, locates the base directory of the
|
||||||
|
## associated 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.
|
||||||
|
##
|
||||||
|
## @param PLUGIN_FILE
|
||||||
|
## The full path to the FreeRDP plugin to check.
|
||||||
|
##
|
||||||
|
where_is_freerdp() {
|
||||||
|
|
||||||
|
PLUGIN_FILE="$1"
|
||||||
|
|
||||||
|
# Determine the location of all libfreerdp* libraries explicitly linked
|
||||||
|
# to given file
|
||||||
|
PATHS="$(ldd "$PLUGIN_FILE" \
|
||||||
|
| awk '/=>/{print $(NF-1)}' \
|
||||||
|
| grep 'libfreerdp' \
|
||||||
|
| xargs -r dirname \
|
||||||
|
| xargs -r realpath \
|
||||||
|
| sort -u)"
|
||||||
|
|
||||||
|
# Verify that exactly one location was found
|
||||||
|
if [ "$(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
|
||||||
|
#
|
||||||
|
|
||||||
|
while [ -n "$1" ]; do
|
||||||
|
|
||||||
|
# Determine correct install location for FreeRDP plugins
|
||||||
|
FREERDP_DIR="$(where_is_freerdp "$1")"
|
||||||
|
FREERDP_PLUGIN_DIR="${FREERDP_DIR}/freerdp2"
|
||||||
|
|
||||||
|
# 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
|
## @fn list-dependencies.sh
|
||||||
##
|
##
|
||||||
## Lists the Alpine Linux package names for all library dependencies of the
|
## Lists the Debian/Ubuntu package names for all library dependencies of the
|
||||||
## given binaries. Each package is only listed once, even if multiple binaries
|
## given binaries. Each package is only listed once, even if multiple binaries
|
||||||
## provided by the same package are given.
|
## provided by the same package are given.
|
||||||
##
|
##
|
||||||
@ -35,17 +35,14 @@ while [ -n "$1" ]; do
|
|||||||
ldd "$1" | grep -v 'libguac' | awk '/=>/{print $(NF-1)}' \
|
ldd "$1" | grep -v 'libguac' | awk '/=>/{print $(NF-1)}' \
|
||||||
| while read LIBRARY; do
|
| while read LIBRARY; do
|
||||||
|
|
||||||
# List the package providing that library, if any
|
# Determine the Debian package which is associated with that
|
||||||
apk info -W "$LIBRARY" 2> /dev/null \
|
# library, if any
|
||||||
| grep 'is owned by' | grep -o '[^ ]*$' || true
|
dpkg-query -S "$LIBRARY" 2> /dev/null || true
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
# Next binary
|
# Next binary
|
||||||
shift
|
shift
|
||||||
|
|
||||||
# Strip the "-VERSION" suffix from each package name, listing each resulting
|
done | cut -f1 -d: | sort -u
|
||||||
# package uniquely ("apk add" cannot handle package names that include the
|
|
||||||
# version number)
|
|
||||||
done | sed 's/\(.*\)-[0-9]\+\..*$/\1/' | sort -u
|
|
||||||
|
|
||||||
|
@ -381,15 +381,10 @@ int main(int argc, char* argv[]) {
|
|||||||
CRYPTO_set_locking_callback(guacd_openssl_locking_callback);
|
CRYPTO_set_locking_callback(guacd_openssl_locking_callback);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
/* Init SSL */
|
||||||
/* Init OpenSSL for OpenSSL Versions < 1.1.0 */
|
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
SSL_load_error_strings();
|
SSL_load_error_strings();
|
||||||
ssl_context = SSL_CTX_new(SSLv23_server_method());
|
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 */
|
/* Load key */
|
||||||
if (config->key_file != NULL) {
|
if (config->key_file != NULL) {
|
||||||
|
@ -213,7 +213,7 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* codec,
|
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec,
|
||||||
int bitrate, int width, int height, int gop_size, int qmax, int qmin,
|
int bitrate, int width, int height, int gop_size, int qmax, int qmin,
|
||||||
int pix_fmt, AVRational time_base) {
|
int pix_fmt, AVRational time_base) {
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* co
|
|||||||
}
|
}
|
||||||
|
|
||||||
int guacenc_open_avcodec(AVCodecContext *avcodec_context,
|
int guacenc_open_avcodec(AVCodecContext *avcodec_context,
|
||||||
const AVCodec *codec, AVDictionary **options,
|
AVCodec *codec, AVDictionary **options,
|
||||||
AVStream* stream) {
|
AVStream* stream) {
|
||||||
|
|
||||||
int ret = avcodec_open2(avcodec_context, codec, options);
|
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.
|
* The pointer to the configured AVCodecContext.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* codec,
|
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec,
|
||||||
int bitrate, int width, int height, int gop_size, int qmax, int qmin,
|
int bitrate, int width, int height, int gop_size, int qmax, int qmin,
|
||||||
int pix_fmt, AVRational time_base);
|
int pix_fmt, AVRational time_base);
|
||||||
|
|
||||||
@ -158,7 +158,7 @@ AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* co
|
|||||||
* Zero on success, a negative value on error.
|
* Zero on success, a negative value on error.
|
||||||
*/
|
*/
|
||||||
int guacenc_open_avcodec(AVCodecContext *avcodec_context,
|
int guacenc_open_avcodec(AVCodecContext *avcodec_context,
|
||||||
const AVCodec *codec, AVDictionary **options,
|
AVCodec *codec, AVDictionary **options,
|
||||||
AVStream* stream);
|
AVStream* stream);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
||||||
int width, int height, int bitrate) {
|
int width, int height, int bitrate) {
|
||||||
|
|
||||||
const AVOutputFormat *container_format;
|
AVOutputFormat *container_format;
|
||||||
AVFormatContext *container_format_context;
|
AVFormatContext *container_format_context;
|
||||||
AVStream *video_stream;
|
AVStream *video_stream;
|
||||||
int ret;
|
int ret;
|
||||||
@ -63,7 +63,7 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
|
|||||||
container_format = container_format_context->oformat;
|
container_format = container_format_context->oformat;
|
||||||
|
|
||||||
/* Pull codec based on name */
|
/* Pull codec based on name */
|
||||||
const AVCodec* codec = avcodec_find_encoder_by_name(codec_name);
|
AVCodec* codec = avcodec_find_encoder_by_name(codec_name);
|
||||||
if (codec == NULL) {
|
if (codec == NULL) {
|
||||||
guacenc_log(GUAC_LOG_ERROR, "Failed to locate codec \"%s\".",
|
guacenc_log(GUAC_LOG_ERROR, "Failed to locate codec \"%s\".",
|
||||||
codec_name);
|
codec_name);
|
||||||
|
@ -44,7 +44,6 @@ libguacinc_HEADERS = \
|
|||||||
guacamole/client-types.h \
|
guacamole/client-types.h \
|
||||||
guacamole/error.h \
|
guacamole/error.h \
|
||||||
guacamole/error-types.h \
|
guacamole/error-types.h \
|
||||||
guacamole/fips.h \
|
|
||||||
guacamole/hash.h \
|
guacamole/hash.h \
|
||||||
guacamole/layer.h \
|
guacamole/layer.h \
|
||||||
guacamole/layer-types.h \
|
guacamole/layer-types.h \
|
||||||
@ -60,7 +59,6 @@ libguacinc_HEADERS = \
|
|||||||
guacamole/protocol.h \
|
guacamole/protocol.h \
|
||||||
guacamole/protocol-constants.h \
|
guacamole/protocol-constants.h \
|
||||||
guacamole/protocol-types.h \
|
guacamole/protocol-types.h \
|
||||||
guacamole/recording.h \
|
|
||||||
guacamole/socket-constants.h \
|
guacamole/socket-constants.h \
|
||||||
guacamole/socket.h \
|
guacamole/socket.h \
|
||||||
guacamole/socket-fntypes.h \
|
guacamole/socket-fntypes.h \
|
||||||
@ -94,7 +92,6 @@ libguac_la_SOURCES = \
|
|||||||
encode-jpeg.c \
|
encode-jpeg.c \
|
||||||
encode-png.c \
|
encode-png.c \
|
||||||
error.c \
|
error.c \
|
||||||
fips.c \
|
|
||||||
hash.c \
|
hash.c \
|
||||||
id.c \
|
id.c \
|
||||||
palette.c \
|
palette.c \
|
||||||
@ -102,7 +99,6 @@ libguac_la_SOURCES = \
|
|||||||
pool.c \
|
pool.c \
|
||||||
protocol.c \
|
protocol.c \
|
||||||
raw_encoder.c \
|
raw_encoder.c \
|
||||||
recording.c \
|
|
||||||
socket.c \
|
socket.c \
|
||||||
socket-broadcast.c \
|
socket-broadcast.c \
|
||||||
socket-fd.c \
|
socket-fd.c \
|
||||||
@ -139,7 +135,7 @@ libguac_la_CFLAGS = \
|
|||||||
-Werror -Wall -pedantic
|
-Werror -Wall -pedantic
|
||||||
|
|
||||||
libguac_la_LDFLAGS = \
|
libguac_la_LDFLAGS = \
|
||||||
-version-info 21:0:0 \
|
-version-info 20:0:0 \
|
||||||
-no-undefined \
|
-no-undefined \
|
||||||
@CAIRO_LIBS@ \
|
@CAIRO_LIBS@ \
|
||||||
@DL_LIBS@ \
|
@DL_LIBS@ \
|
||||||
|
@ -307,10 +307,6 @@ int guac_client_add_user(guac_client* client, guac_user* user, int argc, char**
|
|||||||
|
|
||||||
pthread_rwlock_unlock(&(client->__users_lock));
|
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;
|
return retval;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -337,10 +333,6 @@ void guac_client_remove_user(guac_client* client, guac_user* user) {
|
|||||||
|
|
||||||
pthread_rwlock_unlock(&(client->__users_lock));
|
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 */
|
/* Call handler, if defined */
|
||||||
if (user->leave_handler)
|
if (user->leave_handler)
|
||||||
user->leave_handler(user);
|
user->leave_handler(user);
|
||||||
@ -421,19 +413,15 @@ void* guac_client_for_user(guac_client* client, guac_user* user,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int guac_client_end_frame(guac_client* client) {
|
int guac_client_end_frame(guac_client* client) {
|
||||||
return guac_client_end_multiple_frames(client, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int guac_client_end_multiple_frames(guac_client* client, int frames) {
|
|
||||||
|
|
||||||
/* Update and send timestamp */
|
/* Update and send timestamp */
|
||||||
client->last_sent_timestamp = guac_timestamp_current();
|
client->last_sent_timestamp = guac_timestamp_current();
|
||||||
|
|
||||||
/* Log received timestamp and calculated lag (at TRACE level only) */
|
/* Log received timestamp and calculated lag (at TRACE level only) */
|
||||||
guac_client_log(client, GUAC_LOG_TRACE, "Server completed "
|
guac_client_log(client, GUAC_LOG_TRACE, "Server completed "
|
||||||
"frame %" PRIu64 "ms (%i logical frames)", client->last_sent_timestamp, frames);
|
"frame %" PRIu64 "ms.", client->last_sent_timestamp);
|
||||||
|
|
||||||
return guac_protocol_send_sync(client->socket, client->last_sent_timestamp, frames);
|
return guac_protocol_send_sync(client->socket, client->last_sent_timestamp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,36 +671,6 @@ static void* __webp_support_callback(guac_user* user, void* data) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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()
|
* A callback function which is invoked by guac_client_owner_supports_required()
|
||||||
* to determine if the owner of a client supports the "required" instruction,
|
* to determine if the owner of a client supports the "required" instruction,
|
||||||
@ -743,124 +701,6 @@ 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) {
|
int guac_client_supports_webp(guac_client* client) {
|
||||||
|
|
||||||
#ifdef ENABLE_WEBP
|
#ifdef ENABLE_WEBP
|
||||||
|
@ -1,51 +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 "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;
|
|
||||||
|
|
||||||
}
|
|
@ -509,47 +509,18 @@ void* guac_client_for_user(guac_client* client, guac_user* user,
|
|||||||
guac_user_callback* callback, void* data);
|
guac_user_callback* callback, void* data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the end of the current frame by sending a "sync" instruction to all
|
* Marks the end of the current frame by sending a "sync" instruction to
|
||||||
* connected users, where the number of input frames that were considered in
|
* all connected users. This instruction will contain the current timestamp.
|
||||||
* creating this frame is either unknown or inapplicable. This instruction will
|
* The last_sent_timestamp member of guac_client will be updated accordingly.
|
||||||
* contain the current timestamp. The last_sent_timestamp member of guac_client
|
|
||||||
* will be updated accordingly.
|
|
||||||
*
|
*
|
||||||
* If an error occurs sending the instruction, a non-zero value is
|
* If an error occurs sending the instruction, a non-zero value is
|
||||||
* returned, and guac_error is set appropriately.
|
* returned, and guac_error is set appropriately.
|
||||||
*
|
*
|
||||||
* @param client
|
* @param client The guac_client which has finished a frame.
|
||||||
* The guac_client which has finished a frame.
|
* @return Zero on success, non-zero on error.
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* Zero on success, non-zero on error.
|
|
||||||
*/
|
*/
|
||||||
int guac_client_end_frame(guac_client* client);
|
int guac_client_end_frame(guac_client* client);
|
||||||
|
|
||||||
/**
|
|
||||||
* Marks the end of the current frame by sending a "sync" instruction to all
|
|
||||||
* connected users, where that frame may combine or otherwise represent the
|
|
||||||
* changes of an arbitrary number of input frames. This instruction will
|
|
||||||
* contain the current timestamp, as well as the number of frames that were
|
|
||||||
* considered in creating that frame. The last_sent_timestamp member of
|
|
||||||
* guac_client will be updated accordingly.
|
|
||||||
*
|
|
||||||
* If an error occurs sending the instruction, a non-zero value is
|
|
||||||
* returned, and guac_error is set appropriately.
|
|
||||||
*
|
|
||||||
* @param client
|
|
||||||
* The guac_client which has finished a frame.
|
|
||||||
*
|
|
||||||
* @param frames
|
|
||||||
* The number of distinct frames that were considered or combined when
|
|
||||||
* generating the current frame, or zero if the boundaries of relevant
|
|
||||||
* frames are unknown.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* Zero on success, non-zero on error.
|
|
||||||
*/
|
|
||||||
int guac_client_end_multiple_frames(guac_client* client, int frames);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the given guac_client using the initialization routine provided
|
* Initializes the given guac_client using the initialization routine provided
|
||||||
* by the plugin corresponding to the named protocol. This will automatically
|
* by the plugin corresponding to the named protocol. This will automatically
|
||||||
@ -737,21 +708,6 @@ void guac_client_stream_webp(guac_client* client, guac_socket* socket,
|
|||||||
guac_composite_mode mode, const guac_layer* layer, int x, int y,
|
guac_composite_mode mode, const guac_layer* layer, int x, int y,
|
||||||
cairo_surface_t* surface, int quality, int lossless);
|
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"
|
* Returns whether the owner of the given client supports the "required"
|
||||||
* instruction, returning non-zero if the client owner does support the
|
* instruction, returning non-zero if the client owner does support the
|
||||||
@ -767,42 +723,6 @@ int guac_client_owner_supports_msg(guac_client* client);
|
|||||||
*/
|
*/
|
||||||
int guac_client_owner_supports_required(guac_client* client);
|
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
|
* 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.
|
* not support WebP, or the server cannot encode WebP images, zero is returned.
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
* This version is passed by the __guac_protocol_send_args() function from the
|
* This version is passed by the __guac_protocol_send_args() function from the
|
||||||
* server to the client during the client/server handshake.
|
* server to the client during the client/server handshake.
|
||||||
*/
|
*/
|
||||||
#define GUACAMOLE_PROTOCOL_VERSION "VERSION_1_5_0"
|
#define GUACAMOLE_PROTOCOL_VERSION "VERSION_1_3_0"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum number of bytes that should be sent in any one blob instruction
|
* The maximum number of bytes that should be sent in any one blob instruction
|
||||||
|
@ -306,40 +306,9 @@ typedef enum guac_protocol_version {
|
|||||||
* allowing connections in guacd to request information from the client and
|
* allowing connections in guacd to request information from the client and
|
||||||
* await a response.
|
* 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;
|
} 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
|
#endif
|
||||||
|
|
||||||
|
@ -171,27 +171,6 @@ int guac_protocol_send_log(guac_socket* socket, const char* format, ...);
|
|||||||
int vguac_protocol_send_log(guac_socket* socket, const char* format,
|
int vguac_protocol_send_log(guac_socket* socket, const char* format,
|
||||||
va_list args);
|
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.
|
* Sends a mouse instruction over the given guac_socket connection.
|
||||||
*
|
*
|
||||||
@ -384,22 +363,11 @@ int guac_protocol_send_select(guac_socket* socket, const char* protocol);
|
|||||||
* If an error occurs sending the instruction, a non-zero value is
|
* If an error occurs sending the instruction, a non-zero value is
|
||||||
* returned, and guac_error is set appropriately.
|
* returned, and guac_error is set appropriately.
|
||||||
*
|
*
|
||||||
* @param socket
|
* @param socket The guac_socket connection to use.
|
||||||
* The guac_socket connection to use.
|
* @param timestamp The current timestamp (in milliseconds).
|
||||||
*
|
* @return Zero on success, non-zero on error.
|
||||||
* @param timestamp
|
|
||||||
* The current timestamp (in milliseconds).
|
|
||||||
*
|
|
||||||
* @param frames
|
|
||||||
* The number of distinct frames that were considered or combined when
|
|
||||||
* generating the frame terminated by this instruction, or zero if the
|
|
||||||
* boundaries of relevant frames are unknown.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* Zero on success, non-zero on error.
|
|
||||||
*/
|
*/
|
||||||
int guac_protocol_send_sync(guac_socket* socket, guac_timestamp timestamp,
|
int guac_protocol_send_sync(guac_socket* socket, guac_timestamp timestamp);
|
||||||
int frames);
|
|
||||||
|
|
||||||
/* OBJECT INSTRUCTIONS */
|
/* OBJECT INSTRUCTIONS */
|
||||||
|
|
||||||
|
@ -109,28 +109,6 @@ size_t guac_strlcpy(char* restrict dest, const char* restrict src, size_t n);
|
|||||||
*/
|
*/
|
||||||
size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n);
|
size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n);
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for the null-terminated string needle in the possibly null-
|
|
||||||
* terminated haystack, looking at no more than len bytes.
|
|
||||||
*
|
|
||||||
* @param haystack
|
|
||||||
* The string to search. It may or may not be null-terminated. Only the
|
|
||||||
* first len bytes are searched.
|
|
||||||
*
|
|
||||||
* @param needle
|
|
||||||
* The string to look for. It must be null-terminated.
|
|
||||||
*
|
|
||||||
* @param len
|
|
||||||
* The maximum number of bytes to examine in haystack.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* A pointer to the first instance of needle within haystack, or NULL if
|
|
||||||
* needle does not exist in haystack. If needle is the empty string,
|
|
||||||
* haystack is returned.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
char* guac_strnstr(const char *haystack, const char *needle, size_t len);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple wrapper for strdup() which behaves identically to standard strdup(),
|
* Simple wrapper for strdup() which behaves identically to standard strdup(),
|
||||||
* except that NULL will be returned if the provided string is NULL.
|
* except that NULL will be returned if the provided string is NULL.
|
||||||
|
@ -88,7 +88,7 @@ struct guac_user_info {
|
|||||||
* stated resolution of the display size request is recommended.
|
* stated resolution of the display size request is recommended.
|
||||||
*/
|
*/
|
||||||
int optimal_resolution;
|
int optimal_resolution;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The timezone of the remote system. If the client does not provide
|
* The timezone of the remote system. If the client does not provide
|
||||||
* a specific timezone then this will be NULL. The format of the timezone
|
* a specific timezone then this will be NULL. The format of the timezone
|
||||||
@ -102,14 +102,6 @@ struct guac_user_info {
|
|||||||
*/
|
*/
|
||||||
guac_protocol_version protocol_version;
|
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 {
|
struct guac_user {
|
||||||
@ -858,17 +850,6 @@ void guac_user_stream_webp(guac_user* user, guac_socket* socket,
|
|||||||
guac_composite_mode mode, const guac_layer* layer, int x, int y,
|
guac_composite_mode mode, const guac_layer* layer, int x, int y,
|
||||||
cairo_surface_t* surface, int quality, int lossless);
|
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.
|
* Returns whether the given user supports the "required" instruction.
|
||||||
*
|
*
|
||||||
|
@ -65,7 +65,6 @@ guac_protocol_version_mapping guac_protocol_version_table[] = {
|
|||||||
{ GUAC_PROTOCOL_VERSION_1_0_0, "VERSION_1_0_0" },
|
{ GUAC_PROTOCOL_VERSION_1_0_0, "VERSION_1_0_0" },
|
||||||
{ GUAC_PROTOCOL_VERSION_1_1_0, "VERSION_1_1_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_3_0, "VERSION_1_3_0" },
|
||||||
{ GUAC_PROTOCOL_VERSION_1_5_0, "VERSION_1_5_0" },
|
|
||||||
{ GUAC_PROTOCOL_VERSION_UNKNOWN, NULL }
|
{ GUAC_PROTOCOL_VERSION_UNKNOWN, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -659,23 +658,6 @@ 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,
|
int guac_protocol_send_file(guac_socket* socket, const guac_stream* stream,
|
||||||
const char* mimetype, const char* name) {
|
const char* mimetype, const char* name) {
|
||||||
|
|
||||||
@ -1199,8 +1181,7 @@ int guac_protocol_send_start(guac_socket* socket, const guac_layer* layer,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int guac_protocol_send_sync(guac_socket* socket, guac_timestamp timestamp,
|
int guac_protocol_send_sync(guac_socket* socket, guac_timestamp timestamp) {
|
||||||
int frames) {
|
|
||||||
|
|
||||||
int ret_val;
|
int ret_val;
|
||||||
|
|
||||||
@ -1208,8 +1189,6 @@ int guac_protocol_send_sync(guac_socket* socket, guac_timestamp timestamp,
|
|||||||
ret_val =
|
ret_val =
|
||||||
guac_socket_write_string(socket, "4.sync,")
|
guac_socket_write_string(socket, "4.sync,")
|
||||||
|| __guac_socket_write_length_int(socket, timestamp)
|
|| __guac_socket_write_length_int(socket, timestamp)
|
||||||
|| guac_socket_write_string(socket, ",")
|
|
||||||
|| __guac_socket_write_length_int(socket, frames)
|
|
||||||
|| guac_socket_write_string(socket, ";");
|
|| guac_socket_write_string(socket, ";");
|
||||||
|
|
||||||
guac_socket_instruction_end(socket);
|
guac_socket_instruction_end(socket);
|
||||||
|
@ -81,38 +81,6 @@ size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* guac_strnstr(const char *haystack, const char *needle, size_t len) {
|
|
||||||
|
|
||||||
#ifdef HAVE_STRNSTR
|
|
||||||
return strnstr(haystack, needle, len);
|
|
||||||
#else
|
|
||||||
char* chr;
|
|
||||||
size_t nlen = strlen(needle), off = 0;
|
|
||||||
|
|
||||||
/* Follow documented API: return haystack if needle is the empty string. */
|
|
||||||
if (nlen == 0)
|
|
||||||
return (char *)haystack;
|
|
||||||
|
|
||||||
/* Use memchr to find candidates. It might be optimized in asm. */
|
|
||||||
while (off < len && NULL != (chr = memchr(haystack + off, needle[0], len - off))) {
|
|
||||||
/* chr is guaranteed to be in bounds of and >= haystack. */
|
|
||||||
off = chr - haystack;
|
|
||||||
/* If needle would go beyond provided len, it doesn't exist in haystack. */
|
|
||||||
if (off + nlen > len)
|
|
||||||
return NULL;
|
|
||||||
/* Now that we know we have at least nlen bytes, compare them. */
|
|
||||||
if (!memcmp(chr, needle, nlen))
|
|
||||||
return chr;
|
|
||||||
/* Make sure we make progress. */
|
|
||||||
off += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* memchr ran out of candidates, needle wasn't found. */
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
char* guac_strdup(const char* str) {
|
char* guac_strdup(const char* str) {
|
||||||
|
|
||||||
/* Return NULL if no string provided */
|
/* Return NULL if no string provided */
|
||||||
|
@ -48,7 +48,6 @@ test_libguac_SOURCES = \
|
|||||||
string/strlcat.c \
|
string/strlcat.c \
|
||||||
string/strlcpy.c \
|
string/strlcpy.c \
|
||||||
string/strljoin.c \
|
string/strljoin.c \
|
||||||
string/strnstr.c \
|
|
||||||
unicode/charsize.c \
|
unicode/charsize.c \
|
||||||
unicode/read.c \
|
unicode/read.c \
|
||||||
unicode/strlen.c \
|
unicode/strlen.c \
|
||||||
|
@ -27,11 +27,11 @@
|
|||||||
*/
|
*/
|
||||||
void test_guac_protocol__version_to_string() {
|
void test_guac_protocol__version_to_string() {
|
||||||
|
|
||||||
guac_protocol_version version_a = GUAC_PROTOCOL_VERSION_1_5_0;
|
guac_protocol_version version_a = GUAC_PROTOCOL_VERSION_1_3_0;
|
||||||
guac_protocol_version version_b = GUAC_PROTOCOL_VERSION_1_0_0;
|
guac_protocol_version version_b = GUAC_PROTOCOL_VERSION_1_0_0;
|
||||||
guac_protocol_version version_c = GUAC_PROTOCOL_VERSION_UNKNOWN;
|
guac_protocol_version version_c = GUAC_PROTOCOL_VERSION_UNKNOWN;
|
||||||
|
|
||||||
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_a), "VERSION_1_3_0");
|
||||||
CU_ASSERT_STRING_EQUAL(guac_protocol_version_to_string(version_b), "VERSION_1_0_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));
|
CU_ASSERT_PTR_NULL(guac_protocol_version_to_string(version_c));
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ static void write_instructions(int fd) {
|
|||||||
|
|
||||||
/* Write instructions */
|
/* Write instructions */
|
||||||
guac_protocol_send_name(socket, "a" UTF8_4 "b" UTF8_4 "c");
|
guac_protocol_send_name(socket, "a" UTF8_4 "b" UTF8_4 "c");
|
||||||
guac_protocol_send_sync(socket, 12345, 1);
|
guac_protocol_send_sync(socket, 12345);
|
||||||
guac_socket_flush(socket);
|
guac_socket_flush(socket);
|
||||||
|
|
||||||
/* Close and free socket */
|
/* Close and free socket */
|
||||||
@ -76,7 +76,7 @@ static void read_expected_instructions(int fd) {
|
|||||||
|
|
||||||
char expected[] =
|
char expected[] =
|
||||||
"4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
|
"4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
|
||||||
"4.sync,5.12345,1.1;";
|
"4.sync,5.12345;";
|
||||||
|
|
||||||
int numread;
|
int numread;
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
|
@ -65,7 +65,7 @@ static void write_instructions(int fd) {
|
|||||||
|
|
||||||
/* Write instructions */
|
/* Write instructions */
|
||||||
guac_protocol_send_name(nested_socket, "a" UTF8_4 "b" UTF8_4 "c");
|
guac_protocol_send_name(nested_socket, "a" UTF8_4 "b" UTF8_4 "c");
|
||||||
guac_protocol_send_sync(nested_socket, 12345, 1);
|
guac_protocol_send_sync(nested_socket, 12345);
|
||||||
|
|
||||||
/* Close and free sockets */
|
/* Close and free sockets */
|
||||||
guac_socket_free(nested_socket);
|
guac_socket_free(nested_socket);
|
||||||
@ -86,9 +86,9 @@ static void write_instructions(int fd) {
|
|||||||
static void read_expected_instructions(int fd) {
|
static void read_expected_instructions(int fd) {
|
||||||
|
|
||||||
char expected[] =
|
char expected[] =
|
||||||
"4.nest,3.123,41."
|
"4.nest,3.123,37."
|
||||||
"4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
|
"4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
|
||||||
"4.sync,5.12345,1.1;"
|
"4.sync,5.12345;"
|
||||||
";";
|
";";
|
||||||
|
|
||||||
int numread;
|
int numread;
|
||||||
|
@ -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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <CUnit/CUnit.h>
|
|
||||||
#include <guacamole/string.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify guac_strnstr() behaviors:
|
|
||||||
*/
|
|
||||||
void test_string__strnstr() {
|
|
||||||
char haystack[8] = {'a', 'h', 'i', ' ', 't', 'u', 'n', 'a'};
|
|
||||||
char* result;
|
|
||||||
|
|
||||||
/* needle exists at start of haystack */
|
|
||||||
result = guac_strnstr(haystack, "ah", sizeof(haystack));
|
|
||||||
CU_ASSERT_EQUAL(result, haystack);
|
|
||||||
|
|
||||||
/* needle exists in the middle of haystack */
|
|
||||||
result = guac_strnstr(haystack, "hi", sizeof(haystack));
|
|
||||||
CU_ASSERT_EQUAL(result, haystack + 1);
|
|
||||||
|
|
||||||
/* needle exists at end of haystack */
|
|
||||||
result = guac_strnstr(haystack, "tuna", sizeof(haystack));
|
|
||||||
CU_ASSERT_EQUAL(result, haystack + 4);
|
|
||||||
|
|
||||||
/* needle doesn't exist in haystack, needle[0] isn't in haystack */
|
|
||||||
result = guac_strnstr(haystack, "mahi", sizeof(haystack));
|
|
||||||
CU_ASSERT_EQUAL(result, NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* needle doesn't exist in haystack, needle[0] is in haystack,
|
|
||||||
* length wouldn't allow needle to exist
|
|
||||||
*/
|
|
||||||
result = guac_strnstr(haystack, "narwhal", sizeof(haystack));
|
|
||||||
CU_ASSERT_EQUAL(result, NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* needle doesn't exist in haystack, needle[0] is in haystack,
|
|
||||||
* length would allow needle to exist
|
|
||||||
*/
|
|
||||||
result = guac_strnstr(haystack, "taco", sizeof(haystack));
|
|
||||||
CU_ASSERT_EQUAL(result, NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* needle doesn't exist in haystack, needle[0] is in haystack
|
|
||||||
* multiple times
|
|
||||||
*/
|
|
||||||
result = guac_strnstr(haystack, "ahha", sizeof(haystack));
|
|
||||||
CU_ASSERT_EQUAL(result, NULL);
|
|
||||||
|
|
||||||
/* empty needle should return haystack according to API docs */
|
|
||||||
result = guac_strnstr(haystack, "", sizeof(haystack));
|
|
||||||
CU_ASSERT_EQUAL(result, haystack);
|
|
||||||
}
|
|
@ -64,7 +64,6 @@ __guac_instruction_handler_mapping __guac_handshake_handler_map[] = {
|
|||||||
{"video", __guac_handshake_video_handler},
|
{"video", __guac_handshake_video_handler},
|
||||||
{"image", __guac_handshake_image_handler},
|
{"image", __guac_handshake_image_handler},
|
||||||
{"timezone", __guac_handshake_timezone_handler},
|
{"timezone", __guac_handshake_timezone_handler},
|
||||||
{"name", __guac_handshake_name_handler},
|
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,39 +120,31 @@ int __guac_handle_sync(guac_user* user, int argc, char** argv) {
|
|||||||
/* Calculate length of frame, including network and processing lag */
|
/* Calculate length of frame, including network and processing lag */
|
||||||
frame_duration = current - timestamp;
|
frame_duration = current - timestamp;
|
||||||
|
|
||||||
/* Calculate processing lag portion of length of frame */
|
/* Update lag statistics if at least one frame has been rendered */
|
||||||
int frame_processing_lag = 0;
|
|
||||||
if (user->last_frame_duration != 0) {
|
if (user->last_frame_duration != 0) {
|
||||||
|
|
||||||
/* Calculate lag using the previous frame as a baseline */
|
/* Calculate lag using the previous frame as a baseline */
|
||||||
frame_processing_lag = frame_duration - user->last_frame_duration;
|
int processing_lag = frame_duration - user->last_frame_duration;
|
||||||
|
|
||||||
/* Adjust back to zero if cumulative error leads to a negative
|
/* Adjust back to zero if cumulative error leads to a negative
|
||||||
* value */
|
* value */
|
||||||
if (frame_processing_lag < 0)
|
if (processing_lag < 0)
|
||||||
frame_processing_lag = 0;
|
processing_lag = 0;
|
||||||
|
|
||||||
|
user->processing_lag = processing_lag;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record baseline duration of frame by excluding lag (this is the
|
/* Record baseline duration of frame by excluding lag */
|
||||||
* network round-trip time) */
|
user->last_frame_duration = frame_duration - user->processing_lag;
|
||||||
int estimated_rtt = frame_duration - frame_processing_lag;
|
|
||||||
user->last_frame_duration = estimated_rtt;
|
|
||||||
|
|
||||||
/* Calculate cumulative accumulated processing lag relative to server timeline */
|
|
||||||
int processing_lag = current - user->last_received_timestamp - estimated_rtt;
|
|
||||||
if (processing_lag < 0)
|
|
||||||
processing_lag = 0;
|
|
||||||
|
|
||||||
user->processing_lag = processing_lag;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Log received timestamp and calculated lag (at TRACE level only) */
|
/* Log received timestamp and calculated lag (at TRACE level only) */
|
||||||
guac_user_log(user, GUAC_LOG_TRACE,
|
guac_user_log(user, GUAC_LOG_TRACE,
|
||||||
"User confirmation of frame %" PRIu64 "ms received "
|
"User confirmation of frame %" PRIu64 "ms received "
|
||||||
"at %" PRIu64 "ms (processing_lag=%ims, estimated_rtt=%ims)",
|
"at %" PRIu64 "ms (processing_lag=%ims)",
|
||||||
timestamp, current, user->processing_lag, user->last_frame_duration);
|
timestamp, current, user->processing_lag);
|
||||||
|
|
||||||
if (user->sync_handler)
|
if (user->sync_handler)
|
||||||
return user->sync_handler(user, timestamp);
|
return user->sync_handler(user, timestamp);
|
||||||
@ -685,23 +676,6 @@ 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) {
|
int __guac_handshake_timezone_handler(guac_user* user, int argc, char** argv) {
|
||||||
|
|
||||||
/* Free any past value */
|
/* Free any past value */
|
||||||
|
@ -218,13 +218,6 @@ __guac_instruction_handler __guac_handshake_video_handler;
|
|||||||
*/
|
*/
|
||||||
__guac_instruction_handler __guac_handshake_image_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
|
* Internal handler function that is called when the timezone instruction is
|
||||||
* received during the handshake process, specifying the timezone of the
|
* received during the handshake process, specifying the timezone of the
|
||||||
|
@ -296,7 +296,6 @@ int guac_user_handle_connection(guac_user* user, int usec_timeout) {
|
|||||||
user->info.audio_mimetypes = NULL;
|
user->info.audio_mimetypes = NULL;
|
||||||
user->info.image_mimetypes = NULL;
|
user->info.image_mimetypes = NULL;
|
||||||
user->info.video_mimetypes = NULL;
|
user->info.video_mimetypes = NULL;
|
||||||
user->info.name = NULL;
|
|
||||||
user->info.timezone = NULL;
|
user->info.timezone = NULL;
|
||||||
|
|
||||||
/* Count number of arguments. */
|
/* Count number of arguments. */
|
||||||
@ -371,8 +370,7 @@ 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.image_mimetypes);
|
||||||
guac_free_mimetypes((char **) user->info.video_mimetypes);
|
guac_free_mimetypes((char **) user->info.video_mimetypes);
|
||||||
|
|
||||||
/* Free name and timezone info. */
|
/* Free timezone info. */
|
||||||
free((char *) user->info.name);
|
|
||||||
free((char *) user->info.timezone);
|
free((char *) user->info.timezone);
|
||||||
|
|
||||||
guac_parser_free(parser);
|
guac_parser_free(parser);
|
||||||
|
@ -316,15 +316,6 @@ 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) {
|
int guac_user_supports_required(guac_user* user) {
|
||||||
|
|
||||||
if (user == NULL)
|
if (user == NULL)
|
||||||
|
@ -53,9 +53,8 @@ int guac_kubernetes_argv_callback(guac_user* user, const char* mimetype,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update Kubernetes terminal size */
|
/* Update Kubernetes terminal size */
|
||||||
guac_kubernetes_resize(client,
|
guac_kubernetes_resize(client, terminal->term_height,
|
||||||
guac_terminal_get_rows(terminal),
|
terminal->term_width);
|
||||||
guac_terminal_get_columns(terminal));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -68,20 +67,20 @@ void* guac_kubernetes_send_current_argv(guac_user* user, void* data) {
|
|||||||
|
|
||||||
/* Send current color scheme */
|
/* Send current color scheme */
|
||||||
guac_user_stream_argv(user, user->socket, "text/plain",
|
guac_user_stream_argv(user, user->socket, "text/plain",
|
||||||
GUAC_KUBERNETES_ARGV_COLOR_SCHEME,
|
GUAC_KUBERNETES_ARGV_COLOR_SCHEME, terminal->color_scheme);
|
||||||
guac_terminal_get_color_scheme(terminal));
|
|
||||||
|
|
||||||
/* Send current font name */
|
/* Send current font name */
|
||||||
guac_user_stream_argv(user, user->socket, "text/plain",
|
guac_user_stream_argv(user, user->socket, "text/plain",
|
||||||
GUAC_KUBERNETES_ARGV_FONT_NAME,
|
GUAC_KUBERNETES_ARGV_FONT_NAME, terminal->font_name);
|
||||||
guac_terminal_get_font_name(terminal));
|
|
||||||
|
|
||||||
/* Send current font size */
|
/* Send current font size */
|
||||||
char font_size[64];
|
char font_size[64];
|
||||||
sprintf(font_size, "%i", guac_terminal_get_font_size(terminal));
|
sprintf(font_size, "%i", terminal->font_size);
|
||||||
guac_user_stream_argv(user, user->socket, "text/plain",
|
guac_user_stream_argv(user, user->socket, "text/plain",
|
||||||
GUAC_KUBERNETES_ARGV_FONT_SIZE, font_size);
|
GUAC_KUBERNETES_ARGV_FONT_SIZE, font_size);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "argv.h"
|
#include "argv.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
#include "common/clipboard.h"
|
||||||
#include "kubernetes.h"
|
#include "kubernetes.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "user.h"
|
#include "user.h"
|
||||||
@ -94,6 +95,9 @@ int guac_client_init(guac_client* client) {
|
|||||||
guac_kubernetes_client* kubernetes_client = calloc(1, sizeof(guac_kubernetes_client));
|
guac_kubernetes_client* kubernetes_client = calloc(1, sizeof(guac_kubernetes_client));
|
||||||
client->data = kubernetes_client;
|
client->data = kubernetes_client;
|
||||||
|
|
||||||
|
/* Init clipboard */
|
||||||
|
kubernetes_client->clipboard = guac_common_clipboard_alloc(GUAC_KUBERNETES_CLIPBOARD_MAX_LENGTH);
|
||||||
|
|
||||||
/* Set handlers */
|
/* Set handlers */
|
||||||
client->join_handler = guac_kubernetes_user_join_handler;
|
client->join_handler = guac_kubernetes_user_join_handler;
|
||||||
client->free_handler = guac_kubernetes_client_free_handler;
|
client->free_handler = guac_kubernetes_client_free_handler;
|
||||||
@ -129,6 +133,7 @@ int guac_kubernetes_client_free_handler(guac_client* client) {
|
|||||||
if (kubernetes_client->settings != NULL)
|
if (kubernetes_client->settings != NULL)
|
||||||
guac_kubernetes_settings_free(kubernetes_client->settings);
|
guac_kubernetes_settings_free(kubernetes_client->settings);
|
||||||
|
|
||||||
|
guac_common_clipboard_free(kubernetes_client->clipboard);
|
||||||
free(kubernetes_client);
|
free(kubernetes_client);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -22,6 +22,11 @@
|
|||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of bytes to allow within the clipboard.
|
||||||
|
*/
|
||||||
|
#define GUAC_KUBERNETES_CLIPBOARD_MAX_LENGTH 262144
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static reference to the guac_client associated with the active Kubernetes
|
* Static reference to the guac_client associated with the active Kubernetes
|
||||||
* connection. While libwebsockets provides some means of storing and
|
* connection. While libwebsockets provides some means of storing and
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "clipboard.h"
|
#include "clipboard.h"
|
||||||
|
#include "common/clipboard.h"
|
||||||
#include "kubernetes.h"
|
#include "kubernetes.h"
|
||||||
#include "terminal/terminal.h"
|
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/stream.h>
|
#include <guacamole/stream.h>
|
||||||
@ -33,7 +33,7 @@ int guac_kubernetes_clipboard_handler(guac_user* user, guac_stream* stream,
|
|||||||
(guac_kubernetes_client*) client->data;
|
(guac_kubernetes_client*) client->data;
|
||||||
|
|
||||||
/* Clear clipboard and prepare for new data */
|
/* Clear clipboard and prepare for new data */
|
||||||
guac_terminal_clipboard_reset(kubernetes_client->term, mimetype);
|
guac_common_clipboard_reset(kubernetes_client->clipboard, mimetype);
|
||||||
|
|
||||||
/* Set handlers for clipboard stream */
|
/* Set handlers for clipboard stream */
|
||||||
stream->blob_handler = guac_kubernetes_clipboard_blob_handler;
|
stream->blob_handler = guac_kubernetes_clipboard_blob_handler;
|
||||||
@ -50,7 +50,7 @@ int guac_kubernetes_clipboard_blob_handler(guac_user* user,
|
|||||||
(guac_kubernetes_client*) client->data;
|
(guac_kubernetes_client*) client->data;
|
||||||
|
|
||||||
/* Append new data */
|
/* Append new data */
|
||||||
guac_terminal_clipboard_append(kubernetes_client->term, data, length);
|
guac_common_clipboard_append(kubernetes_client->clipboard, data, length);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "common/recording.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "kubernetes.h"
|
#include "kubernetes.h"
|
||||||
#include "terminal/terminal.h"
|
#include "terminal/terminal.h"
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/recording.h>
|
|
||||||
#include <guacamole/user.h>
|
#include <guacamole/user.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -41,7 +41,7 @@ int guac_kubernetes_user_mouse_handler(guac_user* user,
|
|||||||
|
|
||||||
/* Report mouse position within recording */
|
/* Report mouse position within recording */
|
||||||
if (kubernetes_client->recording != NULL)
|
if (kubernetes_client->recording != NULL)
|
||||||
guac_recording_report_mouse(kubernetes_client->recording, x, y,
|
guac_common_recording_report_mouse(kubernetes_client->recording, x, y,
|
||||||
mask);
|
mask);
|
||||||
|
|
||||||
guac_terminal_send_mouse(term, user, x, y, mask);
|
guac_terminal_send_mouse(term, user, x, y, mask);
|
||||||
@ -57,7 +57,7 @@ int guac_kubernetes_user_key_handler(guac_user* user, int keysym, int pressed) {
|
|||||||
|
|
||||||
/* Report key state within recording */
|
/* Report key state within recording */
|
||||||
if (kubernetes_client->recording != NULL)
|
if (kubernetes_client->recording != NULL)
|
||||||
guac_recording_report_key(kubernetes_client->recording,
|
guac_common_recording_report_key(kubernetes_client->recording,
|
||||||
keysym, pressed);
|
keysym, pressed);
|
||||||
|
|
||||||
/* Skip if terminal not yet ready */
|
/* Skip if terminal not yet ready */
|
||||||
@ -86,9 +86,8 @@ int guac_kubernetes_user_size_handler(guac_user* user, int width, int height) {
|
|||||||
guac_terminal_resize(terminal, width, height);
|
guac_terminal_resize(terminal, width, height);
|
||||||
|
|
||||||
/* Update Kubernetes terminal window size if connected */
|
/* Update Kubernetes terminal window size if connected */
|
||||||
guac_kubernetes_resize(client,
|
guac_kubernetes_resize(client, terminal->term_height,
|
||||||
guac_terminal_get_rows(terminal),
|
terminal->term_width);
|
||||||
guac_terminal_get_columns(terminal));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "argv.h"
|
#include "argv.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
#include "common/recording.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "kubernetes.h"
|
#include "kubernetes.h"
|
||||||
#include "ssl.h"
|
#include "ssl.h"
|
||||||
@ -29,7 +30,6 @@
|
|||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/protocol.h>
|
#include <guacamole/protocol.h>
|
||||||
#include <guacamole/recording.h>
|
|
||||||
#include <libwebsockets.h>
|
#include <libwebsockets.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@ -229,7 +229,7 @@ void* guac_kubernetes_client_thread(void* data) {
|
|||||||
|
|
||||||
/* Set up screen recording, if requested */
|
/* Set up screen recording, if requested */
|
||||||
if (settings->recording_path != NULL) {
|
if (settings->recording_path != NULL) {
|
||||||
kubernetes_client->recording = guac_recording_create(client,
|
kubernetes_client->recording = guac_common_recording_create(client,
|
||||||
settings->recording_path,
|
settings->recording_path,
|
||||||
settings->recording_name,
|
settings->recording_name,
|
||||||
settings->create_recording_path,
|
settings->create_recording_path,
|
||||||
@ -239,23 +239,12 @@ void* guac_kubernetes_client_thread(void* data) {
|
|||||||
settings->recording_include_keys);
|
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 */
|
/* Create terminal */
|
||||||
kubernetes_client->term = guac_terminal_create(client, options);
|
kubernetes_client->term = guac_terminal_create(client,
|
||||||
|
kubernetes_client->clipboard, settings->disable_copy,
|
||||||
/* Free options struct now that it's been used */
|
settings->max_scrollback, settings->font_name, settings->font_size,
|
||||||
free(options);
|
settings->resolution, settings->width, settings->height,
|
||||||
|
settings->color_scheme, settings->backspace);
|
||||||
|
|
||||||
/* Fail if terminal init failed */
|
/* Fail if terminal init failed */
|
||||||
if (kubernetes_client->term == NULL) {
|
if (kubernetes_client->term == NULL) {
|
||||||
@ -369,7 +358,7 @@ fail:
|
|||||||
|
|
||||||
/* Clean up recording, if in progress */
|
/* Clean up recording, if in progress */
|
||||||
if (kubernetes_client->recording != NULL)
|
if (kubernetes_client->recording != NULL)
|
||||||
guac_recording_free(kubernetes_client->recording);
|
guac_common_recording_free(kubernetes_client->recording);
|
||||||
|
|
||||||
/* Free WebSocket context if successfully allocated */
|
/* Free WebSocket context if successfully allocated */
|
||||||
if (kubernetes_client->context != NULL)
|
if (kubernetes_client->context != NULL)
|
||||||
@ -413,8 +402,8 @@ void guac_kubernetes_force_redraw(guac_client* client) {
|
|||||||
|
|
||||||
/* Get current terminal dimensions */
|
/* Get current terminal dimensions */
|
||||||
guac_terminal* term = kubernetes_client->term;
|
guac_terminal* term = kubernetes_client->term;
|
||||||
int rows = guac_terminal_get_rows(term);
|
int rows = term->term_height;
|
||||||
int columns = guac_terminal_get_columns(term);
|
int columns = term->term_width;
|
||||||
|
|
||||||
/* Force a redraw by increasing the terminal size by one character in
|
/* Force a redraw by increasing the terminal size by one character in
|
||||||
* each dimension and then resizing it back to normal (the same technique
|
* each dimension and then resizing it back to normal (the same technique
|
||||||
|
@ -21,12 +21,12 @@
|
|||||||
#define GUAC_KUBERNETES_H
|
#define GUAC_KUBERNETES_H
|
||||||
|
|
||||||
#include "common/clipboard.h"
|
#include "common/clipboard.h"
|
||||||
|
#include "common/recording.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "terminal/terminal.h"
|
#include "terminal/terminal.h"
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/recording.h>
|
|
||||||
#include <libwebsockets.h>
|
#include <libwebsockets.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@ -102,6 +102,11 @@ typedef struct guac_kubernetes_client {
|
|||||||
*/
|
*/
|
||||||
pthread_t client_thread;
|
pthread_t client_thread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current clipboard contents.
|
||||||
|
*/
|
||||||
|
guac_common_clipboard* clipboard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The terminal which will render all output from the Kubernetes pod.
|
* The terminal which will render all output from the Kubernetes pod.
|
||||||
*/
|
*/
|
||||||
@ -123,7 +128,7 @@ typedef struct guac_kubernetes_client {
|
|||||||
* The in-progress session recording, or NULL if no recording is in
|
* The in-progress session recording, or NULL if no recording is in
|
||||||
* progress.
|
* progress.
|
||||||
*/
|
*/
|
||||||
guac_recording* recording;
|
guac_common_recording* recording;
|
||||||
|
|
||||||
} guac_kubernetes_client;
|
} guac_kubernetes_client;
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "argv.h"
|
#include "argv.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "terminal/terminal.h"
|
|
||||||
|
|
||||||
#include <guacamole/user.h>
|
#include <guacamole/user.h>
|
||||||
|
|
||||||
@ -216,8 +215,8 @@ enum KUBERNETES_ARGS_IDX {
|
|||||||
IDX_READ_ONLY,
|
IDX_READ_ONLY,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ASCII code, as an integer to use for the backspace key, or
|
* ASCII code, as an integer to use for the backspace key, or 127
|
||||||
* GUAC_TERMINAL_DEFAULT_BACKSPACE if not specified.
|
* if not specified.
|
||||||
*/
|
*/
|
||||||
IDX_BACKSPACE,
|
IDX_BACKSPACE,
|
||||||
|
|
||||||
@ -321,22 +320,22 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
|
|||||||
/* Read maximum scrollback size */
|
/* Read maximum scrollback size */
|
||||||
settings->max_scrollback =
|
settings->max_scrollback =
|
||||||
guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
||||||
IDX_SCROLLBACK, GUAC_TERMINAL_DEFAULT_MAX_SCROLLBACK);
|
IDX_SCROLLBACK, GUAC_KUBERNETES_DEFAULT_MAX_SCROLLBACK);
|
||||||
|
|
||||||
/* Read font name */
|
/* Read font name */
|
||||||
settings->font_name =
|
settings->font_name =
|
||||||
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
||||||
IDX_FONT_NAME, GUAC_TERMINAL_DEFAULT_FONT_NAME);
|
IDX_FONT_NAME, GUAC_KUBERNETES_DEFAULT_FONT_NAME);
|
||||||
|
|
||||||
/* Read font size */
|
/* Read font size */
|
||||||
settings->font_size =
|
settings->font_size =
|
||||||
guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
||||||
IDX_FONT_SIZE, GUAC_TERMINAL_DEFAULT_FONT_SIZE);
|
IDX_FONT_SIZE, GUAC_KUBERNETES_DEFAULT_FONT_SIZE);
|
||||||
|
|
||||||
/* Copy requested color scheme */
|
/* Copy requested color scheme */
|
||||||
settings->color_scheme =
|
settings->color_scheme =
|
||||||
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
||||||
IDX_COLOR_SCHEME, GUAC_TERMINAL_DEFAULT_COLOR_SCHEME);
|
IDX_COLOR_SCHEME, "");
|
||||||
|
|
||||||
/* Pull width/height/resolution directly from user */
|
/* Pull width/height/resolution directly from user */
|
||||||
settings->width = user->info.optimal_width;
|
settings->width = user->info.optimal_width;
|
||||||
@ -391,7 +390,7 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
|
|||||||
/* Parse backspace key code */
|
/* Parse backspace key code */
|
||||||
settings->backspace =
|
settings->backspace =
|
||||||
guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
|
||||||
IDX_BACKSPACE, GUAC_TERMINAL_DEFAULT_BACKSPACE);
|
IDX_BACKSPACE, 127);
|
||||||
|
|
||||||
/* Parse clipboard copy disable flag */
|
/* Parse clipboard copy disable flag */
|
||||||
settings->disable_copy =
|
settings->disable_copy =
|
||||||
|
@ -24,6 +24,17 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the font to use for the terminal if no name is specified.
|
||||||
|
*/
|
||||||
|
#define GUAC_KUBERNETES_DEFAULT_FONT_NAME "monospace"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the font to use for the terminal if no font size is specified,
|
||||||
|
* in points.
|
||||||
|
*/
|
||||||
|
#define GUAC_KUBERNETES_DEFAULT_FONT_SIZE 12
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The port to connect to when initiating any Kubernetes connection, if no
|
* The port to connect to when initiating any Kubernetes connection, if no
|
||||||
* other port is specified.
|
* other port is specified.
|
||||||
@ -46,6 +57,11 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_KUBERNETES_DEFAULT_RECORDING_NAME "recording"
|
#define GUAC_KUBERNETES_DEFAULT_RECORDING_NAME "recording"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default maximum scrollback size in rows.
|
||||||
|
*/
|
||||||
|
#define GUAC_KUBERNETES_DEFAULT_MAX_SCROLLBACK 1000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings for the Kubernetes connection. The values for this structure are
|
* Settings for the Kubernetes connection. The values for this structure are
|
||||||
* parsed from the arguments given during the Guacamole protocol handshake
|
* parsed from the arguments given during the Guacamole protocol handshake
|
||||||
|
@ -109,8 +109,8 @@ int guac_kubernetes_user_leave_handler(guac_user* user) {
|
|||||||
guac_kubernetes_client* kubernetes_client =
|
guac_kubernetes_client* kubernetes_client =
|
||||||
(guac_kubernetes_client*) user->client->data;
|
(guac_kubernetes_client*) user->client->data;
|
||||||
|
|
||||||
/* Remove the user from the terminal */
|
/* Update shared cursor state */
|
||||||
guac_terminal_remove_user(kubernetes_client->term, user);
|
guac_common_cursor_remove_user(kubernetes_client->term->cursor, user);
|
||||||
|
|
||||||
/* Free settings if not owner (owner settings will be freed with client) */
|
/* Free settings if not owner (owner settings will be freed with client) */
|
||||||
if (!user->owner) {
|
if (!user->owner) {
|
||||||
|
@ -57,7 +57,6 @@ libguac_client_rdp_la_SOURCES = \
|
|||||||
channels/rdpdr/rdpdr-printer.c \
|
channels/rdpdr/rdpdr-printer.c \
|
||||||
channels/rdpdr/rdpdr.c \
|
channels/rdpdr/rdpdr.c \
|
||||||
channels/rdpei.c \
|
channels/rdpei.c \
|
||||||
channels/rdpgfx.c \
|
|
||||||
channels/rdpsnd/rdpsnd-messages.c \
|
channels/rdpsnd/rdpsnd-messages.c \
|
||||||
channels/rdpsnd/rdpsnd.c \
|
channels/rdpsnd/rdpsnd.c \
|
||||||
client.c \
|
client.c \
|
||||||
@ -104,7 +103,6 @@ noinst_HEADERS = \
|
|||||||
channels/rdpdr/rdpdr-printer.h \
|
channels/rdpdr/rdpdr-printer.h \
|
||||||
channels/rdpdr/rdpdr.h \
|
channels/rdpdr/rdpdr.h \
|
||||||
channels/rdpei.h \
|
channels/rdpei.h \
|
||||||
channels/rdpgfx.h \
|
|
||||||
channels/rdpsnd/rdpsnd-messages.h \
|
channels/rdpsnd/rdpsnd-messages.h \
|
||||||
channels/rdpsnd/rdpsnd.h \
|
channels/rdpsnd/rdpsnd.h \
|
||||||
client.h \
|
client.h \
|
||||||
@ -230,7 +228,6 @@ BUILT_SOURCES = \
|
|||||||
rdp_keymaps = \
|
rdp_keymaps = \
|
||||||
$(srcdir)/keymaps/base.keymap \
|
$(srcdir)/keymaps/base.keymap \
|
||||||
$(srcdir)/keymaps/failsafe.keymap \
|
$(srcdir)/keymaps/failsafe.keymap \
|
||||||
$(srcdir)/keymaps/cs-cz-qwertz.keymap \
|
|
||||||
$(srcdir)/keymaps/de_de_qwertz.keymap \
|
$(srcdir)/keymaps/de_de_qwertz.keymap \
|
||||||
$(srcdir)/keymaps/de_ch_qwertz.keymap \
|
$(srcdir)/keymaps/de_ch_qwertz.keymap \
|
||||||
$(srcdir)/keymaps/en_gb_qwerty.keymap \
|
$(srcdir)/keymaps/en_gb_qwerty.keymap \
|
||||||
@ -238,14 +235,12 @@ rdp_keymaps = \
|
|||||||
$(srcdir)/keymaps/es_es_qwerty.keymap \
|
$(srcdir)/keymaps/es_es_qwerty.keymap \
|
||||||
$(srcdir)/keymaps/es_latam_qwerty.keymap \
|
$(srcdir)/keymaps/es_latam_qwerty.keymap \
|
||||||
$(srcdir)/keymaps/fr_be_azerty.keymap \
|
$(srcdir)/keymaps/fr_be_azerty.keymap \
|
||||||
$(srcdir)/keymaps/fr_ca_qwerty.keymap \
|
|
||||||
$(srcdir)/keymaps/fr_ch_qwertz.keymap \
|
$(srcdir)/keymaps/fr_ch_qwertz.keymap \
|
||||||
$(srcdir)/keymaps/fr_fr_azerty.keymap \
|
$(srcdir)/keymaps/fr_fr_azerty.keymap \
|
||||||
$(srcdir)/keymaps/hu_hu_qwertz.keymap \
|
$(srcdir)/keymaps/hu_hu_qwertz.keymap \
|
||||||
$(srcdir)/keymaps/it_it_qwerty.keymap \
|
$(srcdir)/keymaps/it_it_qwerty.keymap \
|
||||||
$(srcdir)/keymaps/ja_jp_qwerty.keymap \
|
$(srcdir)/keymaps/ja_jp_qwerty.keymap \
|
||||||
$(srcdir)/keymaps/no_no_qwerty.keymap \
|
$(srcdir)/keymaps/no_no_qwerty.keymap \
|
||||||
$(srcdir)/keymaps/pl_pl_qwerty.keymap \
|
|
||||||
$(srcdir)/keymaps/pt_br_qwerty.keymap \
|
$(srcdir)/keymaps/pt_br_qwerty.keymap \
|
||||||
$(srcdir)/keymaps/sv_se_qwerty.keymap \
|
$(srcdir)/keymaps/sv_se_qwerty.keymap \
|
||||||
$(srcdir)/keymaps/da_dk_qwerty.keymap \
|
$(srcdir)/keymaps/da_dk_qwerty.keymap \
|
||||||
|
@ -149,7 +149,7 @@ BOOL guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, BOOL pri
|
|||||||
|
|
||||||
else {
|
else {
|
||||||
|
|
||||||
/* Make sure that the received bitmap is not NULL before processing */
|
/* Make sure that the recieved bitmap is not NULL before processing */
|
||||||
if (bitmap == NULL) {
|
if (bitmap == NULL) {
|
||||||
guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in bitmap_setsurface instruction.");
|
guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in bitmap_setsurface instruction.");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -358,7 +358,7 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr,
|
|||||||
|
|
||||||
guac_iconv_write* remote_writer;
|
guac_iconv_write* remote_writer;
|
||||||
const char* input = clipboard->clipboard->buffer;
|
const char* input = clipboard->clipboard->buffer;
|
||||||
char* output = malloc(GUAC_COMMON_CLIPBOARD_MAX_LENGTH);
|
char* output = malloc(GUAC_RDP_CLIPBOARD_MAX_LENGTH);
|
||||||
|
|
||||||
/* Map requested clipboard format to a guac_iconv writer */
|
/* Map requested clipboard format to a guac_iconv writer */
|
||||||
switch (format_data_request->requestedFormatId) {
|
switch (format_data_request->requestedFormatId) {
|
||||||
@ -389,7 +389,7 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr,
|
|||||||
BYTE* start = (BYTE*) output;
|
BYTE* start = (BYTE*) output;
|
||||||
guac_iconv_read* local_reader = settings->normalize_clipboard ? GUAC_READ_UTF8_NORMALIZED : GUAC_READ_UTF8;
|
guac_iconv_read* local_reader = settings->normalize_clipboard ? GUAC_READ_UTF8_NORMALIZED : GUAC_READ_UTF8;
|
||||||
guac_iconv(local_reader, &input, clipboard->clipboard->length,
|
guac_iconv(local_reader, &input, clipboard->clipboard->length,
|
||||||
remote_writer, &output, GUAC_COMMON_CLIPBOARD_MAX_LENGTH);
|
remote_writer, &output, GUAC_RDP_CLIPBOARD_MAX_LENGTH);
|
||||||
|
|
||||||
CLIPRDR_FORMAT_DATA_RESPONSE data_response = {
|
CLIPRDR_FORMAT_DATA_RESPONSE data_response = {
|
||||||
.requestedFormatData = (BYTE*) start,
|
.requestedFormatData = (BYTE*) start,
|
||||||
@ -449,7 +449,7 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr,
|
|||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
char received_data[GUAC_COMMON_CLIPBOARD_MAX_LENGTH];
|
char received_data[GUAC_RDP_CLIPBOARD_MAX_LENGTH];
|
||||||
|
|
||||||
guac_iconv_read* remote_reader;
|
guac_iconv_read* remote_reader;
|
||||||
const char* input = (char*) format_data_response->requestedFormatData;
|
const char* input = (char*) format_data_response->requestedFormatData;
|
||||||
@ -509,12 +509,12 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr,
|
|||||||
* @param context
|
* @param context
|
||||||
* The rdpContext associated with the active RDP session.
|
* The rdpContext associated with the active RDP session.
|
||||||
*
|
*
|
||||||
* @param args
|
* @param e
|
||||||
* Event-specific arguments, mainly the name of the channel, and a
|
* Event-specific arguments, mainly the name of the channel, and a
|
||||||
* reference to the associated plugin loaded for that channel by FreeRDP.
|
* reference to the associated plugin loaded for that channel by FreeRDP.
|
||||||
*/
|
*/
|
||||||
static void guac_rdp_cliprdr_channel_connected(rdpContext* context,
|
static void guac_rdp_cliprdr_channel_connected(rdpContext* context,
|
||||||
ChannelConnectedEventArgs* args) {
|
ChannelConnectedEventArgs* e) {
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
@ -526,12 +526,12 @@ static void guac_rdp_cliprdr_channel_connected(rdpContext* context,
|
|||||||
assert(clipboard != NULL);
|
assert(clipboard != NULL);
|
||||||
|
|
||||||
/* Ignore connection event if it's not for the CLIPRDR channel */
|
/* Ignore connection event if it's not for the CLIPRDR channel */
|
||||||
if (strcmp(args->name, CLIPRDR_SVC_CHANNEL_NAME) != 0)
|
if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* The structure pointed to by pInterface is guaranteed to be a
|
/* The structure pointed to by pInterface is guaranteed to be a
|
||||||
* CliprdrClientContext if the channel is CLIPRDR */
|
* CliprdrClientContext if the channel is CLIPRDR */
|
||||||
CliprdrClientContext* cliprdr = (CliprdrClientContext*) args->pInterface;
|
CliprdrClientContext* cliprdr = (CliprdrClientContext*) e->pInterface;
|
||||||
|
|
||||||
/* Associate FreeRDP CLIPRDR context and its Guacamole counterpart with
|
/* Associate FreeRDP CLIPRDR context and its Guacamole counterpart with
|
||||||
* eachother */
|
* eachother */
|
||||||
@ -562,12 +562,12 @@ static void guac_rdp_cliprdr_channel_connected(rdpContext* context,
|
|||||||
* @param context
|
* @param context
|
||||||
* The rdpContext associated with the active RDP session.
|
* The rdpContext associated with the active RDP session.
|
||||||
*
|
*
|
||||||
* @param args
|
* @param e
|
||||||
* Event-specific arguments, mainly the name of the channel, and a
|
* Event-specific arguments, mainly the name of the channel, and a
|
||||||
* reference to the associated plugin loaded for that channel by FreeRDP.
|
* reference to the associated plugin loaded for that channel by FreeRDP.
|
||||||
*/
|
*/
|
||||||
static void guac_rdp_cliprdr_channel_disconnected(rdpContext* context,
|
static void guac_rdp_cliprdr_channel_disconnected(rdpContext* context,
|
||||||
ChannelDisconnectedEventArgs* args) {
|
ChannelDisconnectedEventArgs* e) {
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
@ -579,7 +579,7 @@ static void guac_rdp_cliprdr_channel_disconnected(rdpContext* context,
|
|||||||
assert(clipboard != NULL);
|
assert(clipboard != NULL);
|
||||||
|
|
||||||
/* Ignore disconnection event if it's not for the CLIPRDR channel */
|
/* Ignore disconnection event if it's not for the CLIPRDR channel */
|
||||||
if (strcmp(args->name, CLIPRDR_SVC_CHANNEL_NAME) != 0)
|
if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Channel is no longer connected */
|
/* Channel is no longer connected */
|
||||||
@ -595,7 +595,7 @@ guac_rdp_clipboard* guac_rdp_clipboard_alloc(guac_client* client) {
|
|||||||
/* Allocate clipboard and underlying storage */
|
/* Allocate clipboard and underlying storage */
|
||||||
guac_rdp_clipboard* clipboard = calloc(1, sizeof(guac_rdp_clipboard));
|
guac_rdp_clipboard* clipboard = calloc(1, sizeof(guac_rdp_clipboard));
|
||||||
clipboard->client = client;
|
clipboard->client = client;
|
||||||
clipboard->clipboard = guac_common_clipboard_alloc();
|
clipboard->clipboard = guac_common_clipboard_alloc(GUAC_RDP_CLIPBOARD_MAX_LENGTH);
|
||||||
clipboard->requested_format = CF_TEXT;
|
clipboard->requested_format = CF_TEXT;
|
||||||
|
|
||||||
return clipboard;
|
return clipboard;
|
||||||
|
@ -115,7 +115,7 @@ struct guac_rdp_common_svc {
|
|||||||
guac_rdp_common_svc_receive_handler* _receive_handler;
|
guac_rdp_common_svc_receive_handler* _receive_handler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler which is involved when the SVC has been disconnected and is
|
* Handler which is invokved when the SVC has been disconnected and is
|
||||||
* about to be freed.
|
* about to be freed.
|
||||||
*/
|
*/
|
||||||
guac_rdp_common_svc_terminate_handler* _terminate_handler;
|
guac_rdp_common_svc_terminate_handler* _terminate_handler;
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "channels/disp.h"
|
#include "channels/disp.h"
|
||||||
#include "plugins/channels.h"
|
#include "plugins/channels.h"
|
||||||
#include "fs.h"
|
|
||||||
#include "rdp.h"
|
#include "rdp.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
@ -68,19 +67,19 @@ void guac_rdp_disp_free(guac_rdp_disp* disp) {
|
|||||||
* @param context
|
* @param context
|
||||||
* The rdpContext associated with the active RDP session.
|
* The rdpContext associated with the active RDP session.
|
||||||
*
|
*
|
||||||
* @param args
|
* @param e
|
||||||
* Event-specific arguments, mainly the name of the channel, and a
|
* Event-specific arguments, mainly the name of the channel, and a
|
||||||
* reference to the associated plugin loaded for that channel by FreeRDP.
|
* reference to the associated plugin loaded for that channel by FreeRDP.
|
||||||
*/
|
*/
|
||||||
static void guac_rdp_disp_channel_connected(rdpContext* context,
|
static void guac_rdp_disp_channel_connected(rdpContext* context,
|
||||||
ChannelConnectedEventArgs* args) {
|
ChannelConnectedEventArgs* e) {
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
guac_rdp_disp* guac_disp = rdp_client->disp;
|
guac_rdp_disp* guac_disp = rdp_client->disp;
|
||||||
|
|
||||||
/* Ignore connection event if it's not for the Display Update channel */
|
/* Ignore connection event if it's not for the Display Update channel */
|
||||||
if (strcmp(args->name, DISP_DVC_CHANNEL_NAME) != 0)
|
if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Init module with current display size */
|
/* Init module with current display size */
|
||||||
@ -89,7 +88,7 @@ static void guac_rdp_disp_channel_connected(rdpContext* context,
|
|||||||
guac_rdp_get_height(context->instance));
|
guac_rdp_get_height(context->instance));
|
||||||
|
|
||||||
/* Store reference to the display update plugin once it's connected */
|
/* Store reference to the display update plugin once it's connected */
|
||||||
DispClientContext* disp = (DispClientContext*) args->pInterface;
|
DispClientContext* disp = (DispClientContext*) e->pInterface;
|
||||||
guac_disp->disp = disp;
|
guac_disp->disp = disp;
|
||||||
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG, "Display update channel "
|
guac_client_log(client, GUAC_LOG_DEBUG, "Display update channel "
|
||||||
@ -110,19 +109,19 @@ static void guac_rdp_disp_channel_connected(rdpContext* context,
|
|||||||
* @param context
|
* @param context
|
||||||
* The rdpContext associated with the active RDP session.
|
* The rdpContext associated with the active RDP session.
|
||||||
*
|
*
|
||||||
* @param args
|
* @param e
|
||||||
* Event-specific arguments, mainly the name of the channel, and a
|
* Event-specific arguments, mainly the name of the channel, and a
|
||||||
* reference to the associated plugin loaded for that channel by FreeRDP.
|
* reference to the associated plugin loaded for that channel by FreeRDP.
|
||||||
*/
|
*/
|
||||||
static void guac_rdp_disp_channel_disconnected(rdpContext* context,
|
static void guac_rdp_disp_channel_disconnected(rdpContext* context,
|
||||||
ChannelDisconnectedEventArgs* args) {
|
ChannelDisconnectedEventArgs* e) {
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
guac_rdp_disp* guac_disp = rdp_client->disp;
|
guac_rdp_disp* guac_disp = rdp_client->disp;
|
||||||
|
|
||||||
/* Ignore disconnection event if it's not for the Display Update channel */
|
/* Ignore disconnection event if it's not for the Display Update channel */
|
||||||
if (strcmp(args->name, DISP_DVC_CHANNEL_NAME) != 0)
|
if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Channel is no longer connected */
|
/* Channel is no longer connected */
|
||||||
@ -278,18 +277,6 @@ void guac_rdp_disp_update_size(guac_rdp_disp* disp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int guac_rdp_disp_reconnect_needed(guac_rdp_disp* disp) {
|
int guac_rdp_disp_reconnect_needed(guac_rdp_disp* disp) {
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) disp->client->data;
|
|
||||||
|
|
||||||
/* Do not reconnect if files are open. */
|
|
||||||
if (rdp_client->filesystem != NULL
|
|
||||||
&& rdp_client->filesystem->open_files > 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Do not reconnect if an active print job is present */
|
|
||||||
if (rdp_client->active_job != NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
|
||||||
return disp->reconnect_needed;
|
return disp->reconnect_needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ void guac_rdp_disp_free(guac_rdp_disp* disp);
|
|||||||
/**
|
/**
|
||||||
* Adds FreeRDP's "disp" plugin to the list of dynamic virtual channel plugins
|
* Adds FreeRDP's "disp" plugin to the list of dynamic virtual channel plugins
|
||||||
* to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will
|
* to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will
|
||||||
* automatically be associated with the guac_rdp_disp instance pointed to by the
|
* automatically be assicated with the guac_rdp_disp instance pointed to by the
|
||||||
* current guac_rdp_client. The plugin will only be loaded once the "drdynvc"
|
* current guac_rdp_client. The plugin will only be loaded once the "drdynvc"
|
||||||
* plugin is loaded. The "disp" plugin ultimately adds support for the Display
|
* plugin is loaded. The "disp" plugin ultimately adds support for the Display
|
||||||
* Update channel.
|
* Update channel.
|
||||||
|
@ -97,6 +97,12 @@ static UINT guac_rdp_rail_complete_handshake(RailClientContext* rail) {
|
|||||||
.flags = 0x00
|
.flags = 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
client_status.flags |= TS_RAIL_CLIENTSTATUS_ZORDER_SYNC;
|
||||||
|
client_status.flags |= TS_RAIL_CLIENTSTATUS_WINDOW_RESIZE_MARGIN_SUPPORTED;
|
||||||
|
client_status.flags |= TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED;
|
||||||
|
client_status.flags |= TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED;
|
||||||
|
client_status.flags |= TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED;
|
||||||
|
|
||||||
/* Send client status */
|
/* Send client status */
|
||||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||||
status = rail->ClientInformation(rail, &client_status);
|
status = rail->ClientInformation(rail, &client_status);
|
||||||
@ -230,22 +236,22 @@ static UINT guac_rdp_rail_handshake_ex(RailClientContext* rail,
|
|||||||
* @param context
|
* @param context
|
||||||
* The rdpContext associated with the active RDP session.
|
* The rdpContext associated with the active RDP session.
|
||||||
*
|
*
|
||||||
* @param args
|
* @param e
|
||||||
* Event-specific arguments, mainly the name of the channel, and a
|
* Event-specific arguments, mainly the name of the channel, and a
|
||||||
* reference to the associated plugin loaded for that channel by FreeRDP.
|
* reference to the associated plugin loaded for that channel by FreeRDP.
|
||||||
*/
|
*/
|
||||||
static void guac_rdp_rail_channel_connected(rdpContext* context,
|
static void guac_rdp_rail_channel_connected(rdpContext* context,
|
||||||
ChannelConnectedEventArgs* args) {
|
ChannelConnectedEventArgs* e) {
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
|
|
||||||
/* Ignore connection event if it's not for the RAIL channel */
|
/* Ignore connection event if it's not for the RAIL channel */
|
||||||
if (strcmp(args->name, RAIL_SVC_CHANNEL_NAME) != 0)
|
if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* The structure pointed to by pInterface is guaranteed to be a
|
/* The structure pointed to by pInterface is guaranteed to be a
|
||||||
* RailClientContext if the channel is RAIL */
|
* RailClientContext if the channel is RAIL */
|
||||||
RailClientContext* rail = (RailClientContext*) args->pInterface;
|
RailClientContext* rail = (RailClientContext*) e->pInterface;
|
||||||
|
|
||||||
/* Init FreeRDP RAIL context, ensuring the guac_client can be accessed from
|
/* Init FreeRDP RAIL context, ensuring the guac_client can be accessed from
|
||||||
* within any RAIL-specific callbacks */
|
* within any RAIL-specific callbacks */
|
||||||
|
@ -66,23 +66,23 @@ void guac_rdp_rdpei_free(guac_rdp_rdpei* rdpei) {
|
|||||||
* @param context
|
* @param context
|
||||||
* The rdpContext associated with the active RDP session.
|
* The rdpContext associated with the active RDP session.
|
||||||
*
|
*
|
||||||
* @param args
|
* @param e
|
||||||
* Event-specific arguments, mainly the name of the channel, and a
|
* Event-specific arguments, mainly the name of the channel, and a
|
||||||
* reference to the associated plugin loaded for that channel by FreeRDP.
|
* reference to the associated plugin loaded for that channel by FreeRDP.
|
||||||
*/
|
*/
|
||||||
static void guac_rdp_rdpei_channel_connected(rdpContext* context,
|
static void guac_rdp_rdpei_channel_connected(rdpContext* context,
|
||||||
ChannelConnectedEventArgs* args) {
|
ChannelConnectedEventArgs* e) {
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
guac_rdp_rdpei* guac_rdpei = rdp_client->rdpei;
|
guac_rdp_rdpei* guac_rdpei = rdp_client->rdpei;
|
||||||
|
|
||||||
/* Ignore connection event if it's not for the RDPEI channel */
|
/* Ignore connection event if it's not for the RDPEI channel */
|
||||||
if (strcmp(args->name, RDPEI_DVC_CHANNEL_NAME) != 0)
|
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Store reference to the RDPEI plugin once it's connected */
|
/* Store reference to the RDPEI plugin once it's connected */
|
||||||
RdpeiClientContext* rdpei = (RdpeiClientContext*) args->pInterface;
|
RdpeiClientContext* rdpei = (RdpeiClientContext*) e->pInterface;
|
||||||
guac_rdpei->rdpei = rdpei;
|
guac_rdpei->rdpei = rdpei;
|
||||||
|
|
||||||
/* Declare level of multi-touch support */
|
/* Declare level of multi-touch support */
|
||||||
@ -107,19 +107,19 @@ static void guac_rdp_rdpei_channel_connected(rdpContext* context,
|
|||||||
* @param context
|
* @param context
|
||||||
* The rdpContext associated with the active RDP session.
|
* The rdpContext associated with the active RDP session.
|
||||||
*
|
*
|
||||||
* @param args
|
* @param e
|
||||||
* Event-specific arguments, mainly the name of the channel, and a
|
* Event-specific arguments, mainly the name of the channel, and a
|
||||||
* reference to the associated plugin loaded for that channel by FreeRDP.
|
* reference to the associated plugin loaded for that channel by FreeRDP.
|
||||||
*/
|
*/
|
||||||
static void guac_rdp_rdpei_channel_disconnected(rdpContext* context,
|
static void guac_rdp_rdpei_channel_disconnected(rdpContext* context,
|
||||||
ChannelDisconnectedEventArgs* args) {
|
ChannelDisconnectedEventArgs* e) {
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
guac_rdp_rdpei* guac_rdpei = rdp_client->rdpei;
|
guac_rdp_rdpei* guac_rdpei = rdp_client->rdpei;
|
||||||
|
|
||||||
/* Ignore disconnection event if it's not for the RDPEI channel */
|
/* Ignore disconnection event if it's not for the RDPEI channel */
|
||||||
if (strcmp(args->name, RDPEI_DVC_CHANNEL_NAME) != 0)
|
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Channel is no longer connected */
|
/* Channel is no longer connected */
|
||||||
|
@ -110,7 +110,7 @@ void guac_rdp_rdpei_free(guac_rdp_rdpei* rdpei);
|
|||||||
/**
|
/**
|
||||||
* Adds FreeRDP's "rdpei" plugin to the list of dynamic virtual channel plugins
|
* Adds FreeRDP's "rdpei" plugin to the list of dynamic virtual channel plugins
|
||||||
* to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will
|
* to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will
|
||||||
* automatically be associated with the guac_rdp_rdpei instance pointed to by the
|
* automatically be assicated with the guac_rdp_rdpei instance pointed to by the
|
||||||
* current guac_rdp_client. The plugin will only be loaded once the "drdynvc"
|
* current guac_rdp_client. The plugin will only be loaded once the "drdynvc"
|
||||||
* plugin is loaded. The "rdpei" plugin ultimately adds support for multi-touch
|
* plugin is loaded. The "rdpei" plugin ultimately adds support for multi-touch
|
||||||
* input via the RDPEI channel.
|
* input via the RDPEI channel.
|
||||||
|
@ -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 "channels/rdpgfx.h"
|
|
||||||
#include "plugins/channels.h"
|
|
||||||
#include "rdp.h"
|
|
||||||
#include "settings.h"
|
|
||||||
|
|
||||||
#include <freerdp/client/rdpgfx.h>
|
|
||||||
#include <freerdp/freerdp.h>
|
|
||||||
#include <freerdp/gdi/gfx.h>
|
|
||||||
#include <freerdp/event.h>
|
|
||||||
#include <guacamole/client.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback which associates handlers specific to Guacamole with the
|
|
||||||
* RdpgfxClientContext instance allocated by FreeRDP to deal with received
|
|
||||||
* RDPGFX (Graphics Pipeline) messages.
|
|
||||||
*
|
|
||||||
* This function is called whenever a channel connects via the PubSub event
|
|
||||||
* system within FreeRDP, but only has any effect if the connected channel is
|
|
||||||
* the RDPGFX channel. This specific callback is registered with the
|
|
||||||
* PubSub system of the relevant rdpContext when guac_rdp_rdpgfx_load_plugin() is
|
|
||||||
* called.
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* The rdpContext associated with the active RDP session.
|
|
||||||
*
|
|
||||||
* @param args
|
|
||||||
* Event-specific arguments, mainly the name of the channel, and a
|
|
||||||
* reference to the associated plugin loaded for that channel by FreeRDP.
|
|
||||||
*/
|
|
||||||
static void guac_rdp_rdpgfx_channel_connected(rdpContext* context,
|
|
||||||
ChannelConnectedEventArgs* args) {
|
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
|
||||||
|
|
||||||
/* Ignore connection event if it's not for the RDPGFX channel */
|
|
||||||
if (strcmp(args->name, RDPGFX_DVC_CHANNEL_NAME) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Init GDI-backed support for the Graphics Pipeline */
|
|
||||||
RdpgfxClientContext* rdpgfx = (RdpgfxClientContext*) args->pInterface;
|
|
||||||
rdpGdi* gdi = context->gdi;
|
|
||||||
|
|
||||||
if (!gdi_graphics_pipeline_init(gdi, rdpgfx))
|
|
||||||
guac_client_log(client, GUAC_LOG_WARNING, "Rendering backend for RDPGFX "
|
|
||||||
"channel could not be loaded. Graphics may not render at all!");
|
|
||||||
else
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG, "RDPGFX channel will be used for "
|
|
||||||
"the RDP Graphics Pipeline Extension.");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback which handles any RDPGFX cleanup specific to Guacamole.
|
|
||||||
*
|
|
||||||
* This function is called whenever a channel disconnects via the PubSub event
|
|
||||||
* system within FreeRDP, but only has any effect if the disconnected channel
|
|
||||||
* is the RDPGFX channel. This specific callback is registered with the PubSub
|
|
||||||
* system of the relevant rdpContext when guac_rdp_rdpgfx_load_plugin() is
|
|
||||||
* called.
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* The rdpContext associated with the active RDP session.
|
|
||||||
*
|
|
||||||
* @param args
|
|
||||||
* Event-specific arguments, mainly the name of the channel, and a
|
|
||||||
* reference to the associated plugin loaded for that channel by FreeRDP.
|
|
||||||
*/
|
|
||||||
static void guac_rdp_rdpgfx_channel_disconnected(rdpContext* context,
|
|
||||||
ChannelDisconnectedEventArgs* args) {
|
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
|
||||||
|
|
||||||
/* Ignore disconnection event if it's not for the RDPGFX channel */
|
|
||||||
if (strcmp(args->name, RDPGFX_DVC_CHANNEL_NAME) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Un-init GDI-backed support for the Graphics Pipeline */
|
|
||||||
RdpgfxClientContext* rdpgfx = (RdpgfxClientContext*) args->pInterface;
|
|
||||||
rdpGdi* gdi = context->gdi;
|
|
||||||
gdi_graphics_pipeline_uninit(gdi, rdpgfx);
|
|
||||||
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG, "RDPGFX channel support unloaded.");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void guac_rdp_rdpgfx_load_plugin(rdpContext* context) {
|
|
||||||
|
|
||||||
/* Subscribe to and handle channel connected events */
|
|
||||||
PubSub_SubscribeChannelConnected(context->pubSub,
|
|
||||||
(pChannelConnectedEventHandler) guac_rdp_rdpgfx_channel_connected);
|
|
||||||
|
|
||||||
/* Subscribe to and handle channel disconnected events */
|
|
||||||
PubSub_SubscribeChannelDisconnected(context->pubSub,
|
|
||||||
(pChannelDisconnectedEventHandler) guac_rdp_rdpgfx_channel_disconnected);
|
|
||||||
|
|
||||||
/* Add "rdpgfx" channel */
|
|
||||||
guac_freerdp_dynamic_channel_collection_add(context->settings, "rdpgfx", NULL);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +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_RDP_CHANNELS_RDPGFX_H
|
|
||||||
#define GUAC_RDP_CHANNELS_RDPGFX_H
|
|
||||||
|
|
||||||
#include "settings.h"
|
|
||||||
|
|
||||||
#include <freerdp/client/rdpgfx.h>
|
|
||||||
#include <freerdp/freerdp.h>
|
|
||||||
#include <guacamole/client.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds FreeRDP's "rdpgfx" plugin to the list of dynamic virtual channel plugins
|
|
||||||
* to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will
|
|
||||||
* automatically be associated with the guac_rdp_rdpgfx instance pointed to by the
|
|
||||||
* current guac_rdp_client. The plugin will only be loaded once the "drdynvc"
|
|
||||||
* plugin is loaded. The "rdpgfx" plugin ultimately adds support for the RDP
|
|
||||||
* Graphics Pipeline Extension.
|
|
||||||
*
|
|
||||||
* If failures occur, messages noting the specifics of those failures will be
|
|
||||||
* logged.
|
|
||||||
*
|
|
||||||
* This MUST be called within the PreConnect callback of the freerdp instance
|
|
||||||
* for Graphics Pipeline support to be loaded.
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* The rdpContext associated with the active RDP session.
|
|
||||||
*/
|
|
||||||
void guac_rdp_rdpgfx_load_plugin(rdpContext* context);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
|||||||
#include "channels/audio-input/audio-buffer.h"
|
#include "channels/audio-input/audio-buffer.h"
|
||||||
#include "channels/cliprdr.h"
|
#include "channels/cliprdr.h"
|
||||||
#include "channels/disp.h"
|
#include "channels/disp.h"
|
||||||
|
#include "common/recording.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -36,7 +37,6 @@
|
|||||||
|
|
||||||
#include <guacamole/audio.h>
|
#include <guacamole/audio.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/recording.h>
|
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -199,14 +199,6 @@ int guac_rdp_client_free_handler(guac_client* client) {
|
|||||||
if (rdp_client->filesystem != NULL)
|
if (rdp_client->filesystem != NULL)
|
||||||
guac_rdp_fs_free(rdp_client->filesystem);
|
guac_rdp_fs_free(rdp_client->filesystem);
|
||||||
|
|
||||||
/* End active print job, if any */
|
|
||||||
guac_rdp_print_job* job = (guac_rdp_print_job*) rdp_client->active_job;
|
|
||||||
if (job != NULL) {
|
|
||||||
guac_rdp_print_job_kill(job);
|
|
||||||
guac_rdp_print_job_free(job);
|
|
||||||
rdp_client->active_job = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ENABLE_COMMON_SSH
|
#ifdef ENABLE_COMMON_SSH
|
||||||
/* Free SFTP filesystem, if loaded */
|
/* Free SFTP filesystem, if loaded */
|
||||||
if (rdp_client->sftp_filesystem)
|
if (rdp_client->sftp_filesystem)
|
||||||
@ -225,7 +217,7 @@ int guac_rdp_client_free_handler(guac_client* client) {
|
|||||||
|
|
||||||
/* Clean up recording, if in progress */
|
/* Clean up recording, if in progress */
|
||||||
if (rdp_client->recording != NULL)
|
if (rdp_client->recording != NULL)
|
||||||
guac_recording_free(rdp_client->recording);
|
guac_common_recording_free(rdp_client->recording);
|
||||||
|
|
||||||
/* Clean up audio stream, if allocated */
|
/* Clean up audio stream, if allocated */
|
||||||
if (rdp_client->audio != NULL)
|
if (rdp_client->audio != NULL)
|
||||||
|
@ -62,6 +62,11 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_RDP_REASONABLE_AREA (800*600)
|
#define GUAC_RDP_REASONABLE_AREA (800*600)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of bytes to allow within the clipboard.
|
||||||
|
*/
|
||||||
|
#define GUAC_RDP_CLIPBOARD_MAX_LENGTH 262144
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initial rate of audio to stream, in Hz. If the RDP server uses a different
|
* Initial rate of audio to stream, in Hz. If the RDP server uses a different
|
||||||
* value, the Guacamole audio stream will simply be reset appropriately.
|
* value, the Guacamole audio stream will simply be reset appropriately.
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include <guacamole/stream.h>
|
#include <guacamole/stream.h>
|
||||||
#include <guacamole/string.h>
|
#include <guacamole/string.h>
|
||||||
#include <guacamole/user.h>
|
#include <guacamole/user.h>
|
||||||
#include <winpr/file.h>
|
|
||||||
#include <winpr/nt.h>
|
#include <winpr/nt.h>
|
||||||
#include <winpr/shell.h>
|
#include <winpr/shell.h>
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
|
|
||||||
#include <cairo/cairo.h>
|
#include <cairo/cairo.h>
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <freerdp/gdi/gdi.h>
|
|
||||||
#include <freerdp/graphics.h>
|
#include <freerdp/graphics.h>
|
||||||
#include <freerdp/primary.h>
|
#include <freerdp/primary.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
@ -248,7 +247,7 @@ BOOL guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) {
|
|||||||
int x_src = memblt->nXSrc;
|
int x_src = memblt->nXSrc;
|
||||||
int y_src = memblt->nYSrc;
|
int y_src = memblt->nYSrc;
|
||||||
|
|
||||||
/* Make sure that the received bitmap is not NULL before processing */
|
/* Make sure that the recieved bitmap is not NULL before processing */
|
||||||
if (bitmap == NULL) {
|
if (bitmap == NULL) {
|
||||||
guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in memblt instruction.");
|
guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in memblt instruction.");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -372,110 +371,9 @@ BOOL guac_rdp_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_rdp_gdi_mark_frame(rdpContext* context, int starting) {
|
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
|
||||||
|
|
||||||
/* The server supports defining explicit frames */
|
|
||||||
rdp_client->frames_supported = 1;
|
|
||||||
|
|
||||||
/* A new frame is beginning */
|
|
||||||
if (starting) {
|
|
||||||
rdp_client->in_frame = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The current frame has ended */
|
|
||||||
guac_timestamp frame_end = guac_timestamp_current();
|
|
||||||
int time_elapsed = frame_end - client->last_sent_timestamp;
|
|
||||||
rdp_client->in_frame = 0;
|
|
||||||
|
|
||||||
/* A new frame has been received from the RDP server and processed */
|
|
||||||
rdp_client->frames_received++;
|
|
||||||
|
|
||||||
/* Flush a new frame if the client is ready for it */
|
|
||||||
if (time_elapsed >= guac_client_get_processing_lag(client)) {
|
|
||||||
guac_common_display_flush(rdp_client->display);
|
|
||||||
guac_client_end_multiple_frames(client, rdp_client->frames_received);
|
|
||||||
guac_socket_flush(client->socket);
|
|
||||||
rdp_client->frames_received = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL guac_rdp_gdi_frame_marker(rdpContext* context, const FRAME_MARKER_ORDER* frame_marker) {
|
|
||||||
guac_rdp_gdi_mark_frame(context, frame_marker->action == FRAME_START);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL guac_rdp_gdi_surface_frame_marker(rdpContext* context, const SURFACE_FRAME_MARKER* surface_frame_marker) {
|
|
||||||
|
|
||||||
guac_rdp_gdi_mark_frame(context, surface_frame_marker->frameAction == SURFACECMD_FRAMEACTION_END);
|
|
||||||
|
|
||||||
if (context->settings->FrameAcknowledge > 0)
|
|
||||||
IFCALL(context->update->SurfaceFrameAcknowledge, context,
|
|
||||||
surface_frame_marker->frameId);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL guac_rdp_gdi_begin_paint(rdpContext* context) {
|
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
|
||||||
|
|
||||||
/* Leverage BeginPaint handler to detect start of frame for RDPGFX channel */
|
|
||||||
if (rdp_client->settings->enable_gfx && rdp_client->frames_supported)
|
|
||||||
guac_rdp_gdi_mark_frame(context, 1);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL guac_rdp_gdi_end_paint(rdpContext* context) {
|
BOOL guac_rdp_gdi_end_paint(rdpContext* context) {
|
||||||
|
/* IGNORE */
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
|
||||||
rdpGdi* gdi = context->gdi;
|
|
||||||
|
|
||||||
/* Ignore EndPaint handler unless needed to detect end of frame for RDPGFX
|
|
||||||
* channel */
|
|
||||||
if (!rdp_client->settings->enable_gfx)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
/* Ignore paint if GDI output is suppressed */
|
|
||||||
if (gdi->suppressOutput)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
/* Ignore paint if nothing has been done (empty rect) */
|
|
||||||
if (gdi->primary->hdc->hwnd->invalid->null)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
INT32 x = gdi->primary->hdc->hwnd->invalid->x;
|
|
||||||
INT32 y = gdi->primary->hdc->hwnd->invalid->y;
|
|
||||||
UINT32 w = gdi->primary->hdc->hwnd->invalid->w;
|
|
||||||
UINT32 h = gdi->primary->hdc->hwnd->invalid->h;
|
|
||||||
|
|
||||||
/* Create surface from image data */
|
|
||||||
cairo_surface_t* surface = cairo_image_surface_create_for_data(
|
|
||||||
gdi->primary_buffer + 4*x + y*gdi->stride,
|
|
||||||
CAIRO_FORMAT_RGB24, w, h, gdi->stride);
|
|
||||||
|
|
||||||
/* Send surface to buffer */
|
|
||||||
guac_common_surface_draw(rdp_client->display->default_surface, x, y, surface);
|
|
||||||
|
|
||||||
/* Free surface */
|
|
||||||
cairo_surface_destroy(surface);
|
|
||||||
|
|
||||||
/* Next frame */
|
|
||||||
if (gdi->inGfxFrame) {
|
|
||||||
guac_rdp_gdi_mark_frame(context, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL guac_rdp_gdi_desktop_resize(rdpContext* context) {
|
BOOL guac_rdp_gdi_desktop_resize(rdpContext* context) {
|
||||||
@ -493,8 +391,7 @@ BOOL guac_rdp_gdi_desktop_resize(rdpContext* context) {
|
|||||||
guac_rdp_get_width(context->instance),
|
guac_rdp_get_width(context->instance),
|
||||||
guac_rdp_get_height(context->instance));
|
guac_rdp_get_height(context->instance));
|
||||||
|
|
||||||
return gdi_resize(context->gdi, guac_rdp_get_width(context->instance),
|
return TRUE;
|
||||||
guac_rdp_get_height(context->instance));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,68 +156,8 @@ BOOL guac_rdp_gdi_opaquerect(rdpContext* context,
|
|||||||
BOOL guac_rdp_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds);
|
BOOL guac_rdp_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the internal GDI implementation that a frame is either starting or
|
* Handler called when a paint operation is complete. We don't actually
|
||||||
* ending. If the frame is ending and the connected client is ready to receive
|
* use this, but FreeRDP requires it. Calling this function has no effect.
|
||||||
* a new frame, a new frame will be flushed to the client.
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* The rdpContext associated with the current RDP session.
|
|
||||||
*
|
|
||||||
* @param starting
|
|
||||||
* Non-zero if the frame in question is starting, zero if the frame is
|
|
||||||
* ending.
|
|
||||||
*/
|
|
||||||
void guac_rdp_gdi_mark_frame(rdpContext* context, int starting);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler called when a frame boundary is received from the RDP server in the
|
|
||||||
* form of a frame marker command. Each frame boundary may be the beginning or
|
|
||||||
* the end of a frame.
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* The rdpContext associated with the current RDP session.
|
|
||||||
*
|
|
||||||
* @param frame_marker
|
|
||||||
* The received frame marker.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* TRUE if successful, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
BOOL guac_rdp_gdi_frame_marker(rdpContext* context, const FRAME_MARKER_ORDER* frame_marker);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler called when a frame boundary is received from the RDP server in the
|
|
||||||
* form of a surface frame marker. Each frame boundary may be the beginning or
|
|
||||||
* the end of a frame.
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* The rdpContext associated with the current RDP session.
|
|
||||||
*
|
|
||||||
* @param surface_frame_marker
|
|
||||||
* The received frame marker.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* TRUE if successful, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
BOOL guac_rdp_gdi_surface_frame_marker(rdpContext* context, const SURFACE_FRAME_MARKER* surface_frame_marker);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler called when a paint operation is beginning. This function is
|
|
||||||
* expected to be called by the FreeRDP GDI implementation of RemoteFX when a
|
|
||||||
* new frame has started.
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* The rdpContext associated with the current RDP session.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* TRUE if successful, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
BOOL guac_rdp_gdi_begin_paint(rdpContext* context);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler called when a paint operation is complete. This function is
|
|
||||||
* expected to be called by the FreeRDP GDI implementation of RemoteFX when a
|
|
||||||
* new frame has been completed.
|
|
||||||
*
|
*
|
||||||
* @param context
|
* @param context
|
||||||
* The rdpContext associated with the current RDP session.
|
* The rdpContext associated with the current RDP session.
|
||||||
|
@ -96,11 +96,11 @@ BOOL guac_rdp_glyph_new(rdpContext* context, const rdpGlyph* glyph);
|
|||||||
* The height of the glyph being drawn.
|
* The height of the glyph being drawn.
|
||||||
*
|
*
|
||||||
* @param sx
|
* @param sx
|
||||||
* The X coordinate of the upper-left corner of the glyph within the source
|
* The X coordinare of the upper-left corner of the glyph within the source
|
||||||
* cache surface containing the glyph.
|
* cache surface containing the glyph.
|
||||||
*
|
*
|
||||||
* @param sy
|
* @param sy
|
||||||
* The Y coordinate of the upper-left corner of the glyph within the source
|
* The Y coordinare of the upper-left corner of the glyph within the source
|
||||||
* cache surface containing the glyph.
|
* cache surface containing the glyph.
|
||||||
*
|
*
|
||||||
* @param redundant
|
* @param redundant
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "channels/rdpei.h"
|
#include "channels/rdpei.h"
|
||||||
#include "common/cursor.h"
|
#include "common/cursor.h"
|
||||||
#include "common/display.h"
|
#include "common/display.h"
|
||||||
|
#include "common/recording.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "rdp.h"
|
#include "rdp.h"
|
||||||
@ -29,7 +30,6 @@
|
|||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <freerdp/input.h>
|
#include <freerdp/input.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/recording.h>
|
|
||||||
#include <guacamole/user.h>
|
#include <guacamole/user.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -51,7 +51,7 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
|
|||||||
|
|
||||||
/* Report mouse position within recording */
|
/* Report mouse position within recording */
|
||||||
if (rdp_client->recording != NULL)
|
if (rdp_client->recording != NULL)
|
||||||
guac_recording_report_mouse(rdp_client->recording, x, y, mask);
|
guac_common_recording_report_mouse(rdp_client->recording, x, y, mask);
|
||||||
|
|
||||||
/* If button mask unchanged, just send move event */
|
/* If button mask unchanged, just send move event */
|
||||||
if (mask == rdp_client->mouse_button_mask) {
|
if (mask == rdp_client->mouse_button_mask) {
|
||||||
@ -145,7 +145,7 @@ int guac_rdp_user_touch_handler(guac_user* user, int id, int x, int y,
|
|||||||
|
|
||||||
/* Report touch event within recording */
|
/* Report touch event within recording */
|
||||||
if (rdp_client->recording != NULL)
|
if (rdp_client->recording != NULL)
|
||||||
guac_recording_report_touch(rdp_client->recording, id, x, y,
|
guac_common_recording_report_touch(rdp_client->recording, id, x, y,
|
||||||
x_radius, y_radius, angle, force);
|
x_radius, y_radius, angle, force);
|
||||||
|
|
||||||
/* Forward touch event along RDPEI channel */
|
/* Forward touch event along RDPEI channel */
|
||||||
@ -167,7 +167,7 @@ int guac_rdp_user_key_handler(guac_user* user, int keysym, int pressed) {
|
|||||||
|
|
||||||
/* Report key state within recording */
|
/* Report key state within recording */
|
||||||
if (rdp_client->recording != NULL)
|
if (rdp_client->recording != NULL)
|
||||||
guac_recording_report_key(rdp_client->recording,
|
guac_common_recording_report_key(rdp_client->recording,
|
||||||
keysym, pressed);
|
keysym, pressed);
|
||||||
|
|
||||||
/* Skip if keyboard not yet ready */
|
/* Skip if keyboard not yet ready */
|
||||||
|
@ -140,7 +140,7 @@ static void guac_rdp_send_unicode_event(guac_rdp_client* rdp_client,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immediately sends an RDP synchronize event having the given flags. An RDP
|
* Immediately sends an RDP synchonize event having the given flags. An RDP
|
||||||
* synchronize event sets the state of remote lock keys absolutely, where a
|
* synchronize event sets the state of remote lock keys absolutely, where a
|
||||||
* lock key will be active only if its corresponding flag is set in the event.
|
* lock key will be active only if its corresponding flag is set in the event.
|
||||||
*
|
*
|
||||||
|
@ -1,79 +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.
|
|
||||||
#
|
|
||||||
|
|
||||||
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
|
|
@ -1,55 +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.
|
|
||||||
#
|
|
||||||
|
|
||||||
parent "base"
|
|
||||||
name "fr-ca-qwerty"
|
|
||||||
freerdp "KBD_CANADIAN_FRENCH"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Basic keys
|
|
||||||
#
|
|
||||||
|
|
||||||
map -altgr -shift 0x29 0x02..0x0D ~ "#1234567890-="
|
|
||||||
map -altgr -shift 0x10..0x1B 0x2B ~ "qwertyuiop^¸<"
|
|
||||||
map -altgr -shift 0x1E..0x28 ~ "asdfghjkl;`"
|
|
||||||
map -altgr -shift 0x2C..0x35 ~ "zxcvbnm,.é"
|
|
||||||
|
|
||||||
map -altgr +shift 0x29 0x02..0x0D ~ "|!"/$%?&*()_+"
|
|
||||||
map -altgr +shift 0x10..0x1B 0x2B ~ "QWERTYUIOP^¨>"
|
|
||||||
map -altgr +shift 0x1E..0x28 ~ "ASDFGHJKL:`"
|
|
||||||
map -altgr +shift 0x2C..0x35 ~ "ZXCVBNM'.É"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Keys requiring AltGr
|
|
||||||
#
|
|
||||||
|
|
||||||
map +altgr -shift 0x29 0x02..0x0D ~ "\±@£¢¤¬¦²³¼½¾"
|
|
||||||
map +altgr -shift 0x18..0x1B 0x2B ~ "§¶[]}"
|
|
||||||
map +altgr -shift 0x27..0x28 ~ "~{"
|
|
||||||
map +altgr -shift 0x32..0x33 0x35 ~ "µ¯´"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Combined accents
|
|
||||||
#
|
|
||||||
|
|
||||||
map -altgr -shift 0x1A ~ 0x0302 # COMBINING CIRCUMFLEX ACCENT
|
|
||||||
map -altgr -shift 0x1B ~ 0x0327 # COMBINING CEDILLA
|
|
||||||
map -altgr +shift 0x1B ~ 0x0308 # COMBINING DIAERESIS
|
|
||||||
map -altgr -shift 0x28 ~ 0x0300 # COMBINING GRAVE ACCENT
|
|
||||||
map +altgr -shift 0x35 ~ 0x0301 # COMBINING ACUTE ACCENT
|
|
@ -1,64 +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.
|
|
||||||
#
|
|
||||||
|
|
||||||
parent "base"
|
|
||||||
name "pl-pl-qwerty"
|
|
||||||
freerdp "KBD_POLISH_PROGRAMMERS"
|
|
||||||
|
|
||||||
map -caps -shift 0x29 0x02..0x0D ~ "`1234567890-="
|
|
||||||
map -caps -shift 0x10..0x1B 0x2B ~ "qwertyuiop[]\"
|
|
||||||
map -caps -shift 0x1E..0x28 ~ "asdfghjkl;'"
|
|
||||||
map -caps -shift 0x2C..0x35 ~ "zxcvbnm,./"
|
|
||||||
|
|
||||||
map -caps +shift 0x29 0x02..0x0D ~ "~!@#$%^&*()_+"
|
|
||||||
map -caps +shift 0x10..0x1B 0x2B ~ "QWERTYUIOP{}|"
|
|
||||||
map -caps +shift 0x1E..0x28 ~ "ASDFGHJKL:""
|
|
||||||
map -caps +shift 0x2C..0x35 ~ "ZXCVBNM<>?"
|
|
||||||
|
|
||||||
map +caps -shift 0x29 0x02..0x0D ~ "`1234567890-="
|
|
||||||
map +caps -shift 0x10..0x1B 0x2B ~ "QWERTYUIOP[]\"
|
|
||||||
map +caps -shift 0x1E..0x28 ~ "ASDFGHJKL;'"
|
|
||||||
map +caps -shift 0x2C..0x35 ~ "ZXCVBNM,./"
|
|
||||||
|
|
||||||
map +caps +shift 0x29 0x02..0x0D ~ "~!@#$%^&*()_+"
|
|
||||||
map +caps +shift 0x10..0x1B 0x2B ~ "qwertyuiop{}|"
|
|
||||||
map +caps +shift 0x1E..0x28 ~ "asdfghjkl:""
|
|
||||||
map +caps +shift 0x2C..0x35 ~ "zxcvbnm<>?"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Keys requiring AltGr
|
|
||||||
#
|
|
||||||
|
|
||||||
map +altgr -shift 0x16 ~ "€"
|
|
||||||
|
|
||||||
map -caps -shift +altgr 0x12 0x18 ~ "ęó"
|
|
||||||
map -caps -shift +altgr 0x1E 0x1F 0x26 ~ "ąśł"
|
|
||||||
map -caps -shift +altgr 0x2C 0x2D 0x2E 0x31 ~ "żźćń"
|
|
||||||
|
|
||||||
map -caps +shift +altgr 0x12 0x18 ~ "ĘÓ"
|
|
||||||
map -caps +shift +altgr 0x1E 0x1F 0x26 ~ "ĄŚŁ"
|
|
||||||
map -caps +shift +altgr 0x2C 0x2D 0x2E 0x31 ~ "ŻŹĆŃ"
|
|
||||||
|
|
||||||
map +caps -shift +altgr 0x12 0x18 ~ "ĘÓ"
|
|
||||||
map +caps -shift +altgr 0x1E 0x1F 0x26 ~ "ĄŚŁ"
|
|
||||||
map +caps -shift +altgr 0x2C 0x2D 0x2E 0x31 ~ "ŻŹĆŃ"
|
|
||||||
|
|
||||||
map +caps +shift +altgr 0x12 0x18 ~ "ęó"
|
|
||||||
map +caps +shift +altgr 0x1E 0x1F 0x26 ~ "ąśł"
|
|
||||||
map +caps +shift +altgr 0x2C 0x2D 0x2E 0x31 ~ "żźćń"
|
|
@ -25,7 +25,6 @@
|
|||||||
#include <guacamole/socket.h>
|
#include <guacamole/socket.h>
|
||||||
#include <guacamole/stream.h>
|
#include <guacamole/stream.h>
|
||||||
#include <guacamole/user.h>
|
#include <guacamole/user.h>
|
||||||
#include <winpr/file.h>
|
|
||||||
#include <winpr/nt.h>
|
#include <winpr/nt.h>
|
||||||
#include <winpr/shell.h>
|
#include <winpr/shell.h>
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ void guac_rdp_ai_process_version(guac_client* client,
|
|||||||
|
|
||||||
/* Verify we have at least 4 bytes available (UINT32) */
|
/* Verify we have at least 4 bytes available (UINT32) */
|
||||||
if (Stream_GetRemainingLength(stream) < 4) {
|
if (Stream_GetRemainingLength(stream) < 4) {
|
||||||
guac_client_log(client, GUAC_LOG_WARNING, "Audio input Version PDU "
|
guac_client_log(client, GUAC_LOG_WARNING, "Audio input Versoin PDU "
|
||||||
"does not contain the expected number of bytes. Audio input "
|
"does not contain the expected number of bytes. Audio input "
|
||||||
"redirection may not work as expected.");
|
"redirection may not work as expected.");
|
||||||
return;
|
return;
|
||||||
|
@ -279,7 +279,7 @@ static UINT guac_rdp_ai_terminated(IWTSPlugin* plugin) {
|
|||||||
/**
|
/**
|
||||||
* Entry point for AUDIO_INPUT dynamic virtual channel.
|
* Entry point for AUDIO_INPUT dynamic virtual channel.
|
||||||
*/
|
*/
|
||||||
UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) {
|
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) {
|
||||||
|
|
||||||
/* Pull guac_client from arguments */
|
/* Pull guac_client from arguments */
|
||||||
ADDIN_ARGV* args = pEntryPoints->GetPluginData(pEntryPoints);
|
ADDIN_ARGV* args = pEntryPoints->GetPluginData(pEntryPoints);
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "common/cursor.h"
|
#include "common/cursor.h"
|
||||||
#include "common/display.h"
|
#include "common/display.h"
|
||||||
#include "common/surface.h"
|
#include "common/surface.h"
|
||||||
#include "gdi.h"
|
|
||||||
#include "pointer.h"
|
#include "pointer.h"
|
||||||
#include "rdp.h"
|
#include "rdp.h"
|
||||||
|
|
||||||
@ -79,22 +78,11 @@ BOOL guac_rdp_pointer_set(rdpContext* context, const rdpPointer* pointer) {
|
|||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
|
||||||
/* Add explicit frame boundaries around cursor set operation if not already
|
|
||||||
* in a frame (the RDP protocol does not send nor expect frame boundaries
|
|
||||||
* for cursor changes, but Guacamole does expect this) */
|
|
||||||
int in_frame = rdp_client->in_frame;
|
|
||||||
|
|
||||||
if (rdp_client->frames_supported && !in_frame)
|
|
||||||
guac_rdp_gdi_mark_frame(context, 1);
|
|
||||||
|
|
||||||
/* Set cursor */
|
/* Set cursor */
|
||||||
guac_common_cursor_set_surface(rdp_client->display->cursor,
|
guac_common_cursor_set_surface(rdp_client->display->cursor,
|
||||||
pointer->xPos, pointer->yPos,
|
pointer->xPos, pointer->yPos,
|
||||||
((guac_rdp_pointer*) pointer)->layer->surface);
|
((guac_rdp_pointer*) pointer)->layer->surface);
|
||||||
|
|
||||||
if (rdp_client->frames_supported && !in_frame)
|
|
||||||
guac_rdp_gdi_mark_frame(context, 0);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -118,20 +106,9 @@ BOOL guac_rdp_pointer_set_null(rdpContext* context) {
|
|||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
|
||||||
/* Add explicit frame boundaries around cursor set operation if not already
|
|
||||||
* in a frame (the RDP protocol does not send nor expect frame boundaries
|
|
||||||
* for cursor changes, but Guacamole does expect this) */
|
|
||||||
int in_frame = rdp_client->in_frame;
|
|
||||||
|
|
||||||
if (rdp_client->frames_supported && !in_frame)
|
|
||||||
guac_rdp_gdi_mark_frame(context, 1);
|
|
||||||
|
|
||||||
/* Set cursor to empty/blank graphic */
|
/* Set cursor to empty/blank graphic */
|
||||||
guac_common_cursor_set_blank(rdp_client->display->cursor);
|
guac_common_cursor_set_blank(rdp_client->display->cursor);
|
||||||
|
|
||||||
if (rdp_client->frames_supported && !in_frame)
|
|
||||||
guac_rdp_gdi_mark_frame(context, 0);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -141,20 +118,9 @@ BOOL guac_rdp_pointer_set_default(rdpContext* context) {
|
|||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
|
||||||
/* Add explicit frame boundaries around cursor set operation if not already
|
|
||||||
* in a frame (the RDP protocol does not send nor expect frame boundaries
|
|
||||||
* for cursor changes, but Guacamole does expect this) */
|
|
||||||
int in_frame = rdp_client->in_frame;
|
|
||||||
|
|
||||||
if (rdp_client->frames_supported && !in_frame)
|
|
||||||
guac_rdp_gdi_mark_frame(context, 1);
|
|
||||||
|
|
||||||
/* Set cursor to embedded pointer */
|
/* Set cursor to embedded pointer */
|
||||||
guac_common_cursor_set_pointer(rdp_client->display->cursor);
|
guac_common_cursor_set_pointer(rdp_client->display->cursor);
|
||||||
|
|
||||||
if (rdp_client->frames_supported && !in_frame)
|
|
||||||
guac_rdp_gdi_mark_frame(context, 0);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "print-job.h"
|
#include "print-job.h"
|
||||||
#include "rdp.h"
|
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/protocol.h>
|
#include <guacamole/protocol.h>
|
||||||
@ -28,7 +27,6 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -605,9 +603,6 @@ static void guac_rdp_print_job_read_filename(guac_rdp_print_job* job,
|
|||||||
int guac_rdp_print_job_write(guac_rdp_print_job* job,
|
int guac_rdp_print_job_write(guac_rdp_print_job* job,
|
||||||
void* buffer, int length) {
|
void* buffer, int length) {
|
||||||
|
|
||||||
guac_client* client = job->client;
|
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
|
||||||
|
|
||||||
/* Create print job, if not yet created */
|
/* Create print job, if not yet created */
|
||||||
if (job->bytes_received == 0) {
|
if (job->bytes_received == 0) {
|
||||||
|
|
||||||
@ -623,40 +618,19 @@ int guac_rdp_print_job_write(guac_rdp_print_job* job,
|
|||||||
/* Update counter of bytes received */
|
/* Update counter of bytes received */
|
||||||
job->bytes_received += length;
|
job->bytes_received += length;
|
||||||
|
|
||||||
/* Write data to filter process, unblocking any threads waiting on the
|
/* Write data to filter process */
|
||||||
* generic RDP message lock as this may be a lengthy operation that depends
|
return write(job->input_fd, buffer, length);
|
||||||
* on other threads sending outstanding messages (resulting in deadlock if
|
|
||||||
* those messages are blocked) */
|
|
||||||
int unlock_status = pthread_mutex_unlock(&(rdp_client->message_lock));
|
|
||||||
int write_status = write(job->input_fd, buffer, length);
|
|
||||||
|
|
||||||
/* Restore RDP message lock state */
|
|
||||||
if (!unlock_status)
|
|
||||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
|
||||||
|
|
||||||
return write_status;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_rdp_print_job_free(guac_rdp_print_job* job) {
|
void guac_rdp_print_job_free(guac_rdp_print_job* job) {
|
||||||
|
|
||||||
guac_client* client = job->client;
|
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
|
||||||
|
|
||||||
/* No more input will be provided */
|
/* No more input will be provided */
|
||||||
close(job->input_fd);
|
close(job->input_fd);
|
||||||
|
|
||||||
/* Wait for job to terminate, unblocking any threads waiting on the generic
|
/* Wait for job to terminate */
|
||||||
* RDP message lock as this may be a lengthy operation that depends on
|
|
||||||
* other threads sending outstanding messages (resulting in deadlock if
|
|
||||||
* those messages are blocked) */
|
|
||||||
int unlock_status = pthread_mutex_unlock(&(rdp_client->message_lock));
|
|
||||||
pthread_join(job->output_thread, NULL);
|
pthread_join(job->output_thread, NULL);
|
||||||
|
|
||||||
/* Restore RDP message lock state */
|
|
||||||
if (!unlock_status)
|
|
||||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
|
||||||
|
|
||||||
/* Destroy lock */
|
/* Destroy lock */
|
||||||
pthread_mutex_destroy(&(job->state_lock));
|
pthread_mutex_destroy(&(job->state_lock));
|
||||||
|
|
||||||
@ -667,9 +641,6 @@ void guac_rdp_print_job_free(guac_rdp_print_job* job) {
|
|||||||
|
|
||||||
void guac_rdp_print_job_kill(guac_rdp_print_job* job) {
|
void guac_rdp_print_job_kill(guac_rdp_print_job* job) {
|
||||||
|
|
||||||
/* Forcibly kill filter process, if running */
|
|
||||||
kill(job->filter_pid, SIGKILL);
|
|
||||||
|
|
||||||
/* Stop all handling of I/O */
|
/* Stop all handling of I/O */
|
||||||
close(job->input_fd);
|
close(job->input_fd);
|
||||||
close(job->output_fd);
|
close(job->output_fd);
|
||||||
|
@ -28,12 +28,12 @@
|
|||||||
#include "channels/rail.h"
|
#include "channels/rail.h"
|
||||||
#include "channels/rdpdr/rdpdr.h"
|
#include "channels/rdpdr/rdpdr.h"
|
||||||
#include "channels/rdpei.h"
|
#include "channels/rdpei.h"
|
||||||
#include "channels/rdpgfx.h"
|
|
||||||
#include "channels/rdpsnd/rdpsnd.h"
|
#include "channels/rdpsnd/rdpsnd.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "common/cursor.h"
|
#include "common/cursor.h"
|
||||||
#include "common/display.h"
|
#include "common/display.h"
|
||||||
|
#include "common/recording.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
@ -71,7 +71,6 @@
|
|||||||
#include <guacamole/audio.h>
|
#include <guacamole/audio.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/protocol.h>
|
#include <guacamole/protocol.h>
|
||||||
#include <guacamole/recording.h>
|
|
||||||
#include <guacamole/socket.h>
|
#include <guacamole/socket.h>
|
||||||
#include <guacamole/string.h>
|
#include <guacamole/string.h>
|
||||||
#include <guacamole/timestamp.h>
|
#include <guacamole/timestamp.h>
|
||||||
@ -138,6 +137,15 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load plugin providing Dynamic Virtual Channel support, if required */
|
||||||
|
if (instance->settings->SupportDynamicChannels &&
|
||||||
|
guac_freerdp_channels_load_plugin(context, "drdynvc",
|
||||||
|
instance->settings)) {
|
||||||
|
guac_client_log(client, GUAC_LOG_WARNING,
|
||||||
|
"Failed to load drdynvc plugin. Display update and audio "
|
||||||
|
"input support will be disabled.");
|
||||||
|
}
|
||||||
|
|
||||||
/* Init FreeRDP internal GDI implementation */
|
/* Init FreeRDP internal GDI implementation */
|
||||||
if (!gdi_init(instance, guac_rdp_get_native_pixel_format(FALSE)))
|
if (!gdi_init(instance, guac_rdp_get_native_pixel_format(FALSE)))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -179,13 +187,9 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
|
|
||||||
/* Set up GDI */
|
/* Set up GDI */
|
||||||
instance->update->DesktopResize = guac_rdp_gdi_desktop_resize;
|
instance->update->DesktopResize = guac_rdp_gdi_desktop_resize;
|
||||||
instance->update->BeginPaint = guac_rdp_gdi_begin_paint;
|
|
||||||
instance->update->EndPaint = guac_rdp_gdi_end_paint;
|
instance->update->EndPaint = guac_rdp_gdi_end_paint;
|
||||||
instance->update->SetBounds = guac_rdp_gdi_set_bounds;
|
instance->update->SetBounds = guac_rdp_gdi_set_bounds;
|
||||||
|
|
||||||
instance->update->SurfaceFrameMarker = guac_rdp_gdi_surface_frame_marker;
|
|
||||||
instance->update->altsec->FrameMarker = guac_rdp_gdi_frame_marker;
|
|
||||||
|
|
||||||
rdpPrimaryUpdate* primary = instance->update->primary;
|
rdpPrimaryUpdate* primary = instance->update->primary;
|
||||||
primary->DstBlt = guac_rdp_gdi_dstblt;
|
primary->DstBlt = guac_rdp_gdi_dstblt;
|
||||||
primary->PatBlt = guac_rdp_gdi_patblt;
|
primary->PatBlt = guac_rdp_gdi_patblt;
|
||||||
@ -200,19 +204,6 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
offscreen_cache_register_callbacks(instance->update);
|
offscreen_cache_register_callbacks(instance->update);
|
||||||
palette_cache_register_callbacks(instance->update);
|
palette_cache_register_callbacks(instance->update);
|
||||||
|
|
||||||
/* Load "rdpgfx" plugin for Graphics Pipeline Extension */
|
|
||||||
if (settings->enable_gfx)
|
|
||||||
guac_rdp_rdpgfx_load_plugin(context);
|
|
||||||
|
|
||||||
/* Load plugin providing Dynamic Virtual Channel support, if required */
|
|
||||||
if (instance->settings->SupportDynamicChannels &&
|
|
||||||
guac_freerdp_channels_load_plugin(context, "drdynvc",
|
|
||||||
instance->settings)) {
|
|
||||||
guac_client_log(client, GUAC_LOG_WARNING,
|
|
||||||
"Failed to load drdynvc plugin. Display update and audio "
|
|
||||||
"input support will be disabled.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -553,6 +544,7 @@ static int guac_rdp_handle_connection(guac_client* client) {
|
|||||||
if (wait_result > 0) {
|
if (wait_result > 0) {
|
||||||
|
|
||||||
int processing_lag = guac_client_get_processing_lag(client);
|
int processing_lag = guac_client_get_processing_lag(client);
|
||||||
|
guac_timestamp frame_start = guac_timestamp_current();
|
||||||
|
|
||||||
/* Read server messages until frame is built */
|
/* Read server messages until frame is built */
|
||||||
do {
|
do {
|
||||||
@ -572,15 +564,7 @@ static int guac_rdp_handle_connection(guac_client* client) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Continue handling inbound data if we are in the middle of an RDP frame */
|
|
||||||
if (rdp_client->in_frame) {
|
|
||||||
wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_FRAME_START_TIMEOUT);
|
|
||||||
if (wait_result >= 0)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate time remaining in frame */
|
/* Calculate time remaining in frame */
|
||||||
guac_timestamp frame_start = client->last_sent_timestamp;
|
|
||||||
frame_end = guac_timestamp_current();
|
frame_end = guac_timestamp_current();
|
||||||
frame_remaining = frame_start + GUAC_RDP_FRAME_DURATION
|
frame_remaining = frame_start + GUAC_RDP_FRAME_DURATION
|
||||||
- frame_end;
|
- frame_end;
|
||||||
@ -603,6 +587,12 @@ static int guac_rdp_handle_connection(guac_client* client) {
|
|||||||
|
|
||||||
} while (wait_result > 0);
|
} while (wait_result > 0);
|
||||||
|
|
||||||
|
/* Record end of frame, excluding server-side rendering time (we
|
||||||
|
* assume server-side rendering time will be consistent between any
|
||||||
|
* two subsequent frames, and that this time should thus be
|
||||||
|
* excluded from the required wait period of the next frame). */
|
||||||
|
last_frame_end = frame_start;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test whether the RDP server is closing the connection */
|
/* Test whether the RDP server is closing the connection */
|
||||||
@ -617,13 +607,11 @@ static int guac_rdp_handle_connection(guac_client* client) {
|
|||||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_UNAVAILABLE,
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_UNAVAILABLE,
|
||||||
"Connection closed.");
|
"Connection closed.");
|
||||||
|
|
||||||
/* Flush frame only if successful and an RDP frame is not known to be
|
/* Flush frame only if successful */
|
||||||
* in progress */
|
else {
|
||||||
else if (!rdp_client->frames_supported || rdp_client->frames_received) {
|
|
||||||
guac_common_display_flush(rdp_client->display);
|
guac_common_display_flush(rdp_client->display);
|
||||||
guac_client_end_multiple_frames(client, rdp_client->frames_received);
|
guac_client_end_frame(client);
|
||||||
guac_socket_flush(client->socket);
|
guac_socket_flush(client->socket);
|
||||||
rdp_client->frames_received = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -818,7 +806,7 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
|
|
||||||
/* Set up screen recording, if requested */
|
/* Set up screen recording, if requested */
|
||||||
if (settings->recording_path != NULL) {
|
if (settings->recording_path != NULL) {
|
||||||
rdp_client->recording = guac_recording_create(client,
|
rdp_client->recording = guac_common_recording_create(client,
|
||||||
settings->recording_path,
|
settings->recording_path,
|
||||||
settings->recording_name,
|
settings->recording_name,
|
||||||
settings->create_recording_path,
|
settings->create_recording_path,
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "common/clipboard.h"
|
#include "common/clipboard.h"
|
||||||
#include "common/display.h"
|
#include "common/display.h"
|
||||||
#include "common/list.h"
|
#include "common/list.h"
|
||||||
|
#include "common/recording.h"
|
||||||
#include "common/surface.h"
|
#include "common/surface.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
@ -44,7 +45,6 @@
|
|||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <guacamole/audio.h>
|
#include <guacamole/audio.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/recording.h>
|
|
||||||
#include <winpr/wtypes.h>
|
#include <winpr/wtypes.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@ -91,24 +91,6 @@ typedef struct guac_rdp_client {
|
|||||||
*/
|
*/
|
||||||
guac_common_surface* current_surface;
|
guac_common_surface* current_surface;
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the RDP server supports defining explicit frame boundaries.
|
|
||||||
*/
|
|
||||||
int frames_supported;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the RDP server has reported that a new frame is in progress, and
|
|
||||||
* we are now receiving updates relevant to that frame.
|
|
||||||
*/
|
|
||||||
int in_frame;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of distinct frames received from the RDP server since last
|
|
||||||
* flush, if the RDP server supports reporting frame boundaries. If the RDP
|
|
||||||
* server does not support tracking frames, this will be zero.
|
|
||||||
*/
|
|
||||||
int frames_received;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current state of the keyboard with respect to the RDP session.
|
* The current state of the keyboard with respect to the RDP session.
|
||||||
*/
|
*/
|
||||||
@ -160,7 +142,7 @@ typedef struct guac_rdp_client {
|
|||||||
* The in-progress session recording, or NULL if no recording is in
|
* The in-progress session recording, or NULL if no recording is in
|
||||||
* progress.
|
* progress.
|
||||||
*/
|
*/
|
||||||
guac_recording* recording;
|
guac_common_recording* recording;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display size update module.
|
* Display size update module.
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include <freerdp/settings.h>
|
#include <freerdp/settings.h>
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/fips.h>
|
|
||||||
#include <guacamole/string.h>
|
#include <guacamole/string.h>
|
||||||
#include <guacamole/user.h>
|
#include <guacamole/user.h>
|
||||||
#include <guacamole/wol-constants.h>
|
#include <guacamole/wol-constants.h>
|
||||||
@ -40,16 +39,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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 */
|
/* Client plugin arguments */
|
||||||
const char* GUAC_RDP_CLIENT_ARGS[] = {
|
const char* GUAC_RDP_CLIENT_ARGS[] = {
|
||||||
"hostname",
|
"hostname",
|
||||||
@ -91,7 +80,6 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {
|
|||||||
"disable-bitmap-caching",
|
"disable-bitmap-caching",
|
||||||
"disable-offscreen-caching",
|
"disable-offscreen-caching",
|
||||||
"disable-glyph-caching",
|
"disable-glyph-caching",
|
||||||
"disable-gfx",
|
|
||||||
"preconnection-id",
|
"preconnection-id",
|
||||||
"preconnection-blob",
|
"preconnection-blob",
|
||||||
"timezone",
|
"timezone",
|
||||||
@ -372,7 +360,7 @@ enum RDP_ARGS_IDX {
|
|||||||
IDX_DISABLE_BITMAP_CACHING,
|
IDX_DISABLE_BITMAP_CACHING,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "true" if the offscreen caching should be disabled, false if offscreen
|
* "true" if the offscreen caching should be disabled, false if offscren
|
||||||
* caching should remain enabled.
|
* caching should remain enabled.
|
||||||
*/
|
*/
|
||||||
IDX_DISABLE_OFFSCREEN_CACHING,
|
IDX_DISABLE_OFFSCREEN_CACHING,
|
||||||
@ -383,13 +371,6 @@ enum RDP_ARGS_IDX {
|
|||||||
*/
|
*/
|
||||||
IDX_DISABLE_GLYPH_CACHING,
|
IDX_DISABLE_GLYPH_CACHING,
|
||||||
|
|
||||||
/**
|
|
||||||
* "true" if the RDP Graphics Pipeline Extension should not be used, and
|
|
||||||
* traditional RDP graphics should be used instead, "false" or blank if the
|
|
||||||
* Graphics Pipeline Extension should be used if available.
|
|
||||||
*/
|
|
||||||
IDX_DISABLE_GFX,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The preconnection ID to send within the preconnection PDU when
|
* The preconnection ID to send within the preconnection PDU when
|
||||||
* initiating an RDP connection, if any.
|
* initiating an RDP connection, if any.
|
||||||
@ -717,27 +698,12 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
|
|||||||
if (strcmp(argv[IDX_SECURITY], "nla") == 0) {
|
if (strcmp(argv[IDX_SECURITY], "nla") == 0) {
|
||||||
guac_user_log(user, GUAC_LOG_INFO, "Security mode: NLA");
|
guac_user_log(user, GUAC_LOG_INFO, "Security mode: NLA");
|
||||||
settings->security_mode = GUAC_SECURITY_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 */
|
/* Extended NLA security */
|
||||||
else if (strcmp(argv[IDX_SECURITY], "nla-ext") == 0) {
|
else if (strcmp(argv[IDX_SECURITY], "nla-ext") == 0) {
|
||||||
guac_user_log(user, GUAC_LOG_INFO, "Security mode: Extended NLA");
|
guac_user_log(user, GUAC_LOG_INFO, "Security mode: Extended NLA");
|
||||||
settings->security_mode = GUAC_SECURITY_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 */
|
/* TLS security */
|
||||||
@ -942,6 +908,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
|
|||||||
GUAC_RDP_CLIENT_ARGS[IDX_DISABLE_GLYPH_CACHING]);
|
GUAC_RDP_CLIENT_ARGS[IDX_DISABLE_GLYPH_CACHING]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Session color depth */
|
||||||
|
settings->color_depth =
|
||||||
|
guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
|
||||||
|
IDX_COLOR_DEPTH, RDP_DEFAULT_DEPTH);
|
||||||
|
|
||||||
/* Preconnection ID */
|
/* Preconnection ID */
|
||||||
settings->preconnection_id = -1;
|
settings->preconnection_id = -1;
|
||||||
if (argv[IDX_PRECONNECTION_ID][0] != '\0') {
|
if (argv[IDX_PRECONNECTION_ID][0] != '\0') {
|
||||||
@ -1158,16 +1129,6 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
|
|||||||
settings->resize_method = GUAC_RESIZE_NONE;
|
settings->resize_method = GUAC_RESIZE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RDP Graphics Pipeline enable/disable */
|
|
||||||
settings->enable_gfx =
|
|
||||||
!guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
|
||||||
IDX_DISABLE_GFX, 0);
|
|
||||||
|
|
||||||
/* Session color depth */
|
|
||||||
settings->color_depth =
|
|
||||||
guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
|
|
||||||
IDX_COLOR_DEPTH, settings->enable_gfx ? RDP_GFX_REQUIRED_DEPTH : RDP_DEFAULT_DEPTH);
|
|
||||||
|
|
||||||
/* Multi-touch input enable/disable */
|
/* Multi-touch input enable/disable */
|
||||||
settings->enable_touch =
|
settings->enable_touch =
|
||||||
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
||||||
@ -1436,29 +1397,6 @@ void guac_rdp_push_settings(guac_client* client,
|
|||||||
/* Explicitly set flag value */
|
/* Explicitly set flag value */
|
||||||
rdp_settings->PerformanceFlags = guac_rdp_get_performance_flags(guac_settings);
|
rdp_settings->PerformanceFlags = guac_rdp_get_performance_flags(guac_settings);
|
||||||
|
|
||||||
/* Always request frame markers */
|
|
||||||
rdp_settings->FrameMarkerCommandEnabled = TRUE;
|
|
||||||
rdp_settings->SurfaceFrameMarkerEnabled = TRUE;
|
|
||||||
|
|
||||||
/* Enable RemoteFX / Graphics Pipeline */
|
|
||||||
if (guac_settings->enable_gfx) {
|
|
||||||
|
|
||||||
rdp_settings->SupportGraphicsPipeline = TRUE;
|
|
||||||
rdp_settings->RemoteFxCodec = TRUE;
|
|
||||||
|
|
||||||
if (rdp_settings->ColorDepth != RDP_GFX_REQUIRED_DEPTH) {
|
|
||||||
guac_client_log(client, GUAC_LOG_WARNING, "Ignoring requested "
|
|
||||||
"color depth of %i bpp, as the RDP Graphics Pipeline "
|
|
||||||
"requires %i bpp.", rdp_settings->ColorDepth, RDP_GFX_REQUIRED_DEPTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Required for RemoteFX / Graphics Pipeline */
|
|
||||||
rdp_settings->FastPathOutput = TRUE;
|
|
||||||
rdp_settings->ColorDepth = RDP_GFX_REQUIRED_DEPTH;
|
|
||||||
rdp_settings->SoftwareGdi = TRUE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set individual flags - some FreeRDP versions overwrite the above */
|
/* Set individual flags - some FreeRDP versions overwrite the above */
|
||||||
rdp_settings->AllowFontSmoothing = guac_settings->font_smoothing_enabled;
|
rdp_settings->AllowFontSmoothing = guac_settings->font_smoothing_enabled;
|
||||||
rdp_settings->DisableWallpaper = !guac_settings->wallpaper_enabled;
|
rdp_settings->DisableWallpaper = !guac_settings->wallpaper_enabled;
|
||||||
@ -1555,21 +1493,7 @@ void guac_rdp_push_settings(guac_client* client,
|
|||||||
case GUAC_SECURITY_ANY:
|
case GUAC_SECURITY_ANY:
|
||||||
rdp_settings->RdpSecurity = TRUE;
|
rdp_settings->RdpSecurity = TRUE;
|
||||||
rdp_settings->TlsSecurity = 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;
|
rdp_settings->ExtSecurity = FALSE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1585,8 +1509,12 @@ void guac_rdp_push_settings(guac_client* client,
|
|||||||
rdp_settings->RemoteApplicationMode = TRUE;
|
rdp_settings->RemoteApplicationMode = TRUE;
|
||||||
rdp_settings->RemoteAppLanguageBarSupported = TRUE;
|
rdp_settings->RemoteAppLanguageBarSupported = TRUE;
|
||||||
rdp_settings->RemoteApplicationProgram = guac_strdup(guac_settings->remote_app);
|
rdp_settings->RemoteApplicationProgram = guac_strdup(guac_settings->remote_app);
|
||||||
rdp_settings->ShellWorkingDirectory = guac_strdup(guac_settings->remote_app_dir);
|
if (guac_settings->remote_app_dir != NULL)
|
||||||
|
rdp_settings->RemoteApplicationWorkingDir = guac_strdup(guac_settings->remote_app_dir);
|
||||||
rdp_settings->RemoteApplicationCmdLine = guac_strdup(guac_settings->remote_app_args);
|
rdp_settings->RemoteApplicationCmdLine = guac_strdup(guac_settings->remote_app_args);
|
||||||
|
rdp_settings->DisableWallpaper = TRUE;
|
||||||
|
rdp_settings->DisableFullWindowDrag = TRUE;
|
||||||
|
rdp_settings->Decorations = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Preconnection ID */
|
/* Preconnection ID */
|
||||||
@ -1632,7 +1560,7 @@ void guac_rdp_push_settings(guac_client* client,
|
|||||||
rdp_settings->GlyphSupportLevel = !guac_settings->disable_glyph_caching ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE;
|
rdp_settings->GlyphSupportLevel = !guac_settings->disable_glyph_caching ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE;
|
||||||
rdp_settings->OsMajorType = OSMAJORTYPE_UNSPECIFIED;
|
rdp_settings->OsMajorType = OSMAJORTYPE_UNSPECIFIED;
|
||||||
rdp_settings->OsMinorType = OSMINORTYPE_UNSPECIFIED;
|
rdp_settings->OsMinorType = OSMINORTYPE_UNSPECIFIED;
|
||||||
rdp_settings->DesktopResize = TRUE;
|
rdp_settings->DesktopResize = FALSE;
|
||||||
|
|
||||||
/* Claim support only for specific updates, independent of FreeRDP defaults */
|
/* Claim support only for specific updates, independent of FreeRDP defaults */
|
||||||
ZeroMemory(rdp_settings->OrderSupport, GUAC_RDP_ORDER_SUPPORT_LENGTH);
|
ZeroMemory(rdp_settings->OrderSupport, GUAC_RDP_ORDER_SUPPORT_LENGTH);
|
||||||
|
@ -58,11 +58,6 @@
|
|||||||
*/
|
*/
|
||||||
#define RDP_DEFAULT_DEPTH 16
|
#define RDP_DEFAULT_DEPTH 16
|
||||||
|
|
||||||
/**
|
|
||||||
* The color depth required by the RDPGFX channel, in bits.
|
|
||||||
*/
|
|
||||||
#define RDP_GFX_REQUIRED_DEPTH 32
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The filename to use for the screen recording, if not specified.
|
* The filename to use for the screen recording, if not specified.
|
||||||
*/
|
*/
|
||||||
@ -557,11 +552,6 @@ typedef struct guac_rdp_settings {
|
|||||||
*/
|
*/
|
||||||
int enable_audio_input;
|
int enable_audio_input;
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the RDP Graphics Pipeline Extension is enabled.
|
|
||||||
*/
|
|
||||||
int enable_gfx;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether multi-touch support is enabled.
|
* Whether multi-touch support is enabled.
|
||||||
*/
|
*/
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
#include <guacamole/user.h>
|
#include <guacamole/user.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -55,12 +54,10 @@ int guac_ssh_argv_callback(guac_user* user, const char* mimetype,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update SSH pty size if connected */
|
/* Update SSH pty size if connected */
|
||||||
int term_width = guac_terminal_get_columns(terminal);
|
|
||||||
int term_height = guac_terminal_get_rows(terminal);
|
|
||||||
if (ssh_client->term_channel != NULL) {
|
if (ssh_client->term_channel != NULL) {
|
||||||
pthread_mutex_lock(&(ssh_client->term_channel_lock));
|
pthread_mutex_lock(&(ssh_client->term_channel_lock));
|
||||||
libssh2_channel_request_pty_size(ssh_client->term_channel,
|
libssh2_channel_request_pty_size(ssh_client->term_channel,
|
||||||
term_width, term_height);
|
terminal->term_width, terminal->term_height);
|
||||||
pthread_mutex_unlock(&(ssh_client->term_channel_lock));
|
pthread_mutex_unlock(&(ssh_client->term_channel_lock));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,17 +72,15 @@ void* guac_ssh_send_current_argv(guac_user* user, void* data) {
|
|||||||
|
|
||||||
/* Send current color scheme */
|
/* Send current color scheme */
|
||||||
guac_user_stream_argv(user, user->socket, "text/plain",
|
guac_user_stream_argv(user, user->socket, "text/plain",
|
||||||
GUAC_SSH_ARGV_COLOR_SCHEME,
|
GUAC_SSH_ARGV_COLOR_SCHEME, terminal->color_scheme);
|
||||||
guac_terminal_get_color_scheme(terminal));
|
|
||||||
|
|
||||||
/* Send current font name */
|
/* Send current font name */
|
||||||
guac_user_stream_argv(user, user->socket, "text/plain",
|
guac_user_stream_argv(user, user->socket, "text/plain",
|
||||||
GUAC_SSH_ARGV_FONT_NAME,
|
GUAC_SSH_ARGV_FONT_NAME, terminal->font_name);
|
||||||
guac_terminal_get_font_name(terminal));
|
|
||||||
|
|
||||||
/* Send current font size */
|
/* Send current font size */
|
||||||
char font_size[64];
|
char font_size[64];
|
||||||
sprintf(font_size, "%i", guac_terminal_get_font_size(terminal));
|
sprintf(font_size, "%i", terminal->font_size);
|
||||||
guac_user_stream_argv(user, user->socket, "text/plain",
|
guac_user_stream_argv(user, user->socket, "text/plain",
|
||||||
GUAC_SSH_ARGV_FONT_SIZE, font_size);
|
GUAC_SSH_ARGV_FONT_SIZE, font_size);
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include "argv.h"
|
#include "argv.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
#include "common/clipboard.h"
|
||||||
|
#include "common/recording.h"
|
||||||
#include "common-ssh/sftp.h"
|
#include "common-ssh/sftp.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "terminal/terminal.h"
|
#include "terminal/terminal.h"
|
||||||
@ -33,7 +35,6 @@
|
|||||||
|
|
||||||
#include <guacamole/argv.h>
|
#include <guacamole/argv.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/recording.h>
|
|
||||||
|
|
||||||
int guac_client_init(guac_client* client) {
|
int guac_client_init(guac_client* client) {
|
||||||
|
|
||||||
@ -44,6 +45,9 @@ int guac_client_init(guac_client* client) {
|
|||||||
guac_ssh_client* ssh_client = calloc(1, sizeof(guac_ssh_client));
|
guac_ssh_client* ssh_client = calloc(1, sizeof(guac_ssh_client));
|
||||||
client->data = ssh_client;
|
client->data = ssh_client;
|
||||||
|
|
||||||
|
/* Init clipboard */
|
||||||
|
ssh_client->clipboard = guac_common_clipboard_alloc(GUAC_SSH_CLIPBOARD_MAX_LENGTH);
|
||||||
|
|
||||||
/* Set handlers */
|
/* Set handlers */
|
||||||
client->join_handler = guac_ssh_user_join_handler;
|
client->join_handler = guac_ssh_user_join_handler;
|
||||||
client->free_handler = guac_ssh_client_free_handler;
|
client->free_handler = guac_ssh_client_free_handler;
|
||||||
@ -99,7 +103,7 @@ int guac_ssh_client_free_handler(guac_client* client) {
|
|||||||
|
|
||||||
/* Clean up recording, if in progress */
|
/* Clean up recording, if in progress */
|
||||||
if (ssh_client->recording != NULL)
|
if (ssh_client->recording != NULL)
|
||||||
guac_recording_free(ssh_client->recording);
|
guac_common_recording_free(ssh_client->recording);
|
||||||
|
|
||||||
/* Free interactive SSH session */
|
/* Free interactive SSH session */
|
||||||
if (ssh_client->session != NULL)
|
if (ssh_client->session != NULL)
|
||||||
@ -114,6 +118,7 @@ int guac_ssh_client_free_handler(guac_client* client) {
|
|||||||
guac_ssh_settings_free(ssh_client->settings);
|
guac_ssh_settings_free(ssh_client->settings);
|
||||||
|
|
||||||
/* Free client structure */
|
/* Free client structure */
|
||||||
|
guac_common_clipboard_free(ssh_client->clipboard);
|
||||||
free(ssh_client);
|
free(ssh_client);
|
||||||
|
|
||||||
guac_common_ssh_uninit();
|
guac_common_ssh_uninit();
|
||||||
|
@ -22,6 +22,11 @@
|
|||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of bytes to allow within the clipboard.
|
||||||
|
*/
|
||||||
|
#define GUAC_SSH_CLIPBOARD_MAX_LENGTH 262144
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler which is invoked when the SSH client needs to be disconnected (if
|
* Handler which is invoked when the SSH client needs to be disconnected (if
|
||||||
* connected) and freed. This can happen if initialization fails, or all users
|
* connected) and freed. This can happen if initialization fails, or all users
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "clipboard.h"
|
#include "clipboard.h"
|
||||||
|
#include "common/clipboard.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "terminal/terminal.h"
|
#include "terminal/terminal.h"
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ int guac_ssh_clipboard_handler(guac_user* user, guac_stream* stream,
|
|||||||
/* Clear clipboard and prepare for new data */
|
/* Clear clipboard and prepare for new data */
|
||||||
guac_client* client = user->client;
|
guac_client* client = user->client;
|
||||||
guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;
|
guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;
|
||||||
guac_terminal_clipboard_reset(ssh_client->term, mimetype);
|
guac_common_clipboard_reset(ssh_client->clipboard, mimetype);
|
||||||
|
|
||||||
/* Set handlers for clipboard stream */
|
/* Set handlers for clipboard stream */
|
||||||
stream->blob_handler = guac_ssh_clipboard_blob_handler;
|
stream->blob_handler = guac_ssh_clipboard_blob_handler;
|
||||||
@ -47,7 +48,7 @@ int guac_ssh_clipboard_blob_handler(guac_user* user, guac_stream* stream,
|
|||||||
/* Append new data */
|
/* Append new data */
|
||||||
guac_client* client = user->client;
|
guac_client* client = user->client;
|
||||||
guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;
|
guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;
|
||||||
guac_terminal_clipboard_append(ssh_client->term, data, length);
|
guac_common_clipboard_append(ssh_client->clipboard, data, length);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,11 @@
|
|||||||
|
|
||||||
#include "common/cursor.h"
|
#include "common/cursor.h"
|
||||||
#include "common/display.h"
|
#include "common/display.h"
|
||||||
|
#include "common/recording.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "terminal/terminal.h"
|
#include "terminal/terminal.h"
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/recording.h>
|
|
||||||
#include <guacamole/user.h>
|
#include <guacamole/user.h>
|
||||||
#include <libssh2.h>
|
#include <libssh2.h>
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ int guac_ssh_user_mouse_handler(guac_user* user, int x, int y, int mask) {
|
|||||||
|
|
||||||
/* Report mouse position within recording */
|
/* Report mouse position within recording */
|
||||||
if (ssh_client->recording != NULL)
|
if (ssh_client->recording != NULL)
|
||||||
guac_recording_report_mouse(ssh_client->recording, x, y, mask);
|
guac_common_recording_report_mouse(ssh_client->recording, x, y, mask);
|
||||||
|
|
||||||
/* Send mouse event */
|
/* Send mouse event */
|
||||||
guac_terminal_send_mouse(term, user, x, y, mask);
|
guac_terminal_send_mouse(term, user, x, y, mask);
|
||||||
@ -58,7 +58,7 @@ int guac_ssh_user_key_handler(guac_user* user, int keysym, int pressed) {
|
|||||||
|
|
||||||
/* Report key state within recording */
|
/* Report key state within recording */
|
||||||
if (ssh_client->recording != NULL)
|
if (ssh_client->recording != NULL)
|
||||||
guac_recording_report_key(ssh_client->recording,
|
guac_common_recording_report_key(ssh_client->recording,
|
||||||
keysym, pressed);
|
keysym, pressed);
|
||||||
|
|
||||||
/* Skip if terminal not yet ready */
|
/* Skip if terminal not yet ready */
|
||||||
@ -88,8 +88,7 @@ int guac_ssh_user_size_handler(guac_user* user, int width, int height) {
|
|||||||
if (ssh_client->term_channel != NULL) {
|
if (ssh_client->term_channel != NULL) {
|
||||||
pthread_mutex_lock(&(ssh_client->term_channel_lock));
|
pthread_mutex_lock(&(ssh_client->term_channel_lock));
|
||||||
libssh2_channel_request_pty_size(ssh_client->term_channel,
|
libssh2_channel_request_pty_size(ssh_client->term_channel,
|
||||||
guac_terminal_get_columns(terminal),
|
terminal->term_width, terminal->term_height);
|
||||||
guac_terminal_get_rows(terminal));
|
|
||||||
pthread_mutex_unlock(&(ssh_client->term_channel_lock));
|
pthread_mutex_unlock(&(ssh_client->term_channel_lock));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "common/defaults.h"
|
#include "common/defaults.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "terminal/terminal.h"
|
|
||||||
|
|
||||||
#include <guacamole/user.h>
|
#include <guacamole/user.h>
|
||||||
#include <guacamole/wol-constants.h>
|
#include <guacamole/wol-constants.h>
|
||||||
@ -249,8 +248,8 @@ enum SSH_ARGS_IDX {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The ASCII code, as an integer, to send for the backspace key, as configured
|
* The ASCII code, as an integer, to send for the backspace key, as configured
|
||||||
* by the SSH connection from the client. By default this will be
|
* by the SSH connection from the client. By default this will be 127,
|
||||||
* GUAC_TERMINAL_DEFAULT_BACKSPACE.
|
* the ASCII DELETE code.
|
||||||
*/
|
*/
|
||||||
IDX_BACKSPACE,
|
IDX_BACKSPACE,
|
||||||
|
|
||||||
@ -376,22 +375,22 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user,
|
|||||||
/* Read maximum scrollback size */
|
/* Read maximum scrollback size */
|
||||||
settings->max_scrollback =
|
settings->max_scrollback =
|
||||||
guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
|
guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||||
IDX_SCROLLBACK, GUAC_TERMINAL_DEFAULT_MAX_SCROLLBACK);
|
IDX_SCROLLBACK, GUAC_SSH_DEFAULT_MAX_SCROLLBACK);
|
||||||
|
|
||||||
/* Read font name */
|
/* Read font name */
|
||||||
settings->font_name =
|
settings->font_name =
|
||||||
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||||
IDX_FONT_NAME, GUAC_TERMINAL_DEFAULT_FONT_NAME);
|
IDX_FONT_NAME, GUAC_SSH_DEFAULT_FONT_NAME);
|
||||||
|
|
||||||
/* Read font size */
|
/* Read font size */
|
||||||
settings->font_size =
|
settings->font_size =
|
||||||
guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
|
guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||||
IDX_FONT_SIZE, GUAC_TERMINAL_DEFAULT_FONT_SIZE);
|
IDX_FONT_SIZE, GUAC_SSH_DEFAULT_FONT_SIZE);
|
||||||
|
|
||||||
/* Copy requested color scheme */
|
/* Copy requested color scheme */
|
||||||
settings->color_scheme =
|
settings->color_scheme =
|
||||||
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||||
IDX_COLOR_SCHEME, GUAC_TERMINAL_DEFAULT_COLOR_SCHEME);
|
IDX_COLOR_SCHEME, "");
|
||||||
|
|
||||||
/* Pull width/height/resolution directly from user */
|
/* Pull width/height/resolution directly from user */
|
||||||
settings->width = user->info.optimal_width;
|
settings->width = user->info.optimal_width;
|
||||||
@ -492,7 +491,7 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user,
|
|||||||
/* Parse backspace key setting */
|
/* Parse backspace key setting */
|
||||||
settings->backspace =
|
settings->backspace =
|
||||||
guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
|
guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||||
IDX_BACKSPACE, GUAC_TERMINAL_DEFAULT_BACKSPACE);
|
IDX_BACKSPACE, 127);
|
||||||
|
|
||||||
/* Read terminal emulator type. */
|
/* Read terminal emulator type. */
|
||||||
settings->terminal_type =
|
settings->terminal_type =
|
||||||
|
@ -26,6 +26,17 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the font to use for the terminal if no name is specified.
|
||||||
|
*/
|
||||||
|
#define GUAC_SSH_DEFAULT_FONT_NAME "monospace"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the font to use for the terminal if no font size is specified,
|
||||||
|
* in points.
|
||||||
|
*/
|
||||||
|
#define GUAC_SSH_DEFAULT_FONT_SIZE 12
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The port to connect to when initiating any SSH connection, if no other port
|
* The port to connect to when initiating any SSH connection, if no other port
|
||||||
* is specified.
|
* is specified.
|
||||||
@ -47,6 +58,11 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_SSH_DEFAULT_POLL_TIMEOUT 1000
|
#define GUAC_SSH_DEFAULT_POLL_TIMEOUT 1000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default maximum scrollback size in rows.
|
||||||
|
*/
|
||||||
|
#define GUAC_SSH_DEFAULT_MAX_SCROLLBACK 1000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings for the SSH connection. The values for this structure are parsed
|
* Settings for the SSH connection. The values for this structure are parsed
|
||||||
* from the arguments given during the Guacamole protocol handshake using the
|
* from the arguments given during the Guacamole protocol handshake using the
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "argv.h"
|
#include "argv.h"
|
||||||
|
#include "common/recording.h"
|
||||||
#include "common-ssh/sftp.h"
|
#include "common-ssh/sftp.h"
|
||||||
#include "common-ssh/ssh.h"
|
#include "common-ssh/ssh.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@ -35,9 +36,6 @@
|
|||||||
#include <libssh2.h>
|
#include <libssh2.h>
|
||||||
#include <libssh2_sftp.h>
|
#include <libssh2_sftp.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/recording.h>
|
|
||||||
#include <guacamole/socket.h>
|
|
||||||
#include <guacamole/timestamp.h>
|
|
||||||
#include <guacamole/wol.h>
|
#include <guacamole/wol.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
@ -100,7 +98,7 @@ static guac_common_ssh_user* guac_ssh_get_user(guac_client* client) {
|
|||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
"Initial import failed: %s",
|
"Initial import failed: %s",
|
||||||
guac_common_ssh_key_error());
|
guac_common_ssh_key_error());
|
||||||
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
"Re-attempting private key import (WITH passphrase)");
|
"Re-attempting private key import (WITH passphrase)");
|
||||||
|
|
||||||
@ -150,23 +148,23 @@ static guac_common_ssh_user* guac_ssh_get_user(guac_client* client) {
|
|||||||
* A function used to generate a terminal prompt to gather additional
|
* A function used to generate a terminal prompt to gather additional
|
||||||
* credentials from the guac_client during a connection, and using
|
* credentials from the guac_client during a connection, and using
|
||||||
* the specified string to generate the prompt for the user.
|
* the specified string to generate the prompt for the user.
|
||||||
*
|
*
|
||||||
* @param client
|
* @param client
|
||||||
* The guac_client object associated with the current connection
|
* The guac_client object associated with the current connection
|
||||||
* where additional credentials are required.
|
* where additional credentials are required.
|
||||||
*
|
*
|
||||||
* @param cred_name
|
* @param cred_name
|
||||||
* The prompt text to display to the screen when prompting for the
|
* The prompt text to display to the screen when prompting for the
|
||||||
* additional credentials.
|
* additional credentials.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The string of credentials gathered from the user.
|
* The string of credentials gathered from the user.
|
||||||
*/
|
*/
|
||||||
static char* guac_ssh_get_credential(guac_client *client, char* cred_name) {
|
static char* guac_ssh_get_credential(guac_client *client, char* cred_name) {
|
||||||
|
|
||||||
guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;
|
guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;
|
||||||
return guac_terminal_prompt(ssh_client->term, cred_name, false);
|
return guac_terminal_prompt(ssh_client->term, cred_name, false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ssh_input_thread(void* data) {
|
void* ssh_input_thread(void* data) {
|
||||||
@ -208,17 +206,17 @@ void* ssh_client_thread(void* data) {
|
|||||||
if (settings->wol_send_packet) {
|
if (settings->wol_send_packet) {
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, "
|
guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, "
|
||||||
"and pausing for %d seconds.", settings->wol_wait_time);
|
"and pausing for %d seconds.", settings->wol_wait_time);
|
||||||
|
|
||||||
/* Send the Wake-on-LAN request. */
|
/* Send the Wake-on-LAN request. */
|
||||||
if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr,
|
if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr,
|
||||||
settings->wol_udp_port))
|
settings->wol_udp_port))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* If wait time is specified, sleep for that amount of time. */
|
/* If wait time is specified, sleep for that amount of time. */
|
||||||
if (settings->wol_wait_time > 0)
|
if (settings->wol_wait_time > 0)
|
||||||
guac_timestamp_msleep(settings->wol_wait_time * 1000);
|
guac_timestamp_msleep(settings->wol_wait_time * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init SSH base libraries */
|
/* Init SSH base libraries */
|
||||||
if (guac_common_ssh_init(client)) {
|
if (guac_common_ssh_init(client)) {
|
||||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||||
@ -230,7 +228,7 @@ void* ssh_client_thread(void* data) {
|
|||||||
|
|
||||||
/* Set up screen recording, if requested */
|
/* Set up screen recording, if requested */
|
||||||
if (settings->recording_path != NULL) {
|
if (settings->recording_path != NULL) {
|
||||||
ssh_client->recording = guac_recording_create(client,
|
ssh_client->recording = guac_common_recording_create(client,
|
||||||
settings->recording_path,
|
settings->recording_path,
|
||||||
settings->recording_name,
|
settings->recording_name,
|
||||||
settings->create_recording_path,
|
settings->create_recording_path,
|
||||||
@ -240,23 +238,12 @@ void* ssh_client_thread(void* data) {
|
|||||||
settings->recording_include_keys);
|
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 */
|
/* Create terminal */
|
||||||
ssh_client->term = guac_terminal_create(client, options);
|
ssh_client->term = guac_terminal_create(client, ssh_client->clipboard,
|
||||||
|
settings->disable_copy, settings->max_scrollback,
|
||||||
/* Free options struct now that it's been used */
|
settings->font_name, settings->font_size, settings->resolution,
|
||||||
free(options);
|
settings->width, settings->height, settings->color_scheme,
|
||||||
|
settings->backspace);
|
||||||
|
|
||||||
/* Fail if terminal init failed */
|
/* Fail if terminal init failed */
|
||||||
if (ssh_client->term == NULL) {
|
if (ssh_client->term == NULL) {
|
||||||
@ -360,12 +347,10 @@ void* ssh_client_thread(void* data) {
|
|||||||
|
|
||||||
/* Init handlers for Guacamole-specific console codes */
|
/* Init handlers for Guacamole-specific console codes */
|
||||||
if (!settings->sftp_disable_upload)
|
if (!settings->sftp_disable_upload)
|
||||||
guac_terminal_set_upload_path_handler(ssh_client->term,
|
ssh_client->term->upload_path_handler = guac_sftp_set_upload_path;
|
||||||
guac_sftp_set_upload_path);
|
|
||||||
|
|
||||||
if (!settings->sftp_disable_download)
|
if (!settings->sftp_disable_download)
|
||||||
guac_terminal_set_file_download_handler(ssh_client->term,
|
ssh_client->term->file_download_handler = guac_sftp_download_file;
|
||||||
guac_sftp_download_file);
|
|
||||||
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG, "SFTP session initialized");
|
guac_client_log(client, GUAC_LOG_DEBUG, "SFTP session initialized");
|
||||||
|
|
||||||
@ -379,11 +364,10 @@ void* ssh_client_thread(void* data) {
|
|||||||
" Backspace may not work as expected.");
|
" Backspace may not work as expected.");
|
||||||
|
|
||||||
/* Request PTY */
|
/* Request PTY */
|
||||||
int term_height = guac_terminal_get_rows(ssh_client->term);
|
|
||||||
int term_width = guac_terminal_get_columns(ssh_client->term);
|
|
||||||
if (libssh2_channel_request_pty_ex(ssh_client->term_channel,
|
if (libssh2_channel_request_pty_ex(ssh_client->term_channel,
|
||||||
settings->terminal_type, strlen(settings->terminal_type),
|
settings->terminal_type, strlen(settings->terminal_type),
|
||||||
ssh_ttymodes, ttymodeBytes, term_width, term_height, 0, 0)) {
|
ssh_ttymodes, ttymodeBytes, ssh_client->term->term_width,
|
||||||
|
ssh_client->term->term_height, 0, 0)) {
|
||||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to allocate PTY.");
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to allocate PTY.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "common/clipboard.h"
|
#include "common/clipboard.h"
|
||||||
|
#include "common/recording.h"
|
||||||
#include "common-ssh/sftp.h"
|
#include "common-ssh/sftp.h"
|
||||||
#include "common-ssh/ssh.h"
|
#include "common-ssh/ssh.h"
|
||||||
#include "common-ssh/user.h"
|
#include "common-ssh/user.h"
|
||||||
@ -34,7 +35,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/recording.h>
|
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
@ -90,6 +90,11 @@ typedef struct guac_ssh_client {
|
|||||||
*/
|
*/
|
||||||
pthread_mutex_t term_channel_lock;
|
pthread_mutex_t term_channel_lock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current clipboard contents.
|
||||||
|
*/
|
||||||
|
guac_common_clipboard* clipboard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The terminal which will render all output from the SSH client.
|
* The terminal which will render all output from the SSH client.
|
||||||
*/
|
*/
|
||||||
@ -99,7 +104,7 @@ typedef struct guac_ssh_client {
|
|||||||
* The in-progress session recording, or NULL if no recording is in
|
* The in-progress session recording, or NULL if no recording is in
|
||||||
* progress.
|
* progress.
|
||||||
*/
|
*/
|
||||||
guac_recording* recording;
|
guac_common_recording* recording;
|
||||||
|
|
||||||
} guac_ssh_client ;
|
} guac_ssh_client ;
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "user.h"
|
#include "user.h"
|
||||||
#include "pipe.h"
|
#include "pipe.h"
|
||||||
#include "terminal/terminal.h"
|
|
||||||
#include "sftp.h"
|
#include "sftp.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@ -114,8 +113,8 @@ int guac_ssh_user_leave_handler(guac_user* user) {
|
|||||||
|
|
||||||
guac_ssh_client* ssh_client = (guac_ssh_client*) user->client->data;
|
guac_ssh_client* ssh_client = (guac_ssh_client*) user->client->data;
|
||||||
|
|
||||||
/* Remove the user from the terminal */
|
/* Update shared cursor state */
|
||||||
guac_terminal_remove_user(ssh_client->term, user);
|
guac_common_cursor_remove_user(ssh_client->term->cursor, user);
|
||||||
|
|
||||||
/* Free settings if not owner (owner settings will be freed with client) */
|
/* Free settings if not owner (owner settings will be freed with client) */
|
||||||
if (!user->owner) {
|
if (!user->owner) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user