From 35f2db3b0f505ef96261fa87f4aa1a89da541847 Mon Sep 17 00:00:00 2001 From: Cezary Marczak Date: Mon, 17 Jun 2024 08:20:39 +0200 Subject: [PATCH] WIP --- Dockerfile | 45 ++++++++++-- src/guacd-docker/bin/build-all.sh | 70 ------------------- src/guacd-docker/bin/build-deps.sh | 106 +++++++++++++++++++++++++++++ src/guacd-docker/krb5.conf | 7 ++ src/guacd/proc.h | 2 +- src/guacenc/ffmpeg-compat.c | 4 +- src/guacenc/ffmpeg-compat.h | 4 +- src/guacenc/video.c | 4 +- src/libguac/client.c | 19 +++++- src/libguac/guacamole/client.h | 1 + src/protocols/rdp/client.c | 11 ++- 11 files changed, 189 insertions(+), 84 deletions(-) create mode 100755 src/guacd-docker/bin/build-deps.sh create mode 100644 src/guacd-docker/krb5.conf diff --git a/Dockerfile b/Dockerfile index 4f39e028a..5e66513e3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,11 +42,18 @@ RUN apk add --no-cache \ openssl1.1-compat-dev \ pango-dev \ pulseaudio-dev \ + util-linux-dev \ + ffmpeg-dev \ + krb5-libs \ + krb5 \ + krb5-dev \ + libgss \ + krb5-conf \ util-linux-dev # Copy source to container for sake of build -ARG BUILD_DIR=/tmp/guacamole-server -COPY . ${BUILD_DIR} +# ARG BUILD_DIR=/tmp/guacamole-server +# COPY . ${BUILD_DIR} # # Base directory for installed build artifacts. @@ -84,7 +91,7 @@ ARG FREERDP_OPTS="\ -DWITH_DIRECTFB=OFF \ -DWITH_FFMPEG=OFF \ -DWITH_GSM=OFF \ - -DWITH_GSSAPI=OFF \ + -DWITH_GSSAPI=ON \ -DWITH_IPP=OFF \ -DWITH_JPEG=ON \ -DWITH_LIBSYSTEMD=OFF \ @@ -110,7 +117,11 @@ ARG FREERDP_OPTS="\ -DWITH_XRENDER=OFF \ -DWITH_XTEST=OFF \ -DWITH_XV=OFF \ - -DWITH_ZLIB=ON" + -DWITH_ZLIB=ON \ + -DWITH_KRB5=ON \ + -DKRB5_TRACE=/dev/stdout \ + -DDEBUG_NLA=ON \ + -DGSS_ROOT_FLAVOUR=MIT" ARG GUACAMOLE_SERVER_OPTS="\ --disable-guaclog" @@ -135,6 +146,17 @@ ARG LIBWEBSOCKETS_OPTS="\ -DLWS_WITHOUT_TEST_SERVER_EXTPOLL=ON \ -DLWS_WITH_STATIC=OFF" +# Build the dependencies for guacamole-server +ARG BUILD_DIR=/tmp/guacamole-server +RUN mkdir -p ${BUILD_DIR}/src/guacd-docker/bin + +COPY ./src/guacd-docker/bin/build-deps.sh ${BUILD_DIR}/src/guacd-docker/bin +RUN ${BUILD_DIR}/src/guacd-docker/bin/build-deps.sh +RUN rm -f ${BUILD_DIR}/src/guacd-docker/bin/build-deps.sh + +# Copy source to container for sake of build +COPY . ${BUILD_DIR} + # Build guacamole-server and its core protocol library dependencies RUN ${BUILD_DIR}/src/guacd-docker/bin/build-all.sh @@ -174,6 +196,12 @@ RUN apk add --no-cache \ terminus-font \ ttf-dejavu \ ttf-liberation \ + ffmpeg-dev \ + krb5-conf \ + krb5-libs \ + krb5-dev \ + krb5 \ + libgss \ util-linux-login && \ xargs apk add --no-cache < ${PREFIX_DIR}/DEPENDENCIES @@ -186,6 +214,14 @@ ARG GID=10001 RUN groupadd --gid $GID guacd RUN useradd --system --create-home --shell /sbin/nologin --uid $UID --gid $GID guacd +# Create symlinks to procyon krb5.conf and hosts +RUN mkdir -p /etc/procyon +RUN cp /etc/hosts /etc/procyon/hosts +COPY ./src/guacd-docker/krb5.conf /etc/procyon/krb5.conf + +RUN ln -s /etc/procyon/krb5.conf /etc/krb5.conf +RUN ln -s /etc/procyon/hosts /etc/hosts + # Run with user guacd USER guacd @@ -198,4 +234,3 @@ EXPOSE 4822 # PREFIX_DIR build argument. # CMD /opt/guacamole/sbin/guacd -b 0.0.0.0 -L $GUACD_LOG_LEVEL -f - diff --git a/src/guacd-docker/bin/build-all.sh b/src/guacd-docker/bin/build-all.sh index 52bd150c7..31be14157 100755 --- a/src/guacd-docker/bin/build-all.sh +++ b/src/guacd-docker/bin/build-all.sh @@ -35,76 +35,6 @@ export PKG_CONFIG_PATH="${PREFIX_DIR}/lib/pkgconfig" # 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://github.com/warmcat/libwebsockets" "$WITH_LIBWEBSOCKETS" $LIBWEBSOCKETS_OPTS - # # Build guacamole-server # diff --git a/src/guacd-docker/bin/build-deps.sh b/src/guacd-docker/bin/build-deps.sh new file mode 100755 index 000000000..bc661ad67 --- /dev/null +++ b/src/guacd-docker/bin/build-deps.sh @@ -0,0 +1,106 @@ +#!/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://github.com/warmcat/libwebsockets" "$WITH_LIBWEBSOCKETS" $LIBWEBSOCKETS_OPTS diff --git a/src/guacd-docker/krb5.conf b/src/guacd-docker/krb5.conf new file mode 100644 index 000000000..2638b5945 --- /dev/null +++ b/src/guacd-docker/krb5.conf @@ -0,0 +1,7 @@ +[libdefaults] + dns_lookup_kdc = true + dns_lookup_realm = true + +[realms] + +[domain_realm] diff --git a/src/guacd/proc.h b/src/guacd/proc.h index d13ae1021..c5ffe304d 100644 --- a/src/guacd/proc.h +++ b/src/guacd/proc.h @@ -46,7 +46,7 @@ * within this period of time, the associated process will be forcibly * terminated. */ -#define GUACD_CLIENT_FREE_TIMEOUT 5 +#define GUACD_CLIENT_FREE_TIMEOUT 600 /** * Process information of the internal remote desktop client. diff --git a/src/guacenc/ffmpeg-compat.c b/src/guacenc/ffmpeg-compat.c index 54e4b7498..60e146bd3 100644 --- a/src/guacenc/ffmpeg-compat.c +++ b/src/guacenc/ffmpeg-compat.c @@ -213,7 +213,7 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) { #endif } -AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec, +AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* codec, int bitrate, int width, int height, int gop_size, int qmax, int qmin, int pix_fmt, AVRational time_base) { @@ -249,7 +249,7 @@ AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec, } int guacenc_open_avcodec(AVCodecContext *avcodec_context, - AVCodec *codec, AVDictionary **options, + const AVCodec *codec, AVDictionary **options, AVStream* stream) { int ret = avcodec_open2(avcodec_context, codec, options); diff --git a/src/guacenc/ffmpeg-compat.h b/src/guacenc/ffmpeg-compat.h index a5cfb2f59..d75b5d74e 100644 --- a/src/guacenc/ffmpeg-compat.h +++ b/src/guacenc/ffmpeg-compat.h @@ -128,7 +128,7 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame); * The pointer to the configured AVCodecContext. * */ -AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec, +AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* codec, int bitrate, int width, int height, int gop_size, int qmax, int qmin, int pix_fmt, AVRational time_base); @@ -158,7 +158,7 @@ AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec, * Zero on success, a negative value on error. */ int guacenc_open_avcodec(AVCodecContext *avcodec_context, - AVCodec *codec, AVDictionary **options, + const AVCodec *codec, AVDictionary **options, AVStream* stream); #endif diff --git a/src/guacenc/video.c b/src/guacenc/video.c index e2eed51f3..c8fb8b993 100644 --- a/src/guacenc/video.c +++ b/src/guacenc/video.c @@ -47,7 +47,7 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name, int width, int height, int bitrate) { - AVOutputFormat *container_format; + const AVOutputFormat *container_format; AVFormatContext *container_format_context; AVStream *video_stream; int ret; @@ -63,7 +63,7 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name, container_format = container_format_context->oformat; /* Pull codec based on name */ - AVCodec* codec = avcodec_find_encoder_by_name(codec_name); + const AVCodec* codec = avcodec_find_encoder_by_name(codec_name); if (codec == NULL) { guacenc_log(GUAC_LOG_ERROR, "Failed to locate codec \"%s\".", codec_name); diff --git a/src/libguac/client.c b/src/libguac/client.c index 952ffcc3e..91d8036a9 100644 --- a/src/libguac/client.c +++ b/src/libguac/client.c @@ -215,7 +215,24 @@ void guac_client_free(guac_client* client) { guac_client_log(client, GUAC_LOG_ERROR, "Unable to close plugin: %s", dlerror()); } - pthread_rwlock_destroy(&(client->__users_lock)); + if (client->recording_path != NULL) { + // sleep(1); + char command[3000]; + snprintf(command, sizeof(command), "touch %s.m4v.lock", client->recording_path); + guac_client_log(client, GUAC_LOG_INFO, "Running command \"%s\"", command); + system(command); + + snprintf(command, sizeof(command), "/opt/guacamole/bin/guacenc -s 1920x1080 -f %s", client->recording_path); + guac_client_log(client, GUAC_LOG_INFO, "Running command \"%s\"", command); + system(command); + + snprintf(command, sizeof(command), "rm %s.m4v.lock", client->recording_path); + guac_client_log(client, GUAC_LOG_INFO, "Running command \"%s\"", command); + system(command); + + free(client->recording_path); + } + free(client->connection_id); free(client); } diff --git a/src/libguac/guacamole/client.h b/src/libguac/guacamole/client.h index 5712476f1..1c85e87eb 100644 --- a/src/libguac/guacamole/client.h +++ b/src/libguac/guacamole/client.h @@ -45,6 +45,7 @@ struct guac_client { + char* recording_path; /** * The guac_socket structure to be used to communicate with all connected * web-clients (users). Unlike the user-level guac_socket, this guac_socket diff --git a/src/protocols/rdp/client.c b/src/protocols/rdp/client.c index aed5ea68e..97dbba31e 100644 --- a/src/protocols/rdp/client.c +++ b/src/protocols/rdp/client.c @@ -47,6 +47,7 @@ #include #include #include +#include /** * Tests whether the given path refers to a directory which the current user @@ -183,8 +184,16 @@ int guac_rdp_client_free_handler(guac_client* client) { pthread_join(rdp_client->client_thread, NULL); /* Free parsed settings */ - if (rdp_client->settings != NULL) + if (rdp_client->settings != NULL) { + if (rdp_client->settings->recording_path != NULL && + rdp_client->settings->recording_name != NULL) { + client->recording_path = malloc(2048); + snprintf(client->recording_path, 2048, "%s/%s", + rdp_client->settings->recording_path, + rdp_client->settings->recording_name); + } guac_rdp_settings_free(rdp_client->settings); + } /* Clean up clipboard */ guac_rdp_clipboard_free(rdp_client->clipboard);