Compare commits

...

25 Commits

Author SHA1 Message Date
Matthew McClaskey
446d03d479 Merge branch 'master' into 'release/1.2.0'
Update release with latest changes

See merge request kasm-technologies/internal/KasmVNC!109
2023-08-21 17:52:45 +00:00
Matthew McClaskey
04f95d2b62 Merge branch 'feature/KASM-4796-add-unix-relay-to-config' into 'master'
Add network.unix_relay to yaml config

Closes KASM-4796

See merge request kasm-technologies/internal/KasmVNC!108
2023-08-17 09:38:43 +00:00
Dmitry Maksyoma
c0ed7d7b1a Add network.unix_relay to yaml config 2023-08-17 20:29:23 +12:00
Matt McClaskey
dda29172c1 update novnc ref 2023-08-16 11:05:35 -04:00
Matthew McClaskey
fa88480914 Merge branch 'bugfix/KASM-4765-fix-opensuse-datetime-dependency' into 'master'
OpenSuse: add missing dependency

Closes KASM-4765

See merge request kasm-technologies/internal/KasmVNC!107
2023-08-03 18:12:54 +00:00
Matt McClaskey
b4f6fafd73 update novnc ref 2023-08-03 14:08:57 -04:00
Dmitry Maksyoma
6a73d1cb49 OpenSuse: add missing dependency 2023-08-03 22:09:08 +12:00
Matthew McClaskey
6207b1b60f Merge branch 'bugfix/KASM-4757_watermark_default' into 'master'
KASM-4757 change KasmVNC defaults for watermark

Closes KASM-4757

See merge request kasm-technologies/internal/KasmVNC!105
2023-08-02 10:44:56 +00:00
mattmcclaskey
0923f300a0 KASM-4757 change KasmVNC defaults for watermark 2023-08-01 13:16:24 -04:00
Matthew McClaskey
7b8a4e8388 Merge branch 'feature/KASM-4034_unix_sockets' into 'master'
Add support for relaying unix sockets

Closes KASM-4034

See merge request kasm-technologies/internal/KasmVNC!90
2023-07-27 14:15:40 +00:00
Matthew McClaskey
b9e9a2d2a0 Merge branch 'feature/KASM-4489_watermark_time' into 'master'
Resolve KASM-4489 "Feature/ watermark time"

Closes KASM-4489

See merge request kasm-technologies/internal/KasmVNC!103
2023-07-26 23:55:06 +00:00
Lauri Kasanen
25a996cb97 Resolve KASM-4489 "Feature/ watermark time" 2023-07-26 23:55:06 +00:00
mattmcclaskey
6774cbf3a2 Merge branch 'master' into feature/KASM-4034_unix_sockets 2023-07-26 08:24:10 -04:00
Matthew McClaskey
fc0f2a3192 Merge branch 'bugfix/restart-crash' into 'master'
Blind guess at the reported crash

See merge request kasm-technologies/internal/KasmVNC!104
2023-07-26 12:03:33 +00:00
Ryan Kuba
9a14b07ba4 Merge branch 'bugfix/KASM-4151_gnome_blank' into 'master'
Implement the pixmaps-to-textures path so that mutter is happy. Note: tearing

Closes KASM-4151

See merge request kasm-technologies/internal/KasmVNC!96
2023-07-25 13:56:05 +00:00
Lauri Kasanen
0527c9f76e Add support for compositing 2023-07-25 13:56:05 +00:00
Lauri Kasanen
e41bc997a6 Blind guess at the reported crash 2023-07-12 17:16:28 +03:00
mattmcclaskey
75c51c1e93 rebase and fix merge conflicts 2023-06-30 12:51:01 -04:00
Matthew McClaskey
9450157af1 Merge branch 'feature/KASM-4421-new-distros' into 'master'
KASM-4421 update opensuse to 15.5, add bookworm Alpine 3.18 and Fedora 38

Closes KASM-4421

See merge request kasm-technologies/internal/KasmVNC!102
2023-06-13 18:37:05 +00:00
ryan.kuba
f9e46f5a13 KASM-4421 update opensuse to 15.5, add bookworm Alpine 3.18 and Fedora 38 2023-06-02 14:08:40 -04:00
Matthew McClaskey
13bafe3759 Merge branch 'feature/KASM-3663-host-tip-of-master-preview-builds' into 'master'
Resolve KASM-3663 "Feature/ host tip of master preview builds"

Closes KASM-3663

See merge request kasm-technologies/internal/KasmVNC!101
2023-06-02 17:12:27 +00:00
Dmitry Maksyoma
d5080eca8f Resolve KASM-3663 "Feature/ host tip of master preview builds" 2023-06-02 17:12:27 +00:00
Matthew McClaskey
4d3a9b749a Merge branch 'bump-version-bumps-xvnc-binary' into 'master'
bump-package-version: bump version emitted by Xvnc -version

See merge request kasm-technologies/internal/KasmVNC!100
2023-04-06 13:31:07 +00:00
Dmitry Maksyoma
12ba00f939 bump-package-version: bump version emitted by Xvnc -version 2023-04-07 00:34:29 +12:00
Lauri Kasanen
3bae812364 Add support for relaying unix sockets 2023-02-16 15:51:26 +02:00
59 changed files with 4575 additions and 21 deletions

View File

@@ -89,3 +89,26 @@ detect_revision() {
REVISION=$(echo "$package" | sed "s/_${arch}.\+//" | sed 's/.\++//') REVISION=$(echo "$package" | sed "s/_${arch}.\+//" | sed 's/.\++//')
} }
make_index_html() {
local body=""
local bname
for f in "$@"; do
bname=$(basename "$f")
body="${body}<a href=/$f>$bname</a><br>"
done
cat <<EOF
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>KasmVNC preview build</title>
</head>
<body>
$body
</body>
</html>
EOF
}

View File

@@ -243,6 +243,43 @@ build_debian_bullseye_arm:
paths: paths:
- output/ - output/
build_debian_bookworm:
stage: build
allow_failure: true
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package debian bookworm;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_debian_bookworm_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm64
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package debian bookworm;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_kali_rolling: build_kali_rolling:
stage: build stage: build
allow_failure: true allow_failure: true
@@ -440,6 +477,42 @@ build_fedora_thirtyseven_arm:
paths: paths:
- output/ - output/
build_fedora_thirtyeight:
stage: build
allow_failure: true
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package fedora thirtyeight;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_fedora_thirtyeight_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm64
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package fedora thirtyeight;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_alpine_317: build_alpine_317:
stage: build stage: build
allow_failure: true allow_failure: true
@@ -483,9 +556,49 @@ test:
script: script:
- bash builder/test-vncserver - bash builder/test-vncserver
build_alpine_318:
stage: build
allow_failure: true
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package alpine 318;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
build_alpine_318_arm:
stage: build
allow_failure: true
tags:
- oci-fixed-arm64
before_script:
- *prepare_build
- *prepare_www
after_script:
- *prepare_artfacts
script:
- bash builder/build-package alpine 318;
only:
variables:
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
artifacts:
paths:
- output/
upload: upload:
stage: upload stage: upload
image: ubuntu:focal image: ubuntu:focal
artifacts:
paths:
- output/
before_script: before_script:
- . .ci/upload.sh - . .ci/upload.sh
script: script:
@@ -502,6 +615,7 @@ upload:
done done
- export S3_BUILD_DIRECTORY="kasmvnc/${CI_COMMIT_SHA}" - export S3_BUILD_DIRECTORY="kasmvnc/${CI_COMMIT_SHA}"
- export RELEASE_VERSION=$(.ci/next_release_version "$CI_COMMIT_REF_NAME") - export RELEASE_VERSION=$(.ci/next_release_version "$CI_COMMIT_REF_NAME")
- uploaded_files=()
- for package in `find output/ -type f -name '*.deb' -or -name '*.rpm' -or -name '*.tgz'`; do - for package in `find output/ -type f -name '*.deb' -or -name '*.rpm' -or -name '*.tgz'`; do
prepare_upload_filename "$package"; prepare_upload_filename "$package";
upload_filename="${S3_BUILD_DIRECTORY}/$upload_filename"; upload_filename="${S3_BUILD_DIRECTORY}/$upload_filename";
@@ -510,4 +624,23 @@ upload:
upload_to_s3 "$package" "$upload_filename" "$S3_BUCKET"; upload_to_s3 "$package" "$upload_filename" "$S3_BUCKET";
UPLOAD_NAME=$(basename $upload_filename | sed 's#kasmvncserver_##' | sed -r 's#_([0-9]{1,3}\.){2}[0-9]{1,2}_\S+?([a-f0-9]{6})##' | sed -r 's#\.(deb|rpm|tgz)##'); UPLOAD_NAME=$(basename $upload_filename | sed 's#kasmvncserver_##' | sed -r 's#_([0-9]{1,3}\.){2}[0-9]{1,2}_\S+?([a-f0-9]{6})##' | sed -r 's#\.(deb|rpm|tgz)##');
curl --request POST --header "PRIVATE-TOKEN:${GITLAB_API_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/statuses/${CI_COMMIT_SHA}?state=success&name=${UPLOAD_NAME}&target_url=${S3_URL}"; curl --request POST --header "PRIVATE-TOKEN:${GITLAB_API_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/statuses/${CI_COMMIT_SHA}?state=success&name=${UPLOAD_NAME}&target_url=${S3_URL}";
uploaded_files+=("$upload_filename");
done done
- make_index_html "${uploaded_files[@]}" > output/index.html;
upload_build_preview:
stage: upload
needs: ["upload"]
dependencies: ["upload"]
image: ubuntu:focal
before_script:
- . .ci/upload.sh
resource_group: upload_build_preview
only:
variables:
- $CI_COMMIT_BRANCH == 'master'
script:
- prepare_to_run_scripts_and_s3_uploads
- preview_builds_dir=kasmvnc/preview-builds
- upload_to_s3 "output/index.html" "$preview_builds_dir/index.html" "$S3_BUCKET"
- curl --request POST --header "PRIVATE-TOKEN:${GITLAB_API_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/statuses/${CI_COMMIT_SHA}?state=success&name=index.html&target_url=${S3_URL}";

View File

@@ -154,6 +154,9 @@ find_package(PNG REQUIRED)
# Check for libjpeg # Check for libjpeg
find_package(JPEG REQUIRED) find_package(JPEG REQUIRED)
find_package(Freetype REQUIRED)
include_directories(${FREETYPE_INCLUDE_DIRS})
# Staticly link libjpeg-turbo # Staticly link libjpeg-turbo
set(JPEG_LIBRARIES "-Wl,-Bstatic -lturbojpeg -Wl,-Bdynamic") set(JPEG_LIBRARIES "-Wl,-Bstatic -lturbojpeg -Wl,-Bdynamic")
# Warn if it doesn't seem to be the accelerated libjpeg that's found # Warn if it doesn't seem to be the accelerated libjpeg that's found

View File

@@ -15,6 +15,11 @@ bump_deb() {
builder/bump-package-version-deb "$new_version" builder/bump-package-version-deb "$new_version"
} }
bump_xvnc_binary() {
local cmd="s/#define XVNCVERSION.\+$/#define XVNCVERSION \"KasmVNC $new_version\"/"
sed -i -e "$cmd" unix/xserver/hw/vnc/xvnc.c
}
new_version="$1" new_version="$1"
if [[ -z "$new_version" ]]; then if [[ -z "$new_version" ]]; then
@@ -25,5 +30,6 @@ fi
cd "$(dirname "$0")/.." cd "$(dirname "$0")/.."
update_version_to_meet_packaging_standards update_version_to_meet_packaging_standards
bump_xvnc_binary
bump_rpm bump_rpm
bump_deb bump_deb

View File

@@ -0,0 +1,7 @@
FROM alpine:3.18
RUN apk add shadow bash
RUN useradd -m docker && echo "docker:docker" | chpasswd
USER docker

View File

@@ -0,0 +1,82 @@
FROM alpine:3.18
ENV KASMVNC_BUILD_OS alpine
ENV KASMVNC_BUILD_OS_CODENAME 318
ENV XORG_VER 1.20.14
RUN \
echo "**** install build deps ****" && \
apk add \
alpine-release \
alpine-sdk \
autoconf \
automake \
bash \
ca-certificates \
cmake \
coreutils \
curl \
eudev-dev \
font-cursor-misc \
font-misc-misc \
font-util-dev \
git \
grep \
jq \
libdrm-dev \
libepoxy-dev \
libjpeg-turbo-dev \
libjpeg-turbo-static \
libpciaccess-dev \
libtool \
libwebp-dev \
libx11-dev \
libxau-dev \
libxcb-dev \
libxcursor-dev \
libxcvt-dev \
libxdmcp-dev \
libxext-dev \
libxfont2-dev \
libxkbfile-dev \
libxrandr-dev \
libxshmfence-dev \
libxtst-dev \
mesa-dev \
mesa-dri-gallium \
meson \
nettle-dev \
openssl-dev \
pixman-dev \
procps \
shadow \
tar \
tzdata \
wayland-dev \
wayland-protocols \
xcb-util-dev \
xcb-util-image-dev \
xcb-util-keysyms-dev \
xcb-util-renderutil-dev \
xcb-util-wm-dev \
xinit \
xkbcomp \
xkbcomp-dev \
xkeyboard-config \
xorgproto \
xorg-server-common \
xorg-server-dev \
xtrans
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN useradd -m docker && echo "docker:docker" | chpasswd
COPY --chown=docker:docker . /src/
USER docker
ENTRYPOINT ["/src/builder/build.sh"]

View File

@@ -0,0 +1,38 @@
FROM debian:bookworm-slim
ENV KASMVNC_BUILD_OS debian
ENV KASMVNC_BUILD_OS_CODENAME bookworm
ENV XORG_VER 1.20.10
ENV DEBIAN_FRONTEND noninteractive
RUN \
echo "**** add all sources ****" && \
echo "deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware" > /etc/apt/sources.list && \
echo "deb-src http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb-src http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb http://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb-src http://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb http://security.debian.org/debian-security/ bookworm-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb-src http://security.debian.org/debian-security/ bookworm-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
rm -f /etc/apt/sources.list.d/debian.sources
RUN apt-get update && \
apt-get -y install sudo
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata
RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev
RUN apt-get update && apt-get -y install cmake git libgnutls28-dev vim wget tightvncserver curl
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
COPY --chown=docker:docker . /src/
USER docker
ENTRYPOINT ["/src/builder/build.sh"]

View File

@@ -0,0 +1,19 @@
FROM debian:bookworm
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && \
apt-get -y install vim build-essential devscripts equivs
# Install build-deps for the package.
COPY ./debian/control /tmp
RUN apt-get update && echo YYY | mk-build-deps --install --remove /tmp/control
ARG L_UID
RUN if [ "$L_UID" -eq 0 ]; then \
useradd -m docker; \
else \
useradd -m docker -u $L_UID;\
fi
USER docker

View File

@@ -0,0 +1,57 @@
FROM debian:bookworm-slim
ENV DISPLAY=:1 \
VNC_PORT=8443 \
VNC_RESOLUTION=1280x720 \
MAX_FRAME_RATE=24 \
VNCOPTIONS="-PreferBandwidth -DynamicQualityMin=4 -DynamicQualityMax=7" \
HOME=/home/user \
TERM=xterm \
STARTUPDIR=/dockerstartup \
INST_SCRIPTS=/dockerstartup/install \
KASM_RX_HOME=/dockerstartup/kasmrx \
DEBIAN_FRONTEND=noninteractive \
VNC_COL_DEPTH=24 \
VNC_RESOLUTION=1280x1024 \
VNC_PW=vncpassword \
VNC_USER=user \
VNC_VIEW_ONLY_PW=vncviewonlypassword \
LD_LIBRARY_PATH=/usr/local/lib/ \
OMP_WAIT_POLICY=PASSIVE \
SHELL=/bin/bash \
SINGLE_APPLICATION=0 \
KASMVNC_BUILD_OS=debian \
KASMVNC_BUILD_OS_CODENAME=buster
EXPOSE $VNC_PORT
WORKDIR $HOME
### REQUIRED STUFF ###
RUN apt-get update && apt-get install -y supervisor xfce4 xfce4-terminal dbus-x11 xterm libnss-wrapper gettext wget
RUN apt-get purge -y pm-utils xscreensaver*
RUN apt-get update && apt-get install -y vim less
RUN apt-get update && apt-get -y install lsb-release
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####
COPY ./builder/scripts/ /tmp/scripts/
COPY ./debian/changelog /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
RUN /tmp/scripts/install_kasmvncserver_package
### END CUSTOM STUFF ###
RUN chown -R 1000:0 $HOME
USER 1000:ssl-cert
WORKDIR $HOME
ENTRYPOINT [ "/dockerstartup/vnc_startup.sh" ]

View File

@@ -0,0 +1,19 @@
FROM fedora:38
ENV STARTUPDIR=/dockerstartup
RUN dnf install -y xterm
RUN dnf install -y vim less
RUN yum install -y redhat-lsb-core
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp/
RUN dnf localinstall -y /tmp/*.rpm
RUN mkdir -p $STARTUPDIR
COPY startup/vnc_startup_barebones.sh $STARTUPDIR
RUN useradd -m foo
USER foo:kasmvnc-cert
ENTRYPOINT "/$STARTUPDIR/vnc_startup_barebones.sh"

View File

@@ -0,0 +1,86 @@
FROM fedora:38
ENV KASMVNC_BUILD_OS fedora
ENV KASMVNC_BUILD_OS_CODENAME thirtyeight
ENV XORG_VER 1.20.14
RUN \
echo "**** install build deps ****" && \
dnf group install -y \
"C Development Tools and Libraries" \
"Development Tools" && \
dnf install -y \
autoconf \
automake \
bison \
byacc \
bzip2 \
cmake \
diffutils \
doxygen \
file \
flex \
fop \
gcc \
gcc-c++ \
git \
glibc-devel \
libdrm-devel \
libepoxy-devel \
libmd-devel \
libpciaccess-devel \
libtool \
libwebp-devel \
libX11-devel \
libXau-devel \
libxcb-devel \
libXcursor-devel \
libxcvt-devel \
libXdmcp-devel \
libXext-devel \
libXfont2-devel \
libxkbfile-devel \
libXrandr-devel \
libxshmfence-devel \
libXtst-devel \
mesa-libEGL-devel \
mesa-libgbm-devel \
mesa-libGL-devel \
meson \
mingw64-binutils \
mt-st \
nettle-devel \
openssl-devel \
patch \
pixman-devel \
wayland-devel \
wget \
which \
xcb-util-devel \
xcb-util-image-devel \
xcb-util-keysyms-devel \
xcb-util-renderutil-devel \
xcb-util-wm-devel \
xinit \
xkbcomp \
xkbcomp-devel \
xkeyboard-config \
xmlto \
xorg-x11-font-utils \
xorg-x11-proto-devel \
xorg-x11-server-common \
xorg-x11-server-devel \
xorg-x11-xtrans-devel \
xsltproc
ENV SCRIPTS_DIR=/tmp/scripts
COPY builder/scripts $SCRIPTS_DIR
RUN $SCRIPTS_DIR/build-webp
RUN $SCRIPTS_DIR/build-libjpeg-turbo
RUN useradd -m docker && echo "docker:docker" | chpasswd
COPY --chown=docker:docker . /src/
USER docker
ENTRYPOINT ["/src/builder/build.sh"]

View File

@@ -0,0 +1,13 @@
FROM fedora:38
RUN dnf install -y fedora-packager fedora-review
RUN dnf install -y tree vim less
RUN dnf install -y redhat-lsb-core
RUN dnf install -y dnf-plugins-core
COPY fedora/*.spec /tmp
RUN dnf builddep -y /tmp/*.spec
RUN useradd -m docker && echo "docker:docker" | chpasswd
USER docker

View File

@@ -0,0 +1,62 @@
FROM fedora:38
ENV DISPLAY=:1 \
VNC_PORT=8443 \
VNC_RESOLUTION=1280x720 \
MAX_FRAME_RATE=24 \
VNCOPTIONS="-PreferBandwidth -DynamicQualityMin=4 -DynamicQualityMax=7" \
HOME=/home/user \
TERM=xterm \
STARTUPDIR=/dockerstartup \
INST_SCRIPTS=/dockerstartup/install \
KASM_RX_HOME=/dockerstartup/kasmrx \
DEBIAN_FRONTEND=noninteractive \
VNC_COL_DEPTH=24 \
VNC_RESOLUTION=1280x1024 \
VNC_PW=vncpassword \
VNC_USER=user \
VNC_VIEW_ONLY_PW=vncviewonlypassword \
LD_LIBRARY_PATH=/usr/local/lib/ \
OMP_WAIT_POLICY=PASSIVE \
SHELL=/bin/bash \
SINGLE_APPLICATION=0 \
KASMVNC_BUILD_OS=fedora \
KASMVNC_BUILD_OS_CODENAME=thirtythree
EXPOSE $VNC_PORT
WORKDIR $HOME
### REQUIRED STUFF ###
RUN dnf install -y openssl xterm gettext wget
RUN dnf install -y nss_wrapper
RUN dnf install -y xorg-x11-xauth xkeyboard-config
# xorg-x11-server-Xorg
# RUN dnf install -y @xfce-desktop-environment
RUN dnf erase -y pm-utils xscreensaver*
RUN dnf install -y redhat-lsb-core
RUN dnf install -y vim less
RUN dnf install -y @xfce-desktop-environment
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
RUN mkdir -p $STARTUPDIR
COPY builder/startup/ $STARTUPDIR
### START CUSTOM STUFF ####
COPY ./builder/scripts/ /tmp/scripts/
COPY ./fedora/kasmvncserver.spec /tmp
ARG KASMVNC_PACKAGE_DIR
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp/
# RUN dnf remove -y tigervnc-server-minimal
RUN /tmp/scripts/install_kasmvncserver_package
### END CUSTOM STUFF ###
RUN chown -R 1000:0 $HOME
USER 1000:kasmvnc-cert
WORKDIR $HOME
ENTRYPOINT [ "/dockerstartup/vnc_startup.sh" ]

View File

@@ -1,4 +1,4 @@
FROM opensuse/leap:15.3 FROM opensuse/leap:15.5
ENV STARTUPDIR=/dockerstartup ENV STARTUPDIR=/dockerstartup

View File

@@ -1,4 +1,4 @@
FROM opensuse/leap:15.3 FROM opensuse/leap:15.5
ENV KASMVNC_BUILD_OS opensuse ENV KASMVNC_BUILD_OS opensuse
ENV KASMVNC_BUILD_OS_CODENAME 15 ENV KASMVNC_BUILD_OS_CODENAME 15

View File

@@ -1,4 +1,4 @@
FROM opensuse/leap:15.3 FROM opensuse/leap:15.5
ENV KASMVNC_BUILD_OS opensuse ENV KASMVNC_BUILD_OS opensuse
ENV KASMVNC_BUILD_OS_CODENAME 15 ENV KASMVNC_BUILD_OS_CODENAME 15

View File

@@ -58,7 +58,8 @@ RUN echo 'alias tv="./run-specs spec/vncserver_yaml_validation_spec.py"' >> ~/.b
RUN echo 'alias ty="./run-specs spec/vncserver_*spec.py"' >> ~/.bashrc RUN echo 'alias ty="./run-specs spec/vncserver_*spec.py"' >> ~/.bashrc
RUN echo 'alias ta="./run-specs"' >> ~/.bashrc RUN echo 'alias ta="./run-specs"' >> ~/.bashrc
RUN echo 'alias vd="vncserver -dry-run"' >> ~/.bashrc RUN echo 'alias vd="vncserver -dry-run"' >> ~/.bashrc
ENV SET_PASSWORD_FUNC 'sp() { echo -e "$VNC_PW\\n$VNC_PW\\n" | kasmvncpasswd -w -u $USER $HOME/.kasmpasswd; }' RUN echo 'alias ss="sp; vncserver -select-de xfce"' >> ~/.bashrc
ENV SET_PASSWORD_FUNC 'sp() { echo -e "$VNC_PW\\n$VNC_PW\\n" | kasmvncpasswd -w -u $VNC_USER $HOME/.kasmpasswd; }'
RUN echo $SET_PASSWORD_FUNC >> ~/.bashrc RUN echo $SET_PASSWORD_FUNC >> ~/.bashrc
ENV LC_ALL=C.UTF-8 ENV LC_ALL=C.UTF-8

View File

@@ -7,7 +7,7 @@ License: GPLv2+
URL: https://github.com/kasmtech/KasmVNC URL: https://github.com/kasmtech/KasmVNC
BuildRequires: rsync BuildRequires: rsync
Requires: xorg-x11-xauth, xorg-x11-xkb-utils, xkeyboard-config, xorg-x11-server-utils, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny Requires: xorg-x11-xauth, xorg-x11-xkb-utils, xkeyboard-config, xorg-x11-server-utils, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, perl-DateTime-TimeZone
Conflicts: tigervnc-server, tigervnc-server-minimal Conflicts: tigervnc-server, tigervnc-server-minimal
%description %description

View File

@@ -0,0 +1,17 @@
# - Find freetype
# Find the freetype libraries
#
# This module defines the following variables:
# FREETYPE_FOUND - True if freetype is found
# FREETYPE_INCLUDE_DIRS - include directories
#
find_package(PkgConfig)
pkg_check_modules(PC_FREETYPE freetype2)
find_path(FREETYPE_INCLUDE_DIRS NAMES ft2build.h HINTS ${PC_FREETYPE_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
set(FPHSA_NAME_MISMATCHED 1)
find_package_handle_standard_args(freetype DEFAULT_MSG FREETYPE_INCLUDE_DIRS)
unset(FPHSA_NAME_MISMATCHED)
mark_as_advanced(FREETYPE_INCLUDE_DIRS)

View File

@@ -88,6 +88,9 @@ namespace rfb {
virtual void clearLocalClipboards() {} virtual void clearLocalClipboards() {}
virtual void receivedUnixRelayData(const char name[], const unsigned char *buf,
const unsigned len) {}
protected: protected:
virtual ~SDesktop() {} virtual ~SDesktop() {}
}; };

View File

@@ -98,6 +98,9 @@ namespace rfb {
virtual void udpUpgrade(const char *resp) = 0; virtual void udpUpgrade(const char *resp) = 0;
virtual void udpDowngrade(const bool) = 0; virtual void udpDowngrade(const bool) = 0;
virtual void subscribeUnixRelay(const char *name) = 0;
virtual void unixRelay(const char *name, const rdr::U8 *buf, const unsigned len) = 0;
ConnParams cp; ConnParams cp;
}; };
} }

View File

@@ -100,6 +100,12 @@ void SMsgReader::readMsg()
case msgTypeUpgradeToUdp: case msgTypeUpgradeToUdp:
readUpgradeToUdp(); readUpgradeToUdp();
break; break;
case msgTypeSubscribeUnixRelay:
readSubscribeUnixRelay();
break;
case msgTypeUnixRelay:
readUnixRelay();
break;
default: default:
fprintf(stderr, "unknown message type %d\n", msgType); fprintf(stderr, "unknown message type %d\n", msgType);
throw Exception("unknown message type"); throw Exception("unknown message type");
@@ -357,3 +363,42 @@ void SMsgReader::readUpgradeToUdp()
handler->udpUpgrade(resp); handler->udpUpgrade(resp);
} }
void SMsgReader::readSubscribeUnixRelay()
{
const rdr::U8 namelen = is->readU8();
char name[64];
if (namelen >= sizeof(name)) {
vlog.error("Ignoring subscribe with too large name");
is->skip(namelen);
return;
}
is->readBytes(name, namelen);
name[namelen] = '\0';
handler->subscribeUnixRelay(name);
}
void SMsgReader::readUnixRelay()
{
const rdr::U8 namelen = is->readU8();
char name[64];
if (namelen >= sizeof(name)) {
vlog.error("Ignoring relay packet with too large name");
is->skip(namelen);
return;
}
is->readBytes(name, namelen);
name[namelen] = '\0';
const rdr::U32 len = is->readU32();
rdr::U8 buf[1024 * 1024];
if (len >= sizeof(buf)) {
vlog.error("Ignoring relay packet with too large data");
is->skip(len);
return ;
}
is->readBytes(buf, len);
handler->unixRelay(name, buf, len);
}

View File

@@ -65,6 +65,9 @@ namespace rfb {
void readUpgradeToUdp(); void readUpgradeToUdp();
void readSubscribeUnixRelay();
void readUnixRelay();
SMsgHandler* handler; SMsgHandler* handler;
rdr::InStream* is; rdr::InStream* is;
}; };

View File

@@ -749,3 +749,29 @@ void SMsgWriter::writeUdpUpgrade(const char *resp)
endMsg(); endMsg();
} }
void SMsgWriter::writeSubscribeUnixRelay(const bool success, const char *msg)
{
startMsg(msgTypeSubscribeUnixRelay);
const rdr::U8 len = strlen(msg);
os->writeU8(success);
os->writeU8(len);
os->writeBytes(msg, len);
endMsg();
}
void SMsgWriter::writeUnixRelay(const char *name, const rdr::U8 *buf, const unsigned len)
{
startMsg(msgTypeUnixRelay);
const rdr::U8 namelen = strlen(name);
os->writeU8(namelen);
os->writeBytes(name, namelen);
os->writeU32(len);
os->writeBytes(buf, len);
endMsg();
}

View File

@@ -129,6 +129,9 @@ namespace rfb {
void writeUdpUpgrade(const char *resp); void writeUdpUpgrade(const char *resp);
void writeSubscribeUnixRelay(const bool success, const char *msg);
void writeUnixRelay(const char *name, const rdr::U8 *buf, const unsigned len);
protected: protected:
void startMsg(int type); void startMsg(int type);
void endMsg(); void endMsg();

View File

@@ -189,6 +189,18 @@ rfb::IntParameter rfb::Server::DLP_WatermarkRepeatSpace
("DLP_WatermarkRepeatSpace", ("DLP_WatermarkRepeatSpace",
"Number of pixels between repeats of the watermark", "Number of pixels between repeats of the watermark",
0, 0, 4096); 0, 0, 4096);
rfb::IntParameter rfb::Server::DLP_WatermarkFontSize
("DLP_WatermarkFontSize",
"Font size for -DLP_WatermarkText",
48, 8, 256);
rfb::IntParameter rfb::Server::DLP_WatermarkTimeOffset
("DLP_WatermarkTimeOffset",
"Offset from UTC for -DLP_WatermarkText",
0, -24, 24);
rfb::IntParameter rfb::Server::DLP_WatermarkTimeOffsetMinutes
("DLP_WatermarkTimeOffsetMinutes",
"Offset from UTC for -DLP_WatermarkText, minutes",
0, -24 * 60, 24 * 60);
rfb::StringParameter rfb::Server::DLP_WatermarkImage rfb::StringParameter rfb::Server::DLP_WatermarkImage
("DLP_WatermarkImage", ("DLP_WatermarkImage",
"PNG file to use as a watermark", "PNG file to use as a watermark",
@@ -201,6 +213,14 @@ rfb::StringParameter rfb::Server::DLP_WatermarkTint
("DLP_WatermarkTint", ("DLP_WatermarkTint",
"Tint the greyscale watermark by this color.", "Tint the greyscale watermark by this color.",
"255,255,255,255"); "255,255,255,255");
rfb::StringParameter rfb::Server::DLP_WatermarkText
("DLP_WatermarkText",
"Use this text instead of an image for the watermark, with strftime time formatting",
"");
rfb::StringParameter rfb::Server::DLP_WatermarkFont
("DLP_WatermarkFont",
"Use this font for -DLP_WatermarkText instead of the bundled one",
"");
rfb::StringParameter rfb::Server::maxVideoResolution rfb::StringParameter rfb::Server::maxVideoResolution
("MaxVideoResolution", ("MaxVideoResolution",

View File

@@ -49,12 +49,17 @@ namespace rfb {
static IntParameter DLP_ClipDelay; static IntParameter DLP_ClipDelay;
static IntParameter DLP_KeyRateLimit; static IntParameter DLP_KeyRateLimit;
static IntParameter DLP_WatermarkRepeatSpace; static IntParameter DLP_WatermarkRepeatSpace;
static IntParameter DLP_WatermarkFontSize;
static IntParameter DLP_WatermarkTimeOffset;
static IntParameter DLP_WatermarkTimeOffsetMinutes;
static StringParameter DLP_ClipLog; static StringParameter DLP_ClipLog;
static StringParameter DLP_Region; static StringParameter DLP_Region;
static StringParameter DLP_Clip_Types; static StringParameter DLP_Clip_Types;
static StringParameter DLP_WatermarkImage; static StringParameter DLP_WatermarkImage;
static StringParameter DLP_WatermarkLocation; static StringParameter DLP_WatermarkLocation;
static StringParameter DLP_WatermarkTint; static StringParameter DLP_WatermarkTint;
static StringParameter DLP_WatermarkText;
static StringParameter DLP_WatermarkFont;
static BoolParameter DLP_RegionAllowClick; static BoolParameter DLP_RegionAllowClick;
static BoolParameter DLP_RegionAllowRelease; static BoolParameter DLP_RegionAllowRelease;
static IntParameter jpegVideoQuality; static IntParameter jpegVideoQuality;

View File

@@ -51,6 +51,8 @@ static Cursor emptyCursor(0, 0, Point(0, 0), NULL);
extern rfb::BoolParameter disablebasicauth; extern rfb::BoolParameter disablebasicauth;
extern "C" char unixrelaynames[MAX_UNIX_RELAYS][MAX_UNIX_RELAY_NAME_LEN];
VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s, VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
bool reverse) bool reverse)
: upgradingToUdp(false), sock(s), reverseConnection(reverse), : upgradingToUdp(false), sock(s), reverseConnection(reverse),
@@ -73,6 +75,10 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
memset(bstats_total, 0, sizeof(bstats_total)); memset(bstats_total, 0, sizeof(bstats_total));
gettimeofday(&connStart, NULL); gettimeofday(&connStart, NULL);
unsigned i;
for (i = 0; i < MAX_UNIX_RELAYS; i++)
unixRelaySubscriptions[i][0] = '\0';
// Check their permissions, if applicable // Check their permissions, if applicable
kasmpasswdpath[0] = '\0'; kasmpasswdpath[0] = '\0';
wordexp_t wexp; wordexp_t wexp;
@@ -1789,3 +1795,54 @@ void VNCSConnectionST::udpDowngrade(const bool byServer)
vlog.info("Client %s downgrading from udp by %s", sock->getPeerAddress(), vlog.info("Client %s downgrading from udp by %s", sock->getPeerAddress(),
byServer ? "the server" : "its own request"); byServer ? "the server" : "its own request");
} }
void VNCSConnectionST::subscribeUnixRelay(const char *name)
{
bool read, write, owner;
if (!getPerms(read, write, owner) || !write) {
// Need write permissions to subscribe
writer()->writeSubscribeUnixRelay(false, "No permissions");
vlog.info("Client tried to subscribe to unix channel %s without permissions", name);
return;
}
unsigned i;
bool found = false;
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
if (!strcmp(name, unixrelaynames[i])) {
found = true;
break;
}
}
if (!found) {
writer()->writeSubscribeUnixRelay(false, "No such unix channel");
vlog.info("Client tried to subscribe to nonexistent unix channel %s", name);
return;
}
writer()->writeSubscribeUnixRelay(true, "Ok");
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
if (!unixRelaySubscriptions[i][0]) {
strcpy(unixRelaySubscriptions[i], name);
break;
}
}
}
void VNCSConnectionST::unixRelay(const char *name, const rdr::U8 *buf, const unsigned len)
{
unsigned i;
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
if (!strcmp(unixRelaySubscriptions[i], name)) {
server->desktop->receivedUnixRelayData(name, buf, len);
return;
}
}
}
void VNCSConnectionST::sendUnixRelayData(const char name[], const unsigned char *buf,
const unsigned len)
{
writer()->writeUnixRelay(name, buf, len);
}

View File

@@ -33,6 +33,7 @@
#include <rfb/EncodeManager.h> #include <rfb/EncodeManager.h>
#include <rfb/SConnection.h> #include <rfb/SConnection.h>
#include <rfb/Timer.h> #include <rfb/Timer.h>
#include <rfb/unixRelayLimits.h>
namespace rfb { namespace rfb {
class VNCServerST; class VNCServerST;
@@ -200,6 +201,18 @@ namespace rfb {
bool upgradingToUdp; bool upgradingToUdp;
bool isSubscribedToUnixRelay(const char *name) const {
unsigned i;
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
if (!strcmp(unixRelaySubscriptions[i], name))
return true;
}
return false;
}
virtual void sendUnixRelayData(const char name[], const unsigned char *buf,
const unsigned len);
private: private:
// SConnection callbacks // SConnection callbacks
@@ -222,6 +235,8 @@ namespace rfb {
virtual void handleClipboardAnnounce(bool available); virtual void handleClipboardAnnounce(bool available);
virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]); virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
virtual void udpUpgrade(const char *resp); virtual void udpUpgrade(const char *resp);
virtual void subscribeUnixRelay(const char *name);
virtual void unixRelay(const char *name, const rdr::U8 *buf, const unsigned len);
virtual void supportsLocalCursor(); virtual void supportsLocalCursor();
virtual void supportsFence(); virtual void supportsFence();
virtual void supportsContinuousUpdates(); virtual void supportsContinuousUpdates();
@@ -324,6 +339,8 @@ namespace rfb {
bool frameTracking; bool frameTracking;
uint32_t udpFramesSinceFull; uint32_t udpFramesSinceFull;
char unixRelaySubscriptions[MAX_UNIX_RELAYS][MAX_UNIX_RELAY_NAME_LEN];
bool complainedAboutNoViewRights; bool complainedAboutNoViewRights;
}; };
} }

View File

@@ -974,6 +974,11 @@ void VNCServerST::writeUpdate()
blackOut(); blackOut();
} }
if (watermarkData && Server::DLP_WatermarkText[0] && watermarkTextNeedsUpdate(true)) {
// If using a text watermark, we have to mark everything as changed...
refreshClients();
}
comparer->getUpdateInfo(&ui, pb->getRect()); comparer->getUpdateInfo(&ui, pb->getRect());
toCheck = ui.changed.union_(ui.copied); toCheck = ui.changed.union_(ui.copied);
@@ -1248,3 +1253,15 @@ void VNCServerST::refreshClients()
(*i)->add_changed_all(); (*i)->add_changed_all();
} }
} }
void VNCServerST::sendUnixRelayData(const char name[],
const unsigned char *buf, const unsigned len)
{
// For each client subscribed to this channel, send the data to them
std::list<VNCSConnectionST*>::iterator i;
for (i = clients.begin(); i != clients.end(); i++) {
if ((*i)->isSubscribedToUnixRelay(name)) {
(*i)->sendUnixRelayData(name, buf, len);
}
}
}

View File

@@ -198,6 +198,7 @@ namespace rfb {
const char mimes[][32]); const char mimes[][32]);
void refreshClients(); void refreshClients();
void sendUnixRelayData(const char name[], const unsigned char *buf, const unsigned len);
protected: protected:

View File

@@ -20,10 +20,14 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <zlib.h> #include <zlib.h>
#include <rfb/LogWriter.h> #include <rfb/LogWriter.h>
#include <rfb/ServerCore.h> #include <rfb/ServerCore.h>
#include <rfb/VNCServerST.h> #include <rfb/VNCServerST.h>
#include "font.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include "Watermark.h" #include "Watermark.h"
@@ -36,6 +40,10 @@ watermarkInfo_t watermarkInfo;
uint8_t *watermarkData, *watermarkUnpacked, *watermarkTmp; uint8_t *watermarkData, *watermarkUnpacked, *watermarkTmp;
uint32_t watermarkDataLen; uint32_t watermarkDataLen;
static uint16_t rw, rh; static uint16_t rw, rh;
static time_t lastUpdate;
static FT_Library ft = NULL;
static FT_Face face;
#define MAXW 4096 #define MAXW 4096
#define MAXH 4096 #define MAXH 4096
@@ -92,15 +100,151 @@ static bool loadimage(const char path[]) {
return true; return true;
} }
// Note: w and h are absolute
static void str(uint8_t *buf, const char *txt, const uint32_t x_, const uint32_t y_,
const uint32_t w, const uint32_t h,
const uint32_t stride) {
unsigned ucs[256], i, ucslen;
unsigned len = strlen(txt);
i = 0;
ucslen = 0;
while (len > 0 && txt[i]) {
size_t ret = rfb::utf8ToUCS4(&txt[i], len, &ucs[ucslen]);
i += ret;
len -= ret;
ucslen++;
}
uint32_t x, y;
x = x_;
y = y_;
for (i = 0; i < ucslen; i++) {
if (FT_Load_Char(face, ucs[i], FT_LOAD_RENDER))
continue;
const FT_Bitmap * const map = &(face->glyph->bitmap);
if (FT_HAS_KERNING(face) && i) {
FT_Vector delta;
FT_Get_Kerning(face, ucs[i - 1], ucs[i], ft_kerning_default, &delta);
x += delta.x >> 6;
}
uint32_t row, col;
for (row = 0; row < (uint32_t) map->rows; row++) {
int ny = row + y - face->glyph->bitmap_top;
if (ny < 0)
continue;
if ((unsigned) ny >= h)
continue;
uint8_t *dst = (uint8_t *) buf;
dst += ny * stride + x;
const uint8_t *src = map->buffer + map->pitch * row;
for (col = 0; col < (uint32_t) map->width; col++) {
if (col + x >= w)
continue;
const uint8_t out = (src[col] + 8) >> 4;
dst[col] = out < 16 ? out : 15;
}
}
x += face->glyph->advance.x >> 6;
}
}
static uint32_t drawnwidth(const char *txt) {
unsigned ucs[256], i, ucslen;
unsigned len = strlen(txt);
i = 0;
ucslen = 0;
while (len > 0 && txt[i]) {
size_t ret = rfb::utf8ToUCS4(&txt[i], len, &ucs[ucslen]);
i += ret;
len -= ret;
ucslen++;
}
uint32_t x;
x = 0;
for (i = 0; i < ucslen; i++) {
if (FT_Load_Char(face, ucs[i], FT_LOAD_DEFAULT))
continue;
if (FT_HAS_KERNING(face) && i) {
FT_Vector delta;
FT_Get_Kerning(face, ucs[i - 1], ucs[i], ft_kerning_default, &delta);
x += delta.x >> 6;
}
x += face->glyph->advance.x >> 6;
}
return x;
}
static bool drawtext(const char fmt[], const int16_t utcOff, const char fontpath[],
const uint8_t fontsize) {
char buf[PATH_MAX];
if (!ft) {
if (FT_Init_FreeType(&ft))
abort();
if (fontpath[0]) {
if (FT_New_Face(ft, fontpath, 0, &face))
abort();
} else {
if (FT_New_Memory_Face(ft, font_otf, sizeof(font_otf), 0, &face))
abort();
}
FT_Set_Pixel_Sizes(face, fontsize, fontsize);
}
time_t now = lastUpdate = time(NULL);
now += utcOff * 60;
struct tm *tm = gmtime(&now);
size_t len = strftime(buf, PATH_MAX, fmt, tm);
if (!len)
return false;
free(watermarkInfo.src);
const uint32_t h = fontsize + 4;
const uint32_t w = drawnwidth(buf);
watermarkInfo.w = w;
watermarkInfo.h = h;
watermarkInfo.src = (uint8_t *) calloc(w, h);
str(watermarkInfo.src, buf, 0, fontsize, w, h, w);
return true;
}
bool watermarkInit() { bool watermarkInit() {
memset(&watermarkInfo, 0, sizeof(watermarkInfo_t)); memset(&watermarkInfo, 0, sizeof(watermarkInfo_t));
watermarkData = watermarkUnpacked = watermarkTmp = NULL; watermarkData = watermarkUnpacked = watermarkTmp = NULL;
rw = rh = 0; rw = rh = 0;
if (!Server::DLP_WatermarkImage[0]) if (!Server::DLP_WatermarkImage[0] && !Server::DLP_WatermarkText[0])
return true; return true;
if (!loadimage(Server::DLP_WatermarkImage)) if (Server::DLP_WatermarkImage[0] && Server::DLP_WatermarkText[0]) {
vlog.error("WatermarkImage and WatermarkText can't be used together");
return false;
}
if (Server::DLP_WatermarkImage[0] && !loadimage(Server::DLP_WatermarkImage))
return false;
if (Server::DLP_WatermarkText[0] &&
!drawtext(Server::DLP_WatermarkText,
Server::DLP_WatermarkTimeOffset * 60 + Server::DLP_WatermarkTimeOffsetMinutes,
Server::DLP_WatermarkFont, Server::DLP_WatermarkFontSize))
return false; return false;
if (Server::DLP_WatermarkRepeatSpace && Server::DLP_WatermarkLocation[0]) { if (Server::DLP_WatermarkRepeatSpace && Server::DLP_WatermarkLocation[0]) {
@@ -136,10 +280,22 @@ bool watermarkInit() {
} }
// update the screen-size rendered watermark whenever the screen is resized // update the screen-size rendered watermark whenever the screen is resized
// or if using text, every frame
void VNCServerST::updateWatermark() { void VNCServerST::updateWatermark() {
if (rw == pb->width() && if (rw == pb->width() &&
rh == pb->height()) rh == pb->height()) {
return;
if (Server::DLP_WatermarkImage[0])
return;
if (!watermarkTextNeedsUpdate(false))
return;
}
if (Server::DLP_WatermarkText[0] && watermarkTextNeedsUpdate(false)) {
drawtext(Server::DLP_WatermarkText,
Server::DLP_WatermarkTimeOffset * 60 + Server::DLP_WatermarkTimeOffsetMinutes,
Server::DLP_WatermarkFont, Server::DLP_WatermarkFontSize);
}
rw = pb->width(); rw = pb->width();
rh = pb->height(); rh = pb->height();
@@ -246,3 +402,15 @@ void packWatermark(const Region &changed) {
watermarkDataLen = destLen; watermarkDataLen = destLen;
} }
// Limit changes to once per second
bool watermarkTextNeedsUpdate(const bool early) {
static time_t now;
// We're called a couple times per frame, only grab the
// time on the first time so it doesn't change inside a frame
if (early)
now = time(NULL);
return now != lastUpdate;
}

View File

@@ -36,6 +36,7 @@ extern watermarkInfo_t watermarkInfo;
bool watermarkInit(); bool watermarkInit();
void packWatermark(const rfb::Region &changed); // filter and pack the watermark for sending void packWatermark(const rfb::Region &changed); // filter and pack the watermark for sending
bool watermarkTextNeedsUpdate(const bool early);
extern uint8_t *watermarkData; extern uint8_t *watermarkData;
extern uint32_t watermarkDataLen; extern uint32_t watermarkDataLen;

3107
common/rfb/font.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -33,6 +33,8 @@ namespace rfb {
const int msgTypeRequestFrameStats = 179; const int msgTypeRequestFrameStats = 179;
const int msgTypeBinaryClipboard = 180; const int msgTypeBinaryClipboard = 180;
const int msgTypeUpgradeToUdp = 181; const int msgTypeUpgradeToUdp = 181;
const int msgTypeSubscribeUnixRelay = 182;
const int msgTypeUnixRelay = 183;
const int msgTypeServerFence = 248; const int msgTypeServerFence = 248;
@@ -54,6 +56,8 @@ namespace rfb {
// same as the other direction // same as the other direction
//const int msgTypeBinaryClipboard = 180; //const int msgTypeBinaryClipboard = 180;
//const int msgTypeUpgradeToUdp = 181; //const int msgTypeUpgradeToUdp = 181;
//const int msgTypeSubscribeUnixRelay = 182;
//const int msgTypeUnixRelay = 183;
const int msgTypeClientFence = 248; const int msgTypeClientFence = 248;

View File

@@ -0,0 +1,7 @@
#ifndef UNIX_RELAY_LIMITS_H
#define UNIX_RELAY_LIMITS_H
#define MAX_UNIX_RELAYS 4
#define MAX_UNIX_RELAY_NAME_LEN 64
#endif

2
debian/control vendored
View File

@@ -14,7 +14,7 @@ Architecture: amd64 arm64
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, ssl-cert, xauth, Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, ssl-cert, xauth,
x11-xkb-utils, xkb-data, procps, libswitch-perl, libyaml-tiny-perl, x11-xkb-utils, xkb-data, procps, libswitch-perl, libyaml-tiny-perl,
libhash-merge-simple-perl, libscalar-list-utils-perl, liblist-moreutils-perl, libhash-merge-simple-perl, libscalar-list-utils-perl, liblist-moreutils-perl,
libtry-tiny-perl, libgbm1 libtry-tiny-perl, libdatetime-timezone-perl, libgbm1
Provides: vnc-server Provides: vnc-server
Description: KasmVNC provides remote web-based access to a Desktop or application. Description: KasmVNC provides remote web-based access to a Desktop or application.
While VNC is in the name, KasmVNC differs from other VNC variants such While VNC is in the name, KasmVNC differs from other VNC variants such

View File

@@ -7,7 +7,7 @@ License: GPLv2+
URL: https://github.com/kasmtech/KasmVNC URL: https://github.com/kasmtech/KasmVNC
BuildRequires: rsync BuildRequires: rsync
Requires: xorg-x11-xauth, xkeyboard-config, xkbcomp, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, mesa-libgbm, libxshmfence Requires: xorg-x11-xauth, xkeyboard-config, xkbcomp, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, perl-DateTime-TimeZone, mesa-libgbm, libxshmfence
Conflicts: tigervnc-server, tigervnc-server-minimal Conflicts: tigervnc-server, tigervnc-server-minimal
%description %description

Submodule kasmweb updated: 3873a59941...2b7e3321ae

View File

@@ -7,7 +7,7 @@ License: GPLv2+
URL: https://github.com/kasmtech/KasmVNC URL: https://github.com/kasmtech/KasmVNC
BuildRequires: rsync BuildRequires: rsync
Requires: xauth, hostname, libxkbcommon-x11-0, xkeyboard-config, x11-tools, openssl, perl, libpixman-1-0, libjpeg8, libgomp1, libXfont2-2, libXdmcp6, libglvnd, xkbcomp, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, libgbm1, libxshmfence1 Requires: xauth, hostname, libxkbcommon-x11-0, xkeyboard-config, x11-tools, openssl, perl, libpixman-1-0, libjpeg8, libgomp1, libXfont2-2, libXdmcp6, libglvnd, xkbcomp, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, perl-DateTime, perl-DateTime-TimeZone, libgbm1, libxshmfence1
Conflicts: tigervnc, tigervnc-x11vnc Conflicts: tigervnc, tigervnc-x11vnc
%description %description

View File

@@ -7,7 +7,7 @@ License: GPLv2+
URL: https://github.com/kasmtech/KasmVNC URL: https://github.com/kasmtech/KasmVNC
BuildRequires: rsync BuildRequires: rsync
Requires: xorg-x11-xauth, xorg-x11-xkb-utils, xkeyboard-config, xorg-x11-server-utils, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, hostname, mesa-libgbm, libxshmfence Requires: xorg-x11-xauth, xorg-x11-xkb-utils, xkeyboard-config, xorg-x11-server-utils, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, perl-DateTime-TimeZone, hostname, mesa-libgbm, libxshmfence
Conflicts: tigervnc-server, tigervnc-server-minimal Conflicts: tigervnc-server, tigervnc-server-minimal
%description %description

View File

@@ -7,7 +7,7 @@ License: GPLv2+
URL: https://github.com/kasmtech/KasmVNC URL: https://github.com/kasmtech/KasmVNC
BuildRequires: rsync BuildRequires: rsync
Requires: xorg-x11-xauth, xkeyboard-config, xorg-x11-server-utils, xkbcomp, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, hostname, mesa-libgbm, libxshmfence Requires: xorg-x11-xauth, xkeyboard-config, xorg-x11-server-utils, xkbcomp, openssl, perl, perl-Switch, perl-YAML-Tiny, perl-Hash-Merge-Simple, perl-Scalar-List-Utils, perl-List-MoreUtils, perl-Try-Tiny, perl-DateTime-TimeZone, hostname, mesa-libgbm, libxshmfence
Conflicts: tigervnc-server, tigervnc-server-minimal Conflicts: tigervnc-server, tigervnc-server-minimal
%description %description

View File

@@ -2,7 +2,7 @@ import os
import re import re
import shutil import shutil
from os.path import expanduser from os.path import expanduser
from mamba import description, context, fcontext, it, fit, before, after from mamba import description, context, fcontext, it, fit, _it, before, after
from expects import expect, equal, contain, match from expects import expect, equal, contain, match
from helper.spec_helper import start_xvnc, kill_xvnc, run_cmd, clean_env, \ from helper.spec_helper import start_xvnc, kill_xvnc, run_cmd, clean_env, \
@@ -268,6 +268,18 @@ with description('YAML to CLI') as self:
completed_process.stdout) completed_process.stdout)
expect(cli_option).to(equal("-geometry '1024x768'")) expect(cli_option).to(equal("-geometry '1024x768'"))
with it("allows wide utf characters"):
write_config('''
data_loss_prevention:
watermark:
text:
template: "星街すいせい"
''')
completed_process = run_vncserver()
cli_option = pick_cli_option('DLP_WatermarkText',
completed_process.stdout)
expect(cli_option).to(equal("-DLP_WatermarkText '星街すいせい'"))
with it("ignores empty section override"): with it("ignores empty section override"):
write_config(''' write_config('''
security: security:

9
t Normal file
View File

@@ -0,0 +1,9 @@
use DateTime::TimeZone;
my $timezone = $ARGV[0];
if (DateTime::TimeZone->is_valid_name($timezone)) {
print "Valid timezone\n";
} else {
print "Invalid timezone\n";
}

11
t2 Normal file
View File

@@ -0,0 +1,11 @@
use DateTime;
use DateTime::TimeZone;
#my $timezone_name = 'America/New_York';
my $timezone_name = 'UTC';
my $dt = DateTime->now(time_zone => $timezone_name);
my $offset = $dt->offset();
print "Timezone: $timezone_name\n";
print "Offset: $offset seconds\n";

View File

@@ -0,0 +1,37 @@
package KasmVNC::CallbackValidator;
use strict;
use warnings;
use v5.10;
use Data::Dumper;
use KasmVNC::Utils;
sub new {
my ($class, $args) = @_;
my $self = bless {
isValidCallback => $args->{isValidCallback},
errorMessage => $args->{errorMessage}
}, $class;
}
sub validate {
my $self = shift;
$self->{configKey} = shift;
my @values = @{ listify($self->{configKey}->value()) };
foreach my $value (@values) {
$self->validateValue($value);
}
}
sub validateValue {
my $self = shift;
my $value = shift;
unless ($self->{isValidCallback}($value)) {
$self->{configKey}->addErrorMessage($self->{errorMessage});
}
}
1;

View File

@@ -35,7 +35,7 @@ sub new {
}, },
toStringSub => $args->{toStringSub} || sub { toStringSub => $args->{toStringSub} || sub {
my $self = shift; my $self = shift;
my $derivedValue = $self->deriveValue(); my $derivedValue = $self->deriveValue();
if (defined($derivedValue)) { if (defined($derivedValue)) {
return "-$self->{name} " . "'$derivedValue'"; return "-$self->{name} " . "'$derivedValue'";

View File

@@ -45,6 +45,8 @@ sub isPresent {
sub deriveBoolean { sub deriveBoolean {
my $value = shift; my $value = shift;
return $value if containsWideSymbols($value);
switch($value) { switch($value) {
case 'true' { case 'true' {
return 1; return 1;
@@ -63,4 +65,12 @@ sub printStackTrace {
print { *STDERR } $trace->as_string; print { *STDERR } $trace->as_string;
} }
sub containsWideSymbols {
my $string = shift;
return 1 unless defined($string);
$string =~ /[^\x00-\xFF]/;
}
1; 1;

View File

@@ -23,6 +23,9 @@ network:
pem_certificate: /etc/ssl/certs/ssl-cert-snakeoil.pem pem_certificate: /etc/ssl/certs/ssl-cert-snakeoil.pem
pem_key: /etc/ssl/private/ssl-cert-snakeoil.key pem_key: /etc/ssl/private/ssl-cert-snakeoil.key
require_ssl: true require_ssl: true
# unix_relay:
# name:
# path:
user_session: user_session:
# session_type: shared # session_type: shared
@@ -92,6 +95,11 @@ data_loss_prevention:
# location: 10,10 # location: 10,10
# tint: 255,20,20,128 # tint: 255,20,20,128
# repeat_spacing: 10 # repeat_spacing: 10
#text:
# template: "${USER} %H:%M"
# font: auto
# font_size: 48
# timezone_name: Australia/Adelaide
logging: logging:
# "verbose" SETTING LOGS YOUR PRIVATE INFORMATION. Keypresses and clipboard content # "verbose" SETTING LOGS YOUR PRIVATE INFORMATION. Keypresses and clipboard content
level: off level: off

View File

@@ -27,6 +27,7 @@
use v5.10; use v5.10;
use warnings; use warnings;
use utf8;
sub DEVENV() { $ENV{KASMVNC_DEVELOPMENT} }; sub DEVENV() { $ENV{KASMVNC_DEVELOPMENT} };
use if DEVENV, Devel::StackTrace; use if DEVENV, Devel::StackTrace;
@@ -38,11 +39,14 @@ use List::Util qw(first);
use List::MoreUtils qw(any uniq); use List::MoreUtils qw(any uniq);
use Data::Dumper; use Data::Dumper;
use Try::Tiny; use Try::Tiny;
use DateTime;
use DateTime::TimeZone;
use KasmVNC::CliOption; use KasmVNC::CliOption;
use KasmVNC::ConfigKey; use KasmVNC::ConfigKey;
use KasmVNC::PatternValidator; use KasmVNC::PatternValidator;
use KasmVNC::EnumValidator; use KasmVNC::EnumValidator;
use KasmVNC::CallbackValidator;
use KasmVNC::Config; use KasmVNC::Config;
use KasmVNC::Users; use KasmVNC::Users;
use KasmVNC::TextOption; use KasmVNC::TextOption;
@@ -56,6 +60,7 @@ use constant {
OPTIONAL_ARG_VALUE => 2 OPTIONAL_ARG_VALUE => 2
}; };
UseUtfStdio();
InitLogger(); InitLogger();
CheckWeCanRunInThisEnvironment(); CheckWeCanRunInThisEnvironment();
@@ -1397,6 +1402,24 @@ sub DefineConfigToCLIConversion {
}) })
] ]
}), }),
KasmVNC::CliOption->new({
name => 'UnixRelay',
configKeys => [
KasmVNC::ConfigKey->new({
name => "network.unix_relay.name",
type => KasmVNC::ConfigKey::ANY
}),
KasmVNC::ConfigKey->new({
name => "network.unix_relay.path",
type => KasmVNC::ConfigKey::ANY
})
],
deriveValueSub => sub {
my $self = shift;
$self->{"network.unix_relay.name"} . ":" . $self->{"network.unix_relay.path"};
},
}),
KasmVNC::CliOption->new({ KasmVNC::CliOption->new({
name => 'AlwaysShared', name => 'AlwaysShared',
configKeys => [ configKeys => [
@@ -1765,6 +1788,79 @@ sub DefineConfigToCLIConversion {
}) })
] ]
}), }),
KasmVNC::CliOption->new({
name => 'DLP_WatermarkText',
configKeys => [
KasmVNC::ConfigKey->new({
name => "data_loss_prevention.watermark.text.template",
validator => KasmVNC::CallbackValidator->new({
isValidCallback => sub {
my $value = shift;
isBlank(ConfigValue("data_loss_prevention.watermark.image"));
},
errorMessage => "Watermark image and text can't be used at the same time"
}),
})
]
}),
KasmVNC::CliOption->new({
name => 'DLP_WatermarkFont',
configKeys => [
KasmVNC::ConfigKey->new({
name => "data_loss_prevention.watermark.text.font",
type => KasmVNC::ConfigKey::ANY
})
],
isActiveSub => sub {
$self = shift;
my $value = $self->configValue();
isPresent($value) && $value ne "auto";
}
}),
KasmVNC::CliOption->new({
name => 'DLP_WatermarkFontSize',
configKeys => [
KasmVNC::ConfigKey->new({
name => "data_loss_prevention.watermark.text.font_size",
validator => KasmVNC::CallbackValidator->new({
isValidCallback => sub {
my $value = shift;
return 0 unless $value =~ /^\d+$/;
$value >= 8 && $value <= 256;
},
errorMessage => "must be in range 8..256"
}),
})
]
}),
KasmVNC::CliOption->new({
name => 'DLP_WatermarkTimeOffsetMinutes',
configKeys => [
KasmVNC::ConfigKey->new({
name => "data_loss_prevention.watermark.text.timezone_name",
validator => KasmVNC::CallbackValidator->new({
isValidCallback => sub {
my $timezone_name = shift;
DateTime::TimeZone->is_valid_name($timezone_name);
},
errorMessage => "must be a valid timezone name like Australia/Adelaide"
})
})
],
deriveValueSub => sub {
my $self = shift;
my $timezone_name = $self->configValue();
my $dt = DateTime->now(time_zone => $timezone_name);
my $offset_in_seconds = $dt->offset();
$offset_in_seconds/60;
}
}),
KasmVNC::CliOption->new({ KasmVNC::CliOption->new({
name => 'DLP_Log', name => 'DLP_Log',
configKeys => [ configKeys => [
@@ -2835,3 +2931,7 @@ sub InitLogger {
my $debugEnabled = any { $_ eq "-debug" } @ARGV; my $debugEnabled = any { $_ eq "-debug" } @ARGV;
$logger = KasmVNC::Logger->new({ level => $debugEnabled ? "debug" : "warn" }); $logger = KasmVNC::Logger->new({ level => $debugEnabled ? "debug" : "warn" });
} }
sub UseUtfStdio {
use open qw( :std :encoding(UTF-8) );
}

View File

@@ -52,7 +52,8 @@ Xvnc_CPPFLAGS = $(XVNC_CPPFLAGS) -DKASMVNC -DNO_MODULE_EXTS \
-I$(top_srcdir)/dri3 @LIBDRM_CFLAGS@ -I$(top_srcdir)/dri3 @LIBDRM_CFLAGS@
Xvnc_LDADD = $(XVNC_LIBS) libvnccommon.la $(COMMON_LIBS) \ Xvnc_LDADD = $(XVNC_LIBS) libvnccommon.la $(COMMON_LIBS) \
$(XSERVER_LIBS) $(XSERVER_SYS_LIBS) $(XVNC_SYS_LIBS) -lX11 -lwebp -lssl -lcrypto -lcrypt $(XSERVER_LIBS) $(XSERVER_SYS_LIBS) $(XVNC_SYS_LIBS) -lX11 -lwebp -lssl -lcrypto -lcrypt \
-lfreetype
Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) -fopenmp Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) -fopenmp

View File

@@ -29,6 +29,8 @@
#include <pwd.h> #include <pwd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/utsname.h> #include <sys/utsname.h>
@@ -51,6 +53,7 @@ extern "C" {
void vncSetGlueContext(int screenIndex); void vncSetGlueContext(int screenIndex);
extern int wakeuppipe[2]; extern int wakeuppipe[2];
extern struct sockaddr_un unixrelayclients[MAX_UNIX_RELAYS];
} }
using namespace rfb; using namespace rfb;
@@ -323,6 +326,26 @@ void XserverDesktop::handleSocketEvent(int fd, bool read, bool write)
return; return;
} }
unsigned i;
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
if (unixrelays[i] == -1)
break;
if (fd == unixrelays[i]) {
do {
struct sockaddr_un client;
socklen_t addrlen = sizeof(struct sockaddr_un);
const ssize_t len = recvfrom(unixrelays[i], unixbuf, sizeof(unixbuf),
MSG_DONTWAIT,
(struct sockaddr *) &client, &addrlen);
if (len <= 0)
break;
memcpy(&unixrelayclients[i], &client, addrlen);
server->sendUnixRelayData(unixrelaynames[i], unixbuf, len);
} while (1);
return;
}
}
if (handleListenerEvent(fd, &listeners, server)) if (handleListenerEvent(fd, &listeners, server))
return; return;
} }
@@ -557,3 +580,21 @@ bool XserverDesktop::handleTimeout(Timer* t)
return false; return false;
} }
void XserverDesktop::receivedUnixRelayData(const char name[], const unsigned char *buf,
const unsigned len)
{
unsigned i;
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
if (unixrelays[i] == -1)
break;
if (strcmp(name, unixrelaynames[i]))
continue;
if (sendto(unixrelays[i], buf, len, 0,
(struct sockaddr *) &unixrelayclients[i], sizeof(struct sockaddr_un)) == -1)
vlog.error("Error writing unix relay data to %s", name);
break;
}
}

View File

@@ -110,6 +110,9 @@ public:
const char* userName, const char* userName,
char** reason); char** reason);
virtual void receivedUnixRelayData(const char name[], const unsigned char *buf,
const unsigned len);
protected: protected:
bool handleListenerEvent(int fd, bool handleListenerEvent(int fd,
std::list<network::SocketListener*>* sockets, std::list<network::SocketListener*>* sockets,
@@ -138,5 +141,7 @@ private:
rfb::Point oldCursorPos; rfb::Point oldCursorPos;
bool resizing; bool resizing;
uint8_t unixbuf[1024 * 1024];
}; };
#endif #endif

View File

@@ -89,6 +89,11 @@ Use IPv4 for incoming and outgoing connections. Default is on.
Use IPv6 for incoming and outgoing connections. Default is on. Use IPv6 for incoming and outgoing connections. Default is on.
. .
.TP .TP
.B \-UnixRelay \fIname:path\fP
Create a local named unix socket, for relaying data. May be given multiple times.
Example: -UnixRelay audio:/tmp/audiosock
.
.TP
.B \-rfbunixpath \fIpath\fP .B \-rfbunixpath \fIpath\fP
Specifies the path of a Unix domain socket on which Xvnc listens for Specifies the path of a Unix domain socket on which Xvnc listens for
connections from viewers, instead of listening on a TCP port. connections from viewers, instead of listening on a TCP port.
@@ -243,6 +248,8 @@ Default \fB-1\fP.
.B \-WebpVideoQuality \fInum\fP .B \-WebpVideoQuality \fInum\fP
The WEBP quality to use when in video mode. The WEBP quality to use when in video mode.
Default \fB-1\fP. Default \fB-1\fP.
.
.TP
.B \-MaxVideoResolution \fI1920x1080\fP .B \-MaxVideoResolution \fI1920x1080\fP
When in video mode, downscale the screen to max this size. Keeps aspect ratio. When in video mode, downscale the screen to max this size. Keeps aspect ratio.
Default \fB1920x1080\fP. Default \fB1920x1080\fP.
@@ -372,6 +379,28 @@ The color components can be used to colorize the greyscale watermark, and the al
can be used to make it fainter. can be used to make it fainter.
. .
.TP .TP
.B \-DLP_WatermarkText \fI"foo %H:%M"\fP
Instead of an image, render this text as the watermark. Takes time formatting options
for \fBstrftime\fP.
.
.TP
.B \-DLP_WatermarkFont \fI/path/to/font.ttf\fP
Use a different font for -DLP_WatermarkText than the bundled one. TTF and OTF fonts
are accepted.
.
.TP
.B \-DLP_WatermarkFontSize \fI48\fP
Font size for -DLP_WatermarkText. Default \fI48\fP.
.
.TP
.B \-DLP_WatermarkTimeOffset \fI0\fP
Time offset from UTC, hours. Default \fI0\fP.
.
.TP
.B \-DLP_WatermarkTimeOffsetMinutes \fI0\fP
Time offset from UTC, minutes. Default \fI0\fP.
.
.TP
.B \-selfBench .B \-selfBench
Run a set of self-benchmarks and exit. Run a set of self-benchmarks and exit.
. .

View File

@@ -55,6 +55,15 @@ typedef struct gbm_pixmap gbm_pixmap;
static DevPrivateKeyRec dri3_pixmap_private_key; static DevPrivateKeyRec dri3_pixmap_private_key;
static struct timeval start; static struct timeval start;
#define MAX_TEXPIXMAPS 32
static PixmapPtr texpixmaps[MAX_TEXPIXMAPS];
static uint32_t num_texpixmaps;
static CARD32 update_texpixmaps(OsTimerPtr timer, CARD32 time, void *arg);
static OsTimerPtr texpixmaptimer;
void xvnc_sync_dri3_textures(void);
void xvnc_sync_dri3_pixmap(PixmapPtr pixmap);
void xvnc_init_dri3(void);
static int static int
@@ -99,6 +108,29 @@ static gbm_pixmap *gbm_pixmap_get(PixmapPtr pixmap)
return dixLookupPrivate(&pixmap->devPrivates, &dri3_pixmap_private_key); return dixLookupPrivate(&pixmap->devPrivates, &dri3_pixmap_private_key);
} }
static void add_texpixmap(PixmapPtr pix)
{
uint32_t i;
for (i = 0; i < MAX_TEXPIXMAPS; i++) {
if (texpixmaps[i] == pix)
return;
}
for (i = 0; i < MAX_TEXPIXMAPS; i++) {
if (!texpixmaps[i]) {
texpixmaps[i] = pix;
pix->refcnt++;
num_texpixmaps++;
// start if not running
if (!texpixmaptimer)
texpixmaptimer = TimerSet(NULL, 0, 16, update_texpixmaps, NULL);
return;
}
}
ErrorF("Max number of texpixmaps reached\n");
}
static PixmapPtr static PixmapPtr
create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, CARD8 depth) create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, CARD8 depth)
{ {
@@ -164,14 +196,33 @@ xvnc_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
uint64_t *modifier) uint64_t *modifier)
{ {
gbm_pixmap *gp = gbm_pixmap_get(pixmap); gbm_pixmap *gp = gbm_pixmap_get(pixmap);
if (!gp)
return 0; if (!gp) {
gp = calloc(1, sizeof(gbm_pixmap));
if (!gp)
return 0;
gp->bo = gbm_bo_create(priv.gbm,
pixmap->drawable.width,
pixmap->drawable.height,
gbm_format_for_depth(pixmap->drawable.depth),
(pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED ?
GBM_BO_USE_LINEAR : 0) |
GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
if (!gp->bo) {
ErrorF("Failed to create bo\n");
return 0;
}
dri3_pixmap_set_private(pixmap, gp);
}
fds[0] = gbm_bo_get_fd(gp->bo); fds[0] = gbm_bo_get_fd(gp->bo);
strides[0] = gbm_bo_get_stride(gp->bo); strides[0] = gbm_bo_get_stride(gp->bo);
offsets[0] = 0; offsets[0] = 0;
*modifier = DRM_FORMAT_MOD_INVALID; *modifier = DRM_FORMAT_MOD_INVALID;
add_texpixmap(pixmap);
return 1; return 1;
} }
@@ -219,12 +270,13 @@ void xvnc_sync_dri3_pixmap(PixmapPtr pixmap)
void *ptr; void *ptr;
uint32_t stride, w, h; uint32_t stride, w, h;
void *opaque = NULL; void *opaque = NULL;
gbm_pixmap *gp;
// We may not be running on hw if there's a compositor using PRESENT on llvmpipe // We may not be running on hw if there's a compositor using PRESENT on llvmpipe
if (!driNode) if (!driNode)
return; return;
gbm_pixmap *gp = gbm_pixmap_get(pixmap); gp = gbm_pixmap_get(pixmap);
if (!gp) { if (!gp) {
//ErrorF("Present tried to copy from a non-dri3 pixmap\n"); //ErrorF("Present tried to copy from a non-dri3 pixmap\n");
return; return;
@@ -252,6 +304,69 @@ void xvnc_sync_dri3_pixmap(PixmapPtr pixmap)
gbm_bo_unmap(gp->bo, opaque); gbm_bo_unmap(gp->bo, opaque);
} }
void xvnc_sync_dri3_textures(void)
{
// Sync the tracked pixmaps into their textures (bos)
// This is a bit of an ugly solution, but we don't know
// when the pixmaps have changed nor when the textures are read.
//
// This is called both from the global damage report and the timer,
// to account for cases that do not use the damage report.
uint32_t i, y;
gbm_pixmap *gp;
uint8_t *src, *dst;
uint32_t srcstride, dststride;
void *opaque = NULL;
for (i = 0; i < MAX_TEXPIXMAPS; i++) {
if (!texpixmaps[i])
continue;
if (texpixmaps[i]->refcnt == 1) {
// We are the only user left, delete it
texpixmaps[i]->drawable.pScreen->DestroyPixmap(texpixmaps[i]);
texpixmaps[i] = NULL;
num_texpixmaps--;
continue;
}
gp = gbm_pixmap_get(texpixmaps[i]);
opaque = NULL;
dst = gbm_bo_map(gp->bo, 0, 0,
texpixmaps[i]->drawable.width,
texpixmaps[i]->drawable.height,
GBM_BO_TRANSFER_WRITE, &dststride, &opaque);
if (!dst) {
ErrorF("gbm map failed, errno %d\n", errno);
continue;
}
srcstride = texpixmaps[i]->devKind;
src = texpixmaps[i]->devPrivate.ptr;
for (y = 0; y < texpixmaps[i]->drawable.height; y++) {
memcpy(dst, src, srcstride);
dst += dststride;
src += srcstride;
}
gbm_bo_unmap(gp->bo, opaque);
}
}
static CARD32 update_texpixmaps(OsTimerPtr timer, CARD32 time, void *arg)
{
xvnc_sync_dri3_textures();
if (!num_texpixmaps) {
TimerFree(texpixmaptimer);
texpixmaptimer = NULL;
return 0;
}
return 16; // Reschedule next tick
}
void xvnc_init_dri3(void) void xvnc_init_dri3(void)
{ {
memset(&priv, 0, sizeof(priv)); memset(&priv, 0, sizeof(priv));

View File

@@ -241,6 +241,14 @@ void vncExtensionInit(void)
fcntl(wakeuppipe[0], F_SETFL, flags | O_NONBLOCK); fcntl(wakeuppipe[0], F_SETFL, flags | O_NONBLOCK);
vncSetNotifyFd(wakeuppipe[0], 0, true, false); vncSetNotifyFd(wakeuppipe[0], 0, true, false);
unsigned i;
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
if (unixrelays[i] == -1)
break;
vncSetNotifyFd(unixrelays[i], 0, true, false);
vlog.info("Listening to unix relay socket %s", unixrelaynames[i]);
}
initialised = true; initialised = true;
} }

View File

@@ -23,6 +23,8 @@
#include <stddef.h> #include <stddef.h>
#include <sys/select.h> #include <sys/select.h>
#include <rfb/unixRelayLimits.h>
// Only from C++ // Only from C++
#ifdef __cplusplus #ifdef __cplusplus
namespace rfb { class StringParameter; }; namespace rfb { class StringParameter; };
@@ -106,6 +108,9 @@ void vncRefreshScreenLayout(int scrIdx);
int vncOverrideParam(const char *nameAndValue); int vncOverrideParam(const char *nameAndValue);
extern int unixrelays[MAX_UNIX_RELAYS];
extern char unixrelaynames[MAX_UNIX_RELAYS][MAX_UNIX_RELAY_NAME_LEN];
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -61,8 +61,11 @@ from the X Consortium.
#include "input.h" #include "input.h"
#include "mipointer.h" #include "mipointer.h"
#include "micmap.h" #include "micmap.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h>
#include <errno.h> #include <errno.h>
#ifndef WIN32 #ifndef WIN32
#include <sys/param.h> #include <sys/param.h>
@@ -163,6 +166,73 @@ static char displayNumStr[16];
static int vncVerbose = DEFAULT_LOG_VERBOSITY; static int vncVerbose = DEFAULT_LOG_VERBOSITY;
int unixrelays[MAX_UNIX_RELAYS];
char unixrelaynames[MAX_UNIX_RELAYS][MAX_UNIX_RELAY_NAME_LEN];
struct sockaddr_un unixrelayclients[MAX_UNIX_RELAYS];
static unsigned addrelay(const char * const arg)
{
const char *ptr = strchr(arg, ':');
if (!ptr) {
ErrorF("Invalid unixrelay\n");
return 1;
}
const unsigned namelen = ptr - arg;
if (namelen >= MAX_UNIX_RELAY_NAME_LEN) {
ErrorF("Unix relay name too long\n");
return 1;
}
unsigned i;
unsigned char found = 0;
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
if (unixrelays[i] == -1) {
found = 1;
break;
}
}
if (!found) {
ErrorF("Too many unix relays\n");
return 1;
}
memcpy(unixrelaynames[i], arg, namelen);
unixrelaynames[i][namelen] = '\0';
unixrelays[i] = socket(AF_UNIX, SOCK_DGRAM, 0);
if (unixrelays[i] < 0) {
ErrorF("Failed to create unix sock\n");
return 1;
}
ptr++;
struct sockaddr_un sa;
if (strlen(ptr) >= sizeof(sa.sun_path)) {
ErrorF("Unix relay path too long\n");
return 1;
}
sa.sun_family = AF_UNIX;
strcpy(sa.sun_path, ptr);
// SO_REUSEADDR doesn't exist for unix sockets, if the socket exists
// (from our previous run), we need to delete it first. Check it's a
// socket so we don't delete wrong files
struct stat st;
if (stat(ptr, &st) == 0) {
if (S_ISSOCK(st.st_mode))
unlink(ptr);
}
if (bind(unixrelays[i], (struct sockaddr *) &sa, sizeof(struct sockaddr_un))) {
ErrorF("Failed to bind unix sock\n");
return 1;
}
return 0;
}
char *extra_headers = NULL; char *extra_headers = NULL;
unsigned extra_headers_len = 0; unsigned extra_headers_len = 0;
@@ -374,6 +444,7 @@ void ddxUseMsg(void)
ErrorF("-inetd has been launched from inetd\n"); ErrorF("-inetd has been launched from inetd\n");
ErrorF("-http-header name=val append this header to all HTTP responses\n"); ErrorF("-http-header name=val append this header to all HTTP responses\n");
ErrorF("-noclipboard disable clipboard settings modification via vncconfig utility\n"); ErrorF("-noclipboard disable clipboard settings modification via vncconfig utility\n");
ErrorF("-unixrelay name:path create a local named unix relay socket\n");
ErrorF("-verbose [n] verbose startup messages\n"); ErrorF("-verbose [n] verbose startup messages\n");
ErrorF("-quiet minimal startup messages\n"); ErrorF("-quiet minimal startup messages\n");
ErrorF("-version show the server version\n"); ErrorF("-version show the server version\n");
@@ -426,6 +497,13 @@ ddxProcessArgument(int argc, char *argv[], int i)
vfbInitializeDefaultScreens(); vfbInitializeDefaultScreens();
vfbInitializePixmapDepths(); vfbInitializePixmapDepths();
unsigned r;
for (r = 0; r < MAX_UNIX_RELAYS; r++) {
unixrelays[r] = -1;
unixrelaynames[r][0] = '\0';
}
firstTime = FALSE; firstTime = FALSE;
vncInitRFB(); vncInitRFB();
} }
@@ -692,6 +770,16 @@ ddxProcessArgument(int argc, char *argv[], int i)
return 1; return 1;
} }
if (strcasecmp(argv[i], "-unixrelay") == 0)
{
fail_unless_args(argc, i, 1);
++i;
if (addrelay(argv[i]))
return 0;
return 2;
}
if (!strcmp(argv[i], "-verbose")) { if (!strcmp(argv[i], "-verbose")) {
if (++i < argc && argv[i]) { if (++i < argc && argv[i]) {
char *end; char *end;
@@ -1916,6 +2004,8 @@ InitOutput(ScreenInfo *scrInfo, int argc, char **argv)
#else #else
FatalError("DRI3 disabled at compile time\n"); FatalError("DRI3 disabled at compile time\n");
#endif #endif
} else {
driNode = NULL;
} }
} /* end InitOutput */ } /* end InitOutput */

View File

@@ -111,3 +111,23 @@ Index: xserver/mi/miinitext.c
gc = GetScratchGC(drawable->depth, screen); gc = GetScratchGC(drawable->depth, screen);
if (update) { if (update) {
ChangeGCVal changes[2]; ChangeGCVal changes[2];
--- xserver.orig/damageext/damageext.c 2019-02-26 21:28:50.000000000 +0200
+++ xserver/damageext/damageext.c 2023-03-21 12:52:58.411647186 +0200
@@ -87,6 +87,8 @@
*h = draw->height;
}
+void xvnc_sync_dri3_textures(void);
+
static void
DamageExtNotify(DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes)
{
@@ -97,6 +99,8 @@
damageGetGeometry(pDrawable, &x, &y, &w, &h);
+ xvnc_sync_dri3_textures();
+
UpdateCurrentTimeIf();
ev = (xDamageNotifyEvent) {
.type = DamageEventBase + XDamageNotify,