Compare commits
78 Commits
KASM-1810_
...
innovation
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
920e180c37 | ||
|
|
ba902f8194 | ||
|
|
1f5125fb24 | ||
|
|
dc60c73a81 | ||
|
|
1c54f4f921 | ||
|
|
60de5a9791 | ||
|
|
480add4fe2 | ||
|
|
924329900d | ||
|
|
4e134b578c | ||
|
|
61f08d4986 | ||
|
|
c32521ba64 | ||
|
|
8542a5fb31 | ||
|
|
4cc81ddb3d | ||
|
|
32d6b4804a | ||
|
|
ac7605f316 | ||
|
|
87e39f896c | ||
|
|
f22d8347ed | ||
|
|
bf2bf679b6 | ||
|
|
330eb47142 | ||
|
|
661e9ef329 | ||
|
|
786670354f | ||
|
|
a6842bb46a | ||
|
|
2959156a25 | ||
|
|
774a61ace7 | ||
|
|
d829572a9c | ||
|
|
891bef0877 | ||
|
|
9f6c160d1e | ||
|
|
d581eb798d | ||
|
|
bdf0a4dde9 | ||
|
|
fc894a7096 | ||
|
|
7078884c12 | ||
|
|
d70edd9eb7 | ||
|
|
1e265277f8 | ||
|
|
b73d3fc786 | ||
|
|
b2e878e79e | ||
|
|
6e84e10317 | ||
|
|
d050236248 | ||
|
|
92c449d87b | ||
|
|
73ed994b21 | ||
|
|
74a4b5fd9f | ||
|
|
7506e0881f | ||
|
|
ce78879132 | ||
|
|
08f5000b9f | ||
|
|
3f89e5c117 | ||
|
|
d6d13b59cb | ||
|
|
3ee95e3150 | ||
|
|
0c020f2e79 | ||
|
|
8a5915aeab | ||
|
|
8a4b4548f3 | ||
|
|
c89a966ed6 | ||
|
|
78ee565ab3 | ||
|
|
94791bc9fa | ||
|
|
eda0d899cd | ||
|
|
a734a613c8 | ||
|
|
e6b4f40ed7 | ||
|
|
6a9dfdc593 | ||
|
|
cee7ae86cf | ||
|
|
8bf5ae9ef7 | ||
|
|
49890cf8da | ||
|
|
974a06bb8c | ||
|
|
c3551f807c | ||
|
|
3c6226f03d | ||
|
|
e3afc937e5 | ||
|
|
fa22ed925f | ||
|
|
42d7ff015d | ||
|
|
13331295ac | ||
|
|
99680f23ff | ||
|
|
93e89bd8be | ||
|
|
c0401101ab | ||
|
|
4f7a42f41e | ||
|
|
e6cc132874 | ||
|
|
8422168154 | ||
|
|
03729ca66e | ||
|
|
ca7949537a | ||
|
|
6dd0dd58d4 | ||
|
|
2959b47a86 | ||
|
|
49174b1586 | ||
|
|
bb364badd3 |
@@ -6,6 +6,27 @@ is_kasmvnc() {
|
||||
echo "$package" | grep -q 'kasmvncserver_'
|
||||
}
|
||||
|
||||
detect_deb_package_arch() {
|
||||
local deb_package="$1"
|
||||
echo "$deb_package" | sed -e 's/.\+_\([^.]\+\)\.\(d\?\)deb/\1/'
|
||||
}
|
||||
|
||||
find_deb_package() {
|
||||
local dbgsym_package="$1"
|
||||
|
||||
echo "$dbgsym_package" | sed -e 's/-dbgsym//; s/ddeb/deb/'
|
||||
}
|
||||
|
||||
fetch_xvnc_md5sum() {
|
||||
local deb_package="$1"
|
||||
deb_package=$(realpath "$deb_package")
|
||||
|
||||
local tmpdir=$(mktemp -d)
|
||||
cd "$tmpdir"
|
||||
dpkg-deb -e "$deb_package"
|
||||
cat DEBIAN/md5sums | grep bin/Xkasmvnc | cut -d' ' -f 1
|
||||
}
|
||||
|
||||
function prepare_upload_filename() {
|
||||
local package="$1";
|
||||
|
||||
@@ -34,19 +55,18 @@ function prepare_upload_filename() {
|
||||
function upload_to_s3() {
|
||||
local package="$1";
|
||||
local upload_filename="$2";
|
||||
local s3_bucket="$3";
|
||||
|
||||
# Transfer to S3
|
||||
python3 amazon-s3-bitbucket-pipelines-python/s3_upload.py "${S3_BUCKET}" "$package" "${S3_BUILD_DIRECTORY}/${upload_filename}";
|
||||
python3 amazon-s3-bitbucket-pipelines-python/s3_upload.py "${s3_bucket}" "$package" "${upload_filename}";
|
||||
# Use the Gitlab API to tell Gitlab where the artifact was stored
|
||||
export S3_URL="https://${S3_BUCKET}.s3.amazonaws.com/${S3_BUILD_DIRECTORY}/${upload_filename}";
|
||||
export BUILD_STATUS="{\"key\":\"doc\", \"state\":\"SUCCESSFUL\", \"name\":\"${upload_filename}\", \"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=build-url&target_url=${S3_URL}";
|
||||
export S3_URL="https://${s3_bucket}.s3.amazonaws.com/${upload_filename}";
|
||||
};
|
||||
|
||||
function prepare_to_run_scripts_and_s3_uploads() {
|
||||
export DEBIAN_FRONTEND=noninteractive;
|
||||
apt-get update;
|
||||
apt-get install -y ruby2.7 git;
|
||||
apt-get install -y ruby2.7 git wget;
|
||||
apt-get install -y python3 python3-pip python3-boto3 curl pkg-config libxmlsec1-dev;
|
||||
git clone https://bitbucket.org/awslabs/amazon-s3-bitbucket-pipelines-python.git;
|
||||
};
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,3 +21,4 @@ debian/files
|
||||
debian/kasmvncserver.substvars
|
||||
debian/kasmvncserver/
|
||||
.pc
|
||||
.vscode/
|
||||
|
||||
179
.gitlab-ci.yml
179
.gitlab-ci.yml
@@ -3,9 +3,14 @@ services:
|
||||
- docker:dind
|
||||
|
||||
variables:
|
||||
KASMVNC_COMMIT_ID: $CI_COMMIT_SHA
|
||||
GITLAB_SHARED_DIND_DIR: /builds/$CI_PROJECT_PATH/shared
|
||||
GIT_SUBMODULE_STRATEGY: normal
|
||||
GIT_FETCH_EXTRA_FLAGS: --tags
|
||||
# E.g. BUILD_JOBS: build_debian_buster,build_ubuntu_bionic. This will include
|
||||
# arm builds, because build_debian_buster_arm matches build_debian_buster.
|
||||
# "BUILD_JOBS: none" won't build any build jobs, nor www.
|
||||
BUILD_JOBS: all
|
||||
|
||||
stages:
|
||||
- www
|
||||
@@ -37,6 +42,9 @@ build_www:
|
||||
- mkdir -p output/www
|
||||
- cd builder
|
||||
- tar -zcvf ../output/www/kasm_www.tar.gz www
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS !~ /^none$/
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -51,6 +59,9 @@ build_ubuntu_bionic:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package ubuntu bionic
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -67,6 +78,9 @@ build_ubuntu_bionic_arm:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package ubuntu bionic
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -81,6 +95,9 @@ build_ubuntu_bionic_libjpeg_turbo:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package ubuntu bionic +libjpeg-turbo_latest
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -97,7 +114,7 @@ build_ubuntu_focal:
|
||||
- bash builder/build-package ubuntu focal;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [Cc][Ii]\]/
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -116,7 +133,43 @@ build_ubuntu_focal_arm:
|
||||
- bash builder/build-package ubuntu focal;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [Cc][Ii]\]/
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_ubuntu_jammy:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package ubuntu jammy;
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_ubuntu_jammy_arm:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
tags:
|
||||
- arm
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package ubuntu jammy;
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -133,7 +186,7 @@ build_debian_buster:
|
||||
- bash builder/build-package debian buster;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/ || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -152,7 +205,7 @@ build_debian_buster_arm:
|
||||
- bash builder/build-package debian buster;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/ || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -169,7 +222,7 @@ build_debian_bullseye:
|
||||
- bash builder/build-package debian bullseye;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/ || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -188,7 +241,7 @@ build_debian_bullseye_arm:
|
||||
- bash builder/build-package debian bullseye;
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/
|
||||
- $CI_COMMIT_MESSAGE =~ /\[full [cC][Ii]\]/ || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -203,6 +256,28 @@ build_kali_rolling:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package kali kali-rolling;
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_kali_rolling_arm:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
tags:
|
||||
- arm
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package kali kali-rolling;
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -217,6 +292,81 @@ build_centos7:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package centos core
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_oracle_8:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package oracle 8;
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_oracle_8_arm:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
tags:
|
||||
- arm
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package oracle 8;
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_opensuse_15:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package opensuse 15;
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
|
||||
build_opensuse_15_arm:
|
||||
stage: build
|
||||
allow_failure: true
|
||||
tags:
|
||||
- arm
|
||||
before_script:
|
||||
- *prepare_build
|
||||
- *prepare_www
|
||||
after_script:
|
||||
- *prepare_artfacts
|
||||
script:
|
||||
- bash builder/build-package opensuse 15;
|
||||
only:
|
||||
variables:
|
||||
- $BUILD_JOBS == 'all' || $BUILD_JOBS =~ $CI_JOB_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- output/
|
||||
@@ -227,14 +377,25 @@ upload:
|
||||
before_script:
|
||||
- . .ci/upload.sh
|
||||
script:
|
||||
- export S3_BUILD_DIRECTORY="kasmvnc/${CI_COMMIT_SHA}"
|
||||
- prepare_to_run_scripts_and_s3_uploads
|
||||
- S3_CRASHPAD_BUILD_DIRECTORY="kasmvnc/crashpad/${CI_COMMIT_SHA}"
|
||||
- for dbgsym_package in `find output/ -type f -name '*dbgsym*deb'`; do
|
||||
deb_package=$(find_deb_package "$dbgsym_package");
|
||||
xvnc_md5sum=$(fetch_xvnc_md5sum "$deb_package");
|
||||
upload_filename="${S3_CRASHPAD_BUILD_DIRECTORY}/${xvnc_md5sum}/kasmvncserver-dbgsym.deb";
|
||||
echo;
|
||||
echo "File to upload $upload_filename";
|
||||
upload_to_s3 "$dbgsym_package" "$upload_filename" "$S3_BUCKET";
|
||||
rm "$dbgsym_package";
|
||||
done
|
||||
- export S3_BUILD_DIRECTORY="kasmvnc/${CI_COMMIT_SHA}"
|
||||
- export RELEASE_VERSION=$(.ci/next_release_version "$CI_COMMIT_REF_NAME")
|
||||
- for package in `find output/ -type f -name '*.deb' -or -name '*.rpm'`; do
|
||||
prepare_upload_filename "$package";
|
||||
upload_filename="${S3_BUILD_DIRECTORY}/$upload_filename";
|
||||
echo;
|
||||
echo "File to upload $upload_filename";
|
||||
upload_to_s3 "$package" "$upload_filename";
|
||||
UPLOAD_NAME=$(echo $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)##');
|
||||
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)##');
|
||||
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}";
|
||||
done
|
||||
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,4 +1,4 @@
|
||||
[submodule "kasmweb"]
|
||||
path = kasmweb
|
||||
url = https://github.com/kasmtech/noVNC.git
|
||||
branch = master
|
||||
branch = innovation/session_recording
|
||||
|
||||
108
DEBUGGING.md
Normal file
108
DEBUGGING.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# Debugging
|
||||
In the case where KasmVNC crashes and a backtrace is produced. Developers need a way to make the backtrace useful for debugging. This document covers where the backtrace is logged and how to use a debug symbol package and gdb to gain more information from the backtrace, such as filename, function name, and line number.
|
||||
|
||||
## Test Symbolization
|
||||
If you want to induce a crash to test that you can symbolize a backtrace you can start KasmVNC and then issue the following command.
|
||||
|
||||
killall -SEGV Xvnc
|
||||
|
||||
This will cause KasmVNC to terminate with a backtrace similar to the following. You will find the backtrace in the log file at $HOME/.vnc/$HOSTNAME:$DISPLAY.log where HOME is your user's profile path, HOSTNAME is the hostname of the system, and DISPLAY is the assigned display number for the session.
|
||||
|
||||
(EE)
|
||||
(EE) Backtrace:
|
||||
(EE) 0: /usr/bin/Xvnc (xorg_backtrace+0x4d) [0x5e48dd]
|
||||
(EE) 1: /usr/bin/Xvnc (0x400000+0x1e8259) [0x5e8259]
|
||||
(EE) 2: /lib/x86_64-linux-gnu/libpthread.so.0 (0x7f5a57ef6000+0x12980) [0x7f5a57f08980]
|
||||
(EE) 3: /lib/x86_64-linux-gnu/libc.so.6 (epoll_wait+0x57) [0x7f5a552eca47]
|
||||
(EE) 4: /usr/bin/Xvnc (ospoll_wait+0x37) [0x5e8d07]
|
||||
(EE) 5: /usr/bin/Xvnc (WaitForSomething+0x1c3) [0x5e2813]
|
||||
(EE) 6: /usr/bin/Xvnc (Dispatch+0xa7) [0x597007]
|
||||
(EE) 7: /usr/bin/Xvnc (dix_main+0x36e) [0x59b1fe]
|
||||
(EE) 8: /lib/x86_64-linux-gnu/libc.so.6 (__libc_start_main+0xe7) [0x7f5a551ecbf7]
|
||||
(EE) 9: /usr/bin/Xvnc (_start+0x2a) [0x46048a]
|
||||
(EE)
|
||||
(EE) Received signal 11 sent by process 17182, uid 0
|
||||
(EE)
|
||||
Fatal server error:
|
||||
(EE) Caught signal 11 (Segmentation fault). Server aborting
|
||||
(EE)
|
||||
|
||||
## Debug Symbol Package
|
||||
In order to make use of this backtrace, you will need to symbolize the backtrace. Each build of KasmVNC produced by our pipelines comes with a corresponding debug symbol package that can be downloaded. You need two pieces of information to get the package, the git commit ID of KasmVNC and the MD5 sum of Xkasmvnc binary on your system.
|
||||
|
||||
The git commit ID can be found using Xvnc -version:
|
||||
|
||||
ubuntu@matt-dev-vm-1:~$ Xvnc -version
|
||||
Xvnc KasmVNC 0.9.94002f39917dca0ad82ac0c29a75c723b538b32b - built Feb 17 2022 15:21:01
|
||||
Copyright (C) 1999-2018 KasmVNC Team and many others (see README.me)
|
||||
See http://kasmweb.com for information on KasmVNC.
|
||||
Underlying X server release 12010000, The X.Org Foundation
|
||||
|
||||
The MD5 sum can be obtained using the md5sum command:
|
||||
|
||||
md5sum /usr/bin/Xkasmvnc
|
||||
57ee7028239c5a737c0aeee4a34138c3 /usr/bin/Xkasmvnc
|
||||
|
||||
With these two pieces of information, you can get the debug symbol package at https://kasmweb-build-artifacts.s3.amazonaws.com/kasmvnc/crashpad/[COMMITID]/[MD5SUM]/kasmvncserver-dbgsym.deb, in the above example it would be.
|
||||
|
||||
[https://kasmweb-build-artifacts.s3.amazonaws.com/kasmvnc/crashpad/94002f39917dca0ad82ac0c29a75c723b538b32b/57ee7028239c5a737c0aeee4a34138c3/kasmvncserver-dbgsym.deb](https://kasmweb-build-artifacts.s3.amazonaws.com/kasmvnc/crashpad/94002f39917dca0ad82ac0c29a75c723b538b32b/57ee7028239c5a737c0aeee4a34138c3/kasmvncserver-dbgsym.deb "https://kasmweb-build-artifacts.s3.amazonaws.com/kasmvnc/crashpad/94002f39917dca0ad82ac0c29a75c723b538b32b/57ee7028239c5a737c0aeee4a34138c3/kasmvncserver-dbgsym.deb")
|
||||
|
||||
Use wget or curl to download the debug symbol package and then install it.
|
||||
|
||||
wget https://kasmweb-build-artifacts.s3.amazonaws.com/kasmvnc/crashpad/94002f39917dca0ad82ac0c29a75c723b538b32b/57ee7028239c5a737c0aeee4a34138c3/kasmvncserver-dbgsym.deb
|
||||
sudo dpkg -i kasmvncserver-dbgsym.deb
|
||||
|
||||
## Symbolize a Backtrace
|
||||
With the KasmVNC binary and debug symbol package installed on the system, you can use gdb or addr2line to get more information, such as the filename, function name, and line number that the backtrace line is referring to.
|
||||
|
||||
Here is a single line from a backtrace. The following example shows how to retrieve additional information that can help with debugging the crash.
|
||||
(EE) 8: /usr/bin/Xvnc (0x400000+0x13e674) [**0x53e674**]
|
||||
|
||||
echo info line ***0x53eaaa** | gdb -q /usr/bin/Xkasmvnc
|
||||
(gdb) Line 223 of "/src/common/network/webudp/Wu.cpp" starts at address 0x53e674 <WuClientSendPendingDTLS(WuClient*, Wu const*, Wu const*)+68>
|
||||
|
||||
The following script will search the provide file for a backtrace and symbolize the entire backtrace.
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
FILENAME=$1
|
||||
grep "(EE)" $FILENAME | while read -r line ; do
|
||||
BACKTRACE=$(echo $line | grep -Po '\[[0-9a-f]x[a-f0-9]{1,}' | sed -r 's#\[##')
|
||||
echo $line
|
||||
if ! [ -z $BACKTRACE ] ; then
|
||||
SYMBOLIZED=$(echo "info line *${BACKTRACE}" | gdb /usr/bin/Xkasmvnc | grep "(gdb)" | grep -vP "\(gdb\)\s*quit$")
|
||||
echo " ${SYMBOLIZED}"
|
||||
fi
|
||||
done
|
||||
|
||||
Using this script on the above example backtrace produces the following output.
|
||||
|
||||
ubuntu@hostname-1:~$ bash symbolize.sh ~/.vnc/hostname-1\:10.log
|
||||
(EE)
|
||||
(EE) Backtrace:
|
||||
(EE) 0: /usr/bin/Xvnc (xorg_backtrace+0x4d) [0x5e48dd]
|
||||
(gdb) Line 130 of "backtrace.c" starts at address 0x5e48dd <xorg_backtrace+77> and ends at 0x5e4900 <xorg_backtrace+112>.
|
||||
(EE) 1: /usr/bin/Xvnc (0x400000+0x1e8259) [0x5e8259]
|
||||
(gdb) Line 138 of "osinit.c" starts at address 0x5e8259 <OsSigHandler+41> and ends at 0x5e8275 <OsSigHandler+69>.
|
||||
(EE) 2: /lib/x86_64-linux-gnu/libpthread.so.0 (0x7f5a57ef6000+0x12980) [0x7f5a57f08980]
|
||||
(gdb) No line number information available for address 0x7f5a57f08980
|
||||
(EE) 3: /lib/x86_64-linux-gnu/libc.so.6 (epoll_wait+0x57) [0x7f5a552eca47]
|
||||
(gdb) No line number information available for address 0x7f5a552eca47
|
||||
(EE) 4: /usr/bin/Xvnc (ospoll_wait+0x37) [0x5e8d07]
|
||||
(gdb) Line 643 of "ospoll.c" starts at address 0x5e8d07 <ospoll_wait+55> and ends at 0x5e8d09 <ospoll_wait+57>.
|
||||
(EE) 5: /usr/bin/Xvnc (WaitForSomething+0x1c3) [0x5e2813]
|
||||
(gdb) Line 210 of "WaitFor.c" starts at address 0x5e2813 <WaitForSomething+451> and ends at 0x5e2819 <WaitForSomething+457>.
|
||||
(EE) 6: /usr/bin/Xvnc (Dispatch+0xa7) [0x597007]
|
||||
(gdb) Line 421 of "dispatch.c" starts at address 0x596ffb <Dispatch+155> and ends at 0x59700b <Dispatch+171>.
|
||||
(EE) 7: /usr/bin/Xvnc (dix_main+0x36e) [0x59b1fe]
|
||||
(gdb) Line 278 of "main.c" starts at address 0x59b1fe <dix_main+878> and ends at 0x59b203 <dix_main+883>.
|
||||
(EE) 8: /lib/x86_64-linux-gnu/libc.so.6 (__libc_start_main+0xe7) [0x7f5a551ecbf7]
|
||||
(gdb) No line number information available for address 0x7f5a551ecbf7
|
||||
(EE) 9: /usr/bin/Xvnc (_start+0x2a) [0x46048a]
|
||||
(gdb) No line number information available for address 0x46048a <_start+42>
|
||||
(EE)
|
||||
(EE) Received signal 11 sent by process 17182, uid 0
|
||||
(EE)
|
||||
(EE) Caught signal 11 (Segmentation fault). Server aborting
|
||||
(EE)
|
||||
|
||||
28
README.md
28
README.md
@@ -8,6 +8,10 @@
|
||||
- Security - The RFB specification (VNC) limits the password field to 8 characters, so while the client may take a longer password, only the first 8 characters are sent. KasmVNC defaults to HTTPS with HTTP Basic Auth and disables the legacy VNC authentication method which is not sufficiently secure for internet accessible systems.
|
||||
- Simplicity - KasmVNC aims at being simple to deploy and configure.
|
||||
|
||||
# Releases
|
||||
|
||||
Since this is a fast evolving project, the documents on the tip of master are chaning rapidly and will not match releases. Be sure to use the README and other documentation from the release branch that matches the version of KasmVNC you are using. Do not use the README from the master branch, unless you are compiling KasmVNC yourself from the tip of master. All releases starting at 0.9.3 have a branch named in the format 'release/0.9.3', for example.
|
||||
|
||||
# New Features!
|
||||
|
||||
- Webp image compression for better bandwidth usage
|
||||
@@ -16,6 +20,7 @@
|
||||
- [Full screen video detection](https://github.com/kasmtech/KasmVNC/wiki/Video-Rendering-Options#video-mode), goes into configurable video mode for better full screen videoo playback performance.
|
||||
- [Dynamic jpeg/webp image coompression](https://github.com/kasmtech/KasmVNC/wiki/Video-Rendering-Options#dynamic-image-quality) quality settings based on screen change rates
|
||||
- Seemless clipboard support (on Chromium based browsers)
|
||||
- Binary clipboard support for text, images, and formatted text (on Chromium based browsers)
|
||||
- Allow client to set/change most configuration settings
|
||||
- [Data Loss Prevention features](https://github.com/kasmtech/KasmVNC/wiki/Data-Loss-Prevention)
|
||||
- Key stroke logging
|
||||
@@ -25,27 +30,31 @@
|
||||
- Keyboard input rate limit
|
||||
- Screen region selection
|
||||
- Deb packages for Debian, Ubuntu, and Kali Linux included in release.
|
||||
- RPM packages for CentOS, Fedora. RPM packages are currently not updatable and not released, though you can build and install them. See build documentation.
|
||||
- RPM packages for CentOS, Oracle, OpenSUSE, Fedora. RPM packages are currently not updatable and not released, though you can build and install them. See build documentation.
|
||||
- Web [API](https://github.com/kasmtech/KasmVNC/wiki/API) added for remotely controlling and getting information from KasmVNC
|
||||
- Multi-User with ability to pass control to other users.
|
||||
- Multi-User support with permissions that can be changed via the API
|
||||
- Web UI uses a webpack for faster load times.
|
||||
- Network and CPU bottleneck statistics
|
||||
|
||||
- Relative cursor support (game pointer mode)
|
||||
- Cursor lock
|
||||
- IME support for languages with extended characters
|
||||
- Better mobile support
|
||||
|
||||
Future Goals:
|
||||
|
||||
- Support uploads and downloads
|
||||
- Pre-build Packages for all major Linux distributions
|
||||
- UDP transport for faster frame rates
|
||||
- H264 encoding
|
||||
|
||||
### Installation
|
||||
|
||||
#### Debian-based
|
||||
|
||||
```sh
|
||||
wget https://github.com/kasmtech/KasmVNC/releases/download/v0.9.2-beta/kasmvncserver_ubuntu_bionic_0.9.2_amd64.deb
|
||||
# Please choose the package for your distro here (under Assets):
|
||||
# https://github.com/kasmtech/KasmVNC/releases
|
||||
wget <package_url>
|
||||
|
||||
sudo dpkg -i kasmvncserver_*.deb
|
||||
sudo apt-get -f install
|
||||
sudo apt-get install ./kasmvncserver_*.deb
|
||||
|
||||
# We provide an example script to run KasmVNC at #
|
||||
# /usr/share/doc/kasmvncserver/examples/kasmvncserver-easy-start. It runs a VNC
|
||||
@@ -57,6 +66,9 @@ sudo ln -s /usr/share/doc/kasmvncserver/examples/kasmvncserver-easy-start /usr/b
|
||||
sudo addgroup $USER ssl-cert
|
||||
# You will need to re-connect in order to pick up the group change
|
||||
|
||||
# Create a KasmVNC user able to use keyboard and mouse:
|
||||
vncpasswd -u $USER -w
|
||||
|
||||
# Create ~/.vnc directory and corresponding files.
|
||||
kasmvncserver-easy-start -d && kasmvncserver-easy-start -kill
|
||||
|
||||
|
||||
@@ -29,5 +29,6 @@ fi
|
||||
|
||||
dpkg-buildpackage -us -uc -b
|
||||
mkdir -p "$os_dir"
|
||||
cp ../*dbgsym*deb "$os_dir"
|
||||
cp ../*.deb "$os_dir"
|
||||
lintian ../*.deb || true
|
||||
|
||||
@@ -8,7 +8,7 @@ prepare_build_env() {
|
||||
}
|
||||
|
||||
copy_spec_and_tar_with_binaries() {
|
||||
cp /src/centos/kasmvncserver.spec ~/rpmbuild/SPECS/
|
||||
cp /tmp/kasmvncserver.spec ~/rpmbuild/SPECS/
|
||||
cp /src/builder/build/kasmvnc.${os}_${os_codename}.tar.gz \
|
||||
~/rpmbuild/SOURCES/
|
||||
}
|
||||
@@ -20,8 +20,13 @@ copy_rpm_to_build_dir() {
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
os=$(lsb_release -is | tr '[:upper:]' '[:lower:]')
|
||||
os_codename=$(lsb_release -cs | tr '[:upper:]' '[:lower:]')
|
||||
if [ -z ${KASMVNC_BUILD_OS_CODENAME+x} ]; then
|
||||
os=$(lsb_release -is | tr '[:upper:]' '[:lower:]')
|
||||
os_codename=$(lsb_release -cs | tr '[:upper:]' '[:lower:]')
|
||||
else
|
||||
os=${KASMVNC_BUILD_OS}
|
||||
os_codename=${KASMVNC_BUILD_OS_CODENAME}
|
||||
fi
|
||||
os_dir="build/${os}_${os_codename}"
|
||||
|
||||
prepare_build_env
|
||||
|
||||
@@ -31,6 +31,7 @@ docker build -t "$builder_image" \
|
||||
-f builder/dockerfile.${os}_${os_codename}${build_tag}.build .
|
||||
mkdir -p builder/build
|
||||
docker run -v $shared_with_docker_dir:/build -e BUILD_TAG="$build_tag" \
|
||||
-e KASMVNC_COMMIT_ID="$KASMVNC_COMMIT_ID" \
|
||||
--rm "$builder_image"
|
||||
|
||||
L_GID=$(id -g)
|
||||
|
||||
@@ -7,6 +7,12 @@ detect_quilt() {
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_crashpad_can_fetch_line_number_by_address() {
|
||||
if [ ! -f /etc/centos-release ]; then
|
||||
export LDFLAGS="$LDFLAGS -no-pie"
|
||||
fi
|
||||
}
|
||||
|
||||
# For build-dep to work, the apt sources need to have the source server
|
||||
#sudo apt-get build-dep xorg-server
|
||||
|
||||
@@ -30,7 +36,8 @@ sed -i -e '/find_package(FLTK/s@^@#@' \
|
||||
-e '/add_subdirectory(tests/s@^@#@' \
|
||||
CMakeLists.txt
|
||||
|
||||
cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo . -DBUILD_VIEWER:BOOL=OFF
|
||||
cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo . -DBUILD_VIEWER:BOOL=OFF \
|
||||
-DENABLE_GNUTLS:BOOL=OFF
|
||||
make -j5
|
||||
|
||||
tar -C unix/xserver -xf /tmp/xorg-server-${XORG_VER}.tar.bz2 --strip-components=1
|
||||
@@ -38,7 +45,7 @@ tar -C unix/xserver -xf /tmp/xorg-server-${XORG_VER}.tar.bz2 --strip-components=
|
||||
cd unix/xserver
|
||||
patch -Np1 -i ../xserver${XORG_PATCH}.patch
|
||||
case "$XORG_VER" in
|
||||
1.20.*)
|
||||
1.20.*)
|
||||
if [ -f ../xserver120.7.patch ]; then
|
||||
patch -Np1 -i ../xserver120.7.patch
|
||||
fi ;;
|
||||
@@ -49,12 +56,18 @@ autoreconf -i
|
||||
# The distro paths start after prefix and end with the font path,
|
||||
# everything after that is based on BUILDING.txt to remove unneeded
|
||||
# components.
|
||||
ensure_crashpad_can_fetch_line_number_by_address
|
||||
# remove gl check for opensuse
|
||||
if [ "${KASMVNC_BUILD_OS}" == "opensuse" ]; then
|
||||
sed -i 's/LIBGL="gl >= 7.1.0"/LIBGL="gl >= 1.1"/g' configure
|
||||
fi
|
||||
./configure --prefix=/opt/kasmweb \
|
||||
--with-xkb-path=/usr/share/X11/xkb \
|
||||
--with-xkb-output=/var/lib/xkb \
|
||||
--with-xkb-bin-directory=/usr/bin \
|
||||
--with-default-font-path="/usr/share/fonts/X11/misc,/usr/share/fonts/X11/cyrillic,/usr/share/fonts/X11/100dpi/:unscaled,/usr/share/fonts/X11/75dpi/:unscaled,/usr/share/fonts/X11/Type1,/usr/share/fonts/X11/100dpi,/usr/share/fonts/X11/75dpi,built-ins" \
|
||||
--with-pic --without-dtrace --disable-dri \
|
||||
--with-sha1=libcrypto \
|
||||
--without-dtrace --disable-dri \
|
||||
--disable-static \
|
||||
--disable-xinerama --disable-xvfb --disable-xnest --disable-xorg \
|
||||
--disable-dmx --disable-xwin --disable-xephyr --disable-kdrive \
|
||||
@@ -85,7 +98,9 @@ cd /src
|
||||
detect_quilt
|
||||
if [ -n "$QUILT_PRESENT" ]; then
|
||||
quilt push -a
|
||||
echo 'Patches applied!'
|
||||
fi
|
||||
|
||||
make servertarball
|
||||
|
||||
cp kasmvnc*.tar.gz /build/kasmvnc.${KASMVNC_BUILD_OS}_${KASMVNC_BUILD_OS_CODENAME}.tar.gz
|
||||
|
||||
@@ -15,4 +15,3 @@ cd /build
|
||||
rm *.md
|
||||
rm AUTHORS
|
||||
rm vnc.html
|
||||
rm vnc_lite.html
|
||||
|
||||
@@ -7,24 +7,12 @@ update_version_to_meet_packaging_standards() {
|
||||
sed -e 's/\([0-9]\)-\([a-zA-Z]\)/\1~\2/')
|
||||
}
|
||||
|
||||
add_debian_revision_to_new_version() {
|
||||
echo "$new_version-1"
|
||||
}
|
||||
|
||||
bump_rpm() {
|
||||
sed -i "s/^Version:.\+/Version: $new_version/" centos/kasmvncserver.spec
|
||||
builder/bump-package-version-rpm "$new_version"
|
||||
}
|
||||
|
||||
bump_deb() {
|
||||
local image="debbump_package_version:dev"
|
||||
local L_UID=$(id -u)
|
||||
local L_GID=$(id -g)
|
||||
local debian_version=$(add_debian_revision_to_new_version)
|
||||
|
||||
docker build -t "$image" -f builder/dockerfile.bump-package-version .
|
||||
docker run --rm -v "$PWD":/src --user "$L_UID:$L_GID" \
|
||||
"$image" /bin/bash -c \
|
||||
"cd /src && builder/bump-package-version-inside-docker-deb $debian_version"
|
||||
builder/bump-package-version-deb "$new_version"
|
||||
}
|
||||
|
||||
new_version="$1"
|
||||
|
||||
23
builder/bump-package-version-deb
Executable file
23
builder/bump-package-version-deb
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
new_version="$1"
|
||||
|
||||
add_debian_revision_to_new_version() {
|
||||
echo "$new_version-1"
|
||||
}
|
||||
|
||||
bump_deb() {
|
||||
local image="debbump_package_version:dev"
|
||||
local L_UID=$(id -u)
|
||||
local L_GID=$(id -g)
|
||||
local debian_version=$(add_debian_revision_to_new_version)
|
||||
|
||||
docker build -t "$image" -f builder/dockerfile.bump-package-version .
|
||||
docker run --rm -v "$PWD":/src --user "$L_UID:$L_GID" \
|
||||
"$image" /bin/bash -c \
|
||||
"cd /src && builder/bump-package-version-inside-docker-deb $debian_version"
|
||||
}
|
||||
|
||||
bump_deb
|
||||
32
builder/bump-package-version-rpm
Executable file
32
builder/bump-package-version-rpm
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
new_version="$1"
|
||||
specs="centos/kasmvncserver.spec
|
||||
oracle/kasmvncserver.spec
|
||||
opensuse/kasmvncserver.spec"
|
||||
|
||||
bump_version() {
|
||||
sed -i "s/^Version:.\+/Version: $new_version/" "$1"
|
||||
}
|
||||
|
||||
detect_release_version() {
|
||||
release_version=$(sed -ne 's/^Release:\s\+//p' "$1" | sed -e 's/%.\+$//')
|
||||
}
|
||||
|
||||
bump_changelog() {
|
||||
detect_release_version "$1"
|
||||
|
||||
local date=$(date +'%a %b %d %Y')
|
||||
local changelog_version="$new_version-$release_version"
|
||||
local new_changelog_entry="* $date KasmTech <info@kasmweb.com> - $changelog_version\n- Upstream release"
|
||||
|
||||
sed -i -e "s/%changelog/%changelog\n$new_changelog_entry/" "$1"
|
||||
}
|
||||
|
||||
IFS=$'\n'
|
||||
for spec_file in $specs; do
|
||||
bump_version $spec_file
|
||||
bump_changelog $spec_file
|
||||
done
|
||||
@@ -3,7 +3,7 @@ FROM centos:centos7
|
||||
ENV KASMVNC_BUILD_OS centos
|
||||
ENV KASMVNC_BUILD_OS_CODENAME core
|
||||
|
||||
RUN yum update -y ca-certificates
|
||||
RUN yum install -y ca-certificates
|
||||
RUN yum install -y build-dep xorg-server libxfont-dev sudo
|
||||
RUN yum install -y gcc cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver
|
||||
RUN yum install -y libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev openssl-devel
|
||||
@@ -11,8 +11,10 @@ RUN yum install -y make
|
||||
RUN yum group install -y "Development Tools"
|
||||
RUN yum install -y xorg-x11-server-devel zlib-devel libjpeg-turbo-devel
|
||||
RUN yum install -y libxkbfile-devel libXfont2-devel xorg-x11-font-utils \
|
||||
xorg-x11-xtrans-devel xorg-x11-xkb-utils-devel
|
||||
xorg-x11-xtrans-devel xorg-x11-xkb-utils-devel libXrandr-devel pam-devel \
|
||||
gnutls-devel libX11-devel libXtst-devel libXcursor-devel
|
||||
RUN yum install -y mesa-dri-drivers
|
||||
RUN yum install -y ca-certificates
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
|
||||
@@ -13,7 +13,7 @@ RUN apt-get update && \
|
||||
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 libjpeg-dev libgnutls28-dev vim wget tightvncserver
|
||||
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev
|
||||
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
|
||||
@@ -13,7 +13,7 @@ RUN apt-get update && \
|
||||
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 libjpeg-dev libgnutls28-dev vim wget tightvncserver
|
||||
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev
|
||||
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
|
||||
@@ -18,7 +18,8 @@ RUN dnf install -y make
|
||||
RUN dnf group install -y "Development Tools"
|
||||
RUN dnf install -y xorg-x11-server-devel zlib-devel libjpeg-turbo-devel
|
||||
RUN dnf install -y libxkbfile-devel libXfont2-devel xorg-x11-font-utils \
|
||||
xorg-x11-xtrans-devel xorg-x11-xkb-utils-devel
|
||||
xorg-x11-xtrans-devel xorg-x11-xkb-utils-devel libXrandr-devel libXtst-devel \
|
||||
libXcursor-devel
|
||||
RUN dnf install -y mesa-dri-drivers
|
||||
RUN dnf install -y bzip2 redhat-lsb-core
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ RUN apt-get update && \
|
||||
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 libjpeg-dev libgnutls28-dev vim wget tightvncserver
|
||||
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev
|
||||
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
|
||||
37
builder/dockerfile.opensuse_15.barebones.rpm.test
Normal file
37
builder/dockerfile.opensuse_15.barebones.rpm.test
Normal file
@@ -0,0 +1,37 @@
|
||||
FROM opensuse/leap:15.3
|
||||
|
||||
# base tools
|
||||
RUN zypper -n install -y \
|
||||
less \
|
||||
vim \
|
||||
xterm
|
||||
|
||||
# deps and rpm install
|
||||
RUN zypper -n install -y \
|
||||
libglvnd \
|
||||
libgomp1 \
|
||||
libjpeg8 \
|
||||
libpixman-1-0 \
|
||||
libXdmcp6 \
|
||||
libXfont2-2 \
|
||||
libxkbcommon-x11-0 \
|
||||
openssl \
|
||||
perl \
|
||||
x11-tools \
|
||||
xauth \
|
||||
xkbcomp \
|
||||
xkeyboard-config && \
|
||||
mkdir -p /etc/pki/tls/private
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp
|
||||
RUN zypper install -y --allow-unsigned-rpm /tmp/*.rpm
|
||||
|
||||
RUN useradd -m foo
|
||||
|
||||
USER foo:kasmvnc-cert
|
||||
|
||||
RUN mkdir ~/.vnc && echo '/usr/bin/xterm &' >> ~/.vnc/xstartup && \
|
||||
chmod +x ~/.vnc/xstartup
|
||||
|
||||
ENTRYPOINT bash -c "echo -e \"$VNC_PW\n$VNC_PW\n\" | kasmvncpasswd -w -u \"$VNC_USER\" && vncserver :1 -interface 0.0.0.0 && vncserver -kill :1 && vncserver :1 -depth 24 -geometry 1280x1050 -websocketPort 8443 -cert /etc/pki/tls/private/kasmvnc.pem -sslOnly -FrameRate=24 -interface 0.0.0.0 -httpd /usr/share/kasmvnc/www && tail -f $HOME/.vnc/*.log "
|
||||
59
builder/dockerfile.opensuse_15.build
Normal file
59
builder/dockerfile.opensuse_15.build
Normal file
@@ -0,0 +1,59 @@
|
||||
FROM opensuse/leap:15.3
|
||||
|
||||
ENV KASMVNC_BUILD_OS opensuse
|
||||
ENV KASMVNC_BUILD_OS_CODENAME 15
|
||||
ENV XORG_VER 1.20.3
|
||||
|
||||
# Install depends
|
||||
RUN zypper install -ny \
|
||||
bdftopcf \
|
||||
bigreqsproto-devel \
|
||||
cmake \
|
||||
ffmpeg-4-libavcodec-devel \
|
||||
fonttosfnt \
|
||||
font-util \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
giflib-devel \
|
||||
git \
|
||||
gzip \
|
||||
lbzip2 \
|
||||
libbz2-devel \
|
||||
libGLw-devel \
|
||||
libgnutls-devel \
|
||||
libjpeg8-devel \
|
||||
libopenssl-devel \
|
||||
libpng16-devel \
|
||||
libtiff-devel \
|
||||
libXfont2-devel \
|
||||
libxkbcommon-x11-devel \
|
||||
make \
|
||||
Mesa-dri \
|
||||
Mesa-libglapi-devel \
|
||||
mkfontdir \
|
||||
mkfontscale \
|
||||
patch \
|
||||
tigervnc \
|
||||
wget \
|
||||
xcmiscproto-devel \
|
||||
xorg-x11-devel \
|
||||
xorg-x11-server-sdk \
|
||||
xorg-x11-util-devel \
|
||||
zlib-devel
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
||||
RUN cd /tmp/libwebp-1.0.2 && \
|
||||
./configure --enable-static --disable-shared && \
|
||||
make && make install
|
||||
|
||||
RUN useradd -u 1000 docker && \
|
||||
groupadd -g 1000 docker && \
|
||||
usermod -a -G docker docker
|
||||
|
||||
COPY --chown=docker:docker . /src/
|
||||
|
||||
|
||||
USER docker
|
||||
ENTRYPOINT ["/src/builder/build.sh"]
|
||||
24
builder/dockerfile.opensuse_15.rpm.build
Normal file
24
builder/dockerfile.opensuse_15.rpm.build
Normal file
@@ -0,0 +1,24 @@
|
||||
FROM opensuse/leap:15.3
|
||||
|
||||
ENV KASMVNC_BUILD_OS opensuse
|
||||
ENV KASMVNC_BUILD_OS_CODENAME 15
|
||||
|
||||
RUN zypper -n install -y \
|
||||
gpg* \
|
||||
less \
|
||||
lsb-release \
|
||||
rng-tools \
|
||||
rpm-build \
|
||||
rpmdevtools \
|
||||
rpmlint \
|
||||
tree \
|
||||
vim
|
||||
|
||||
COPY opensuse/*.spec /tmp
|
||||
RUN zypper -n install $(grep BuildRequires /tmp/*.spec | cut -d' ' -f2 | xargs)
|
||||
|
||||
RUN useradd -u 1000 -m -d /home/docker docker && \
|
||||
groupadd -g 1000 docker && \
|
||||
usermod -a -G docker docker
|
||||
|
||||
USER docker
|
||||
20
builder/dockerfile.oracle_8.barebones.rpm.test
Normal file
20
builder/dockerfile.oracle_8.barebones.rpm.test
Normal file
@@ -0,0 +1,20 @@
|
||||
FROM oraclelinux:8
|
||||
|
||||
RUN dnf install -y \
|
||||
less \
|
||||
redhat-lsb-core \
|
||||
vim \
|
||||
xterm
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/*.rpm /tmp
|
||||
RUN dnf localinstall -y /tmp/*.rpm
|
||||
|
||||
RUN useradd -m foo
|
||||
|
||||
USER foo:kasmvnc-cert
|
||||
|
||||
RUN mkdir ~/.vnc && echo '/usr/bin/xterm &' >> ~/.vnc/xstartup && \
|
||||
chmod +x ~/.vnc/xstartup
|
||||
|
||||
ENTRYPOINT bash -c "echo -e \"$VNC_PW\n$VNC_PW\n\" | kasmvncpasswd -w -u \"$VNC_USER\" && vncserver :1 -interface 0.0.0.0 && vncserver -kill :1 && vncserver :1 -depth 24 -geometry 1280x1050 -websocketPort 8443 -cert /etc/pki/tls/private/kasmvnc.pem -sslOnly -FrameRate=24 -interface 0.0.0.0 -httpd /usr/share/kasmvnc/www && tail -f $HOME/.vnc/*.log "
|
||||
61
builder/dockerfile.oracle_8.build
Normal file
61
builder/dockerfile.oracle_8.build
Normal file
@@ -0,0 +1,61 @@
|
||||
FROM oraclelinux:8
|
||||
|
||||
ENV KASMVNC_BUILD_OS oracle
|
||||
ENV KASMVNC_BUILD_OS_CODENAME 8
|
||||
ENV XORG_VER 1.20.10
|
||||
|
||||
# Install from stock repos
|
||||
RUN dnf install -y \
|
||||
bzip2-devel \
|
||||
ca-certificates \
|
||||
cmake \
|
||||
dnf-plugins-core \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
git \
|
||||
gnutls-devel \
|
||||
libjpeg-turbo-devel \
|
||||
libpng-devel \
|
||||
libtiff-devel \
|
||||
make \
|
||||
mesa-dri-drivers \
|
||||
openssl-devel \
|
||||
openssl-devel \
|
||||
patch \
|
||||
tigervnc-server \
|
||||
wget \
|
||||
xorg-x11-font-utils \
|
||||
zlib-devel
|
||||
|
||||
# Enable additional repos (epel, powertools, and fusion)
|
||||
RUN dnf config-manager --set-enabled ol8_codeready_builder
|
||||
RUN dnf install -y oracle-epel-release-el8
|
||||
RUN dnf install -y --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm
|
||||
|
||||
# Install from new repos
|
||||
RUN dnf install -y \
|
||||
ffmpeg-devel \
|
||||
giflib-devel \
|
||||
lbzip2 \
|
||||
libXfont2-devel \
|
||||
libxkbfile-devel \
|
||||
xorg-x11-server-devel \
|
||||
xorg-x11-xkb-utils-devel \
|
||||
xorg-x11-xtrans-devel \
|
||||
libXrandr-devel \
|
||||
libXtst-devel \
|
||||
libXcursor-devel
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
||||
RUN cd /tmp/libwebp-1.0.2 && \
|
||||
./configure --enable-static --disable-shared && \
|
||||
make && make install
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd
|
||||
|
||||
COPY --chown=docker:docker . /src/
|
||||
|
||||
USER docker
|
||||
ENTRYPOINT ["/src/builder/build.sh"]
|
||||
21
builder/dockerfile.oracle_8.rpm.build
Normal file
21
builder/dockerfile.oracle_8.rpm.build
Normal file
@@ -0,0 +1,21 @@
|
||||
FROM oraclelinux:8
|
||||
|
||||
ENV KASMVNC_BUILD_OS oracle
|
||||
ENV KASMVNC_BUILD_OS_CODENAME 8
|
||||
|
||||
RUN dnf install -y \
|
||||
gpg* \
|
||||
less \
|
||||
redhat-lsb-core \
|
||||
rng-tools \
|
||||
rpm* \
|
||||
rpmlint \
|
||||
tree \
|
||||
vim
|
||||
|
||||
COPY oracle/*.spec /tmp
|
||||
RUN dnf builddep -y /tmp/*.spec
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd
|
||||
|
||||
USER docker
|
||||
@@ -11,7 +11,7 @@ RUN apt-get update && \
|
||||
|
||||
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
|
||||
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev
|
||||
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
|
||||
|
||||
RUN apt-get update && apt-get install -y cmake nasm gcc
|
||||
RUN git clone https://github.com/libjpeg-turbo/libjpeg-turbo.git
|
||||
|
||||
@@ -11,7 +11,7 @@ RUN apt-get update && \
|
||||
|
||||
RUN apt-get update && apt-get -y build-dep xorg-server libxfont-dev
|
||||
RUN apt-get update && apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver
|
||||
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev
|
||||
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
|
||||
@@ -12,8 +12,8 @@ RUN apt-get update && \
|
||||
|
||||
RUN apt-get update && 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 libjpeg-dev libgnutls28-dev vim wget tightvncserver
|
||||
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev
|
||||
RUN apt-get update && apt-get -y install cmake git libjpeg-dev vim wget
|
||||
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
|
||||
30
builder/dockerfile.ubuntu_jammy.build
Normal file
30
builder/dockerfile.ubuntu_jammy.build
Normal file
@@ -0,0 +1,30 @@
|
||||
FROM ubuntu:jammy
|
||||
|
||||
ENV KASMVNC_BUILD_OS ubuntu
|
||||
ENV KASMVNC_BUILD_OS_CODENAME jammy
|
||||
ENV XORG_VER 1.20.8
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
RUN sed -i 's$# deb-src$deb-src$' /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install sudo
|
||||
|
||||
RUN apt-get update && 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 libjpeg-dev libgnutls28-dev vim wget tightvncserver
|
||||
RUN apt-get update && apt-get -y install libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev libxrandr-dev libxcursor-dev
|
||||
|
||||
# Additions for webp
|
||||
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
|
||||
RUN cd /tmp && tar -xzf /tmp/libwebp-*
|
||||
RUN cd /tmp/libwebp-1.0.2 && \
|
||||
./configure --enable-static --disable-shared && \
|
||||
make && make install
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||
|
||||
COPY --chown=docker:docker . /src/
|
||||
|
||||
USER docker
|
||||
ENTRYPOINT ["/src/builder/build.sh"]
|
||||
19
builder/dockerfile.ubuntu_jammy.deb.build
Normal file
19
builder/dockerfile.ubuntu_jammy.deb.build
Normal file
@@ -0,0 +1,19 @@
|
||||
FROM ubuntu:jammy
|
||||
|
||||
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
|
||||
57
builder/dockerfile.ubuntu_jammy.deb.test
Normal file
57
builder/dockerfile.ubuntu_jammy.deb.test
Normal file
@@ -0,0 +1,57 @@
|
||||
FROM ubuntu:jammy
|
||||
|
||||
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=ubuntu \
|
||||
KASMVNC_BUILD_OS_CODENAME=bionic
|
||||
|
||||
EXPOSE $VNC_PORT
|
||||
|
||||
WORKDIR $HOME
|
||||
|
||||
### REQUIRED STUFF ###
|
||||
|
||||
RUN apt-get update && apt-get install -y supervisor xfce4 xfce4-terminal 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 startup/ $STARTUPDIR
|
||||
|
||||
### START CUSTOM STUFF ####
|
||||
|
||||
ARG KASMVNC_PACKAGE_DIR
|
||||
COPY $KASMVNC_PACKAGE_DIR/kasmvncserver_*.deb /tmp/
|
||||
RUN rm -f /tmp/kasmvncserver_*+*.deb; dpkg -i /tmp/*.deb; apt-get -yf install
|
||||
|
||||
RUN mkdir ~/.vnc && echo '/usr/bin/xfce4-session &' >> ~/.vnc/xstartup && \
|
||||
chmod +x ~/.vnc/xstartup
|
||||
|
||||
### END CUSTOM STUFF ###
|
||||
|
||||
RUN chown -R 1000:0 $HOME
|
||||
USER 1000:ssl-cert
|
||||
WORKDIR $HOME
|
||||
|
||||
ENTRYPOINT [ "/dockerstartup/vnc_startup.sh" ]
|
||||
51
builder/dockerfile.ubuntu_jammy.test
Normal file
51
builder/dockerfile.ubuntu_jammy.test
Normal file
@@ -0,0 +1,51 @@
|
||||
FROM ubuntu:jammy
|
||||
|
||||
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=ubuntu \
|
||||
KASMVNC_BUILD_OS_CODENAME=jammy
|
||||
|
||||
EXPOSE $VNC_PORT
|
||||
|
||||
WORKDIR $HOME
|
||||
|
||||
### REQUIRED STUFF ###
|
||||
|
||||
RUN apt-get update && apt-get install -y supervisor xfce4 xfce4-terminal xterm libnss-wrapper gettext libjpeg-dev wget
|
||||
RUN apt-get purge -y pm-utils xscreensaver*
|
||||
|
||||
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
|
||||
|
||||
RUN mkdir -p $STARTUPDIR
|
||||
COPY startup/ $STARTUPDIR
|
||||
|
||||
### START CUSTOM STUFF ####
|
||||
|
||||
COPY build/kasmvnc.${KASMVNC_BUILD_OS}_${KASMVNC_BUILD_OS_CODENAME}.tar.gz /tmp/
|
||||
RUN tar -xzvf /tmp/kasmvnc.${KASMVNC_BUILD_OS}_${KASMVNC_BUILD_OS_CODENAME}.tar.gz --strip 1 -C /
|
||||
|
||||
### END CUSTOM STUFF ###
|
||||
|
||||
RUN chown -R 1000:0 $HOME
|
||||
USER 1000
|
||||
WORKDIR $HOME
|
||||
|
||||
ENTRYPOINT [ "/dockerstartup/vnc_startup.sh" ]
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: kasmvncserver
|
||||
Version: 0.9.1~beta
|
||||
Version: 0.9.3~beta
|
||||
Release: 1%{?dist}
|
||||
Summary: VNC server accessible from a web browser
|
||||
|
||||
@@ -53,6 +53,7 @@ cp $SRC_BIN/Xvnc $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/vncserver $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/vncconfig $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/kasmvncpasswd $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/kasmxproxy $DESTDIR/usr/bin;
|
||||
cd $DESTDIR/usr/bin && ln -s kasmvncpasswd vncpasswd;
|
||||
cp -r $SRC/share/doc/kasmvnc*/* $DESTDIR/usr/share/doc/kasmvncserver/
|
||||
rsync -r --exclude '.git*' --exclude po2js --exclude xgettext-html \
|
||||
@@ -62,8 +63,10 @@ cp $SRC/man/man1/Xvnc.1 $DESTDIR/usr/share/man/man1/;
|
||||
cp $SRC/share/man/man1/vncserver.1 $DST_MAN;
|
||||
cp $SRC/share/man/man1/vncconfig.1 $DST_MAN;
|
||||
cp $SRC/share/man/man1/vncpasswd.1 $DST_MAN;
|
||||
cp $SRC/share/man/man1/kasmxproxy.1 $DST_MAN;
|
||||
cd $DST_MAN && ln -s vncpasswd.1 kasmvncpasswd.1;
|
||||
|
||||
|
||||
%files
|
||||
/usr/bin/*
|
||||
/usr/share/man/man1/*
|
||||
@@ -73,6 +76,7 @@ cd $DST_MAN && ln -s vncpasswd.1 kasmvncpasswd.1;
|
||||
%doc /usr/share/doc/kasmvncserver/README.md
|
||||
|
||||
%changelog
|
||||
* Tue Mar 22 2022 KasmTech <info@kasmweb.com> - 0.9.3~beta-1
|
||||
* Fri Feb 12 2021 KasmTech <info@kasmweb.com> - 0.9.1~beta-1
|
||||
- Initial release of the rpm package.
|
||||
|
||||
|
||||
85
common/network/Blacklist.cxx
Normal file
85
common/network/Blacklist.cxx
Normal file
@@ -0,0 +1,85 @@
|
||||
/* Copyright (C) 2021 Kasm
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <network/Blacklist.h>
|
||||
#include <rfb/Blacklist.h>
|
||||
|
||||
static std::map<std::string, unsigned> hits;
|
||||
static std::map<std::string, time_t> blacklist;
|
||||
|
||||
static pthread_mutex_t hitmutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t blmutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
unsigned char bl_isBlacklisted(const char *addr) {
|
||||
const unsigned char count = blacklist.count(addr);
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
const time_t now = time(NULL);
|
||||
const unsigned timeout = rfb::Blacklist::initialTimeout;
|
||||
|
||||
if (pthread_mutex_lock(&blmutex))
|
||||
abort();
|
||||
|
||||
if (now - timeout > blacklist[addr]) {
|
||||
blacklist.erase(addr);
|
||||
pthread_mutex_unlock(&blmutex);
|
||||
|
||||
if (pthread_mutex_lock(&hitmutex))
|
||||
abort();
|
||||
hits.erase(addr);
|
||||
pthread_mutex_unlock(&hitmutex);
|
||||
return 0;
|
||||
} else {
|
||||
blacklist[addr] = now;
|
||||
pthread_mutex_unlock(&blmutex);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void bl_addFailure(const char *addr) {
|
||||
if (!rfb::Blacklist::threshold)
|
||||
return;
|
||||
|
||||
if (pthread_mutex_lock(&hitmutex))
|
||||
abort();
|
||||
const unsigned num = ++hits[addr];
|
||||
pthread_mutex_unlock(&hitmutex);
|
||||
|
||||
if (num >= (unsigned) rfb::Blacklist::threshold) {
|
||||
if (pthread_mutex_lock(&blmutex))
|
||||
abort();
|
||||
blacklist[addr] = time(NULL);
|
||||
pthread_mutex_unlock(&blmutex);
|
||||
}
|
||||
}
|
||||
33
common/network/Blacklist.h
Normal file
33
common/network/Blacklist.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/* Copyright (C) 2021 Kasm
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifndef __NETWORK_BLACKLIST_H__
|
||||
#define __NETWORK_BLACKLIST_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned char bl_isBlacklisted(const char *);
|
||||
void bl_addFailure(const char *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern C
|
||||
#endif
|
||||
|
||||
#endif // __NETWORK_TCP_SOCKET_H__
|
||||
@@ -2,8 +2,11 @@ include_directories(${CMAKE_SOURCE_DIR}/common ${CMAKE_SOURCE_DIR}/unix/kasmvncp
|
||||
|
||||
set(NETWORK_SOURCES
|
||||
GetAPIMessager.cxx
|
||||
Blacklist.cxx
|
||||
Socket.cxx
|
||||
TcpSocket.cxx
|
||||
cJSON.c
|
||||
jsonescape.c
|
||||
websocket.c
|
||||
websockify.c
|
||||
${CMAKE_SOURCE_DIR}/unix/kasmvncpasswd/kasmpasswd.c)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <kasmpasswd.h>
|
||||
#include <pthread.h>
|
||||
#include <network/GetAPIEnums.h>
|
||||
#include <rfb/PixelBuffer.h>
|
||||
#include <rfb/PixelFormat.h>
|
||||
#include <stdint.h>
|
||||
@@ -52,17 +53,21 @@ namespace network {
|
||||
uint8_t *netGetScreenshot(uint16_t w, uint16_t h,
|
||||
const uint8_t q, const bool dedup,
|
||||
uint32_t &len, uint8_t *staging);
|
||||
uint8_t netAddUser(const char name[], const char pw[], const bool write);
|
||||
uint8_t netAddUser(const char name[], const char pw[],
|
||||
const bool read, const bool write, const bool owner);
|
||||
uint8_t netRemoveUser(const char name[]);
|
||||
uint8_t netGiveControlTo(const char name[]);
|
||||
uint8_t netUpdateUser(const char name[], const uint64_t mask,
|
||||
const char password[],
|
||||
const bool read, const bool write, const bool owner);
|
||||
uint8_t netAddOrUpdateUser(const struct kasmpasswd_entry_t *entry);
|
||||
void netGetUsers(const char **ptr);
|
||||
void netGetBottleneckStats(char *buf, uint32_t len);
|
||||
void netGetFrameStats(char *buf, uint32_t len);
|
||||
void netResetFrameStatsCall();
|
||||
uint8_t netServerFrameStatsReady();
|
||||
|
||||
enum USER_ACTION {
|
||||
//USER_ADD, - handled locally for interactivity
|
||||
USER_REMOVE,
|
||||
USER_GIVE_CONTROL,
|
||||
NONE,
|
||||
WANT_FRAME_STATS_SERVERONLY,
|
||||
WANT_FRAME_STATS_ALL,
|
||||
WANT_FRAME_STATS_OWNER,
|
||||
|
||||
30
common/network/GetAPIEnums.h
Normal file
30
common/network/GetAPIEnums.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* Copyright (C) 2021 Kasm
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifndef __NETWORK_GET_API_ENUMS_H__
|
||||
#define __NETWORK_GET_API_ENUMS_H__
|
||||
|
||||
// Enums that need accessibility from both C and C++.
|
||||
enum USER_UPDATE_MASK {
|
||||
USER_UPDATE_WRITE_MASK = 1 << 0,
|
||||
USER_UPDATE_OWNER_MASK = 1 << 1,
|
||||
USER_UPDATE_PASSWORD_MASK = 1 << 2,
|
||||
USER_UPDATE_READ_MASK = 1 << 3,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <network/GetAPI.h>
|
||||
#include <network/jsonescape.h>
|
||||
#include <rfb/ConnParams.h>
|
||||
#include <rfb/EncodeManager.h>
|
||||
#include <rfb/LogWriter.h>
|
||||
@@ -263,10 +264,9 @@ uint8_t *GetAPIMessager::netGetScreenshot(uint16_t w, uint16_t h,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define USERNAME_LEN sizeof(((struct kasmpasswd_entry_t *)0)->user)
|
||||
#define PASSWORD_LEN sizeof(((struct kasmpasswd_entry_t *)0)->password)
|
||||
|
||||
uint8_t GetAPIMessager::netAddUser(const char name[], const char pw[], const bool write) {
|
||||
uint8_t GetAPIMessager::netAddUser(const char name[], const char pw[],
|
||||
const bool read, const bool write,
|
||||
const bool owner) {
|
||||
if (strlen(name) >= USERNAME_LEN) {
|
||||
vlog.error("Username too long");
|
||||
return 0;
|
||||
@@ -280,14 +280,17 @@ uint8_t GetAPIMessager::netAddUser(const char name[], const char pw[], const boo
|
||||
if (!passwdfile)
|
||||
return 0;
|
||||
|
||||
uint8_t ret = 1;
|
||||
|
||||
action_data act;
|
||||
|
||||
memcpy(act.data.user, name, USERNAME_LEN);
|
||||
act.data.user[USERNAME_LEN - 1] = '\0';
|
||||
memcpy(act.data.password, pw, PASSWORD_LEN);
|
||||
act.data.password[PASSWORD_LEN - 1] = '\0';
|
||||
act.data.owner = 0;
|
||||
act.data.owner = owner;
|
||||
act.data.write = write;
|
||||
act.data.read = read;
|
||||
|
||||
if (pthread_mutex_lock(&userMutex))
|
||||
return 0;
|
||||
@@ -299,8 +302,9 @@ uint8_t GetAPIMessager::netAddUser(const char name[], const char pw[], const boo
|
||||
struct kasmpasswd_t *set = readkasmpasswd(passwdfile);
|
||||
unsigned s;
|
||||
for (s = 0; s < set->num; s++) {
|
||||
if (!strcmp(set->entries[s].user, act.data.user)) {
|
||||
vlog.error("Can't create user %s, already exists", act.data.user);
|
||||
if (!strcmp(set->entries[s].user, name)) {
|
||||
vlog.error("Can't create user %s, already exists", name);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -311,11 +315,14 @@ uint8_t GetAPIMessager::netAddUser(const char name[], const char pw[], const boo
|
||||
set->entries[s] = act.data;
|
||||
|
||||
writekasmpasswd(passwdfile, set);
|
||||
vlog.info("User %s created", act.data.user);
|
||||
vlog.info("User %s created", name);
|
||||
out:
|
||||
pthread_mutex_unlock(&userMutex);
|
||||
|
||||
return 1;
|
||||
free(set->entries);
|
||||
free(set);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t GetAPIMessager::netRemoveUser(const char name[]) {
|
||||
@@ -324,44 +331,189 @@ uint8_t GetAPIMessager::netRemoveUser(const char name[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
action_data act;
|
||||
act.action = USER_REMOVE;
|
||||
|
||||
memcpy(act.data.user, name, USERNAME_LEN);
|
||||
act.data.user[USERNAME_LEN - 1] = '\0';
|
||||
|
||||
if (pthread_mutex_lock(&userMutex))
|
||||
return 0;
|
||||
|
||||
actionQueue.push_back(act);
|
||||
struct kasmpasswd_t *set = readkasmpasswd(passwdfile);
|
||||
bool found = false;
|
||||
unsigned s;
|
||||
for (s = 0; s < set->num; s++) {
|
||||
if (!strcmp(set->entries[s].user, name)) {
|
||||
set->entries[s].user[0] = '\0';
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
writekasmpasswd(passwdfile, set);
|
||||
vlog.info("User %s removed", name);
|
||||
} else {
|
||||
vlog.error("Tried to remove nonexistent user %s", name);
|
||||
|
||||
pthread_mutex_unlock(&userMutex);
|
||||
|
||||
free(set->entries);
|
||||
free(set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&userMutex);
|
||||
|
||||
free(set->entries);
|
||||
free(set);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t GetAPIMessager::netGiveControlTo(const char name[]) {
|
||||
uint8_t GetAPIMessager::netUpdateUser(const char name[], const uint64_t mask,
|
||||
const char password[],
|
||||
const bool read, const bool write, const bool owner) {
|
||||
if (strlen(name) >= USERNAME_LEN) {
|
||||
vlog.error("Username too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
action_data act;
|
||||
act.action = USER_GIVE_CONTROL;
|
||||
if (strlen(password) >= PASSWORD_LEN) {
|
||||
vlog.error("Password too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(act.data.user, name, USERNAME_LEN);
|
||||
act.data.user[USERNAME_LEN - 1] = '\0';
|
||||
if (!mask) {
|
||||
vlog.error("Update_user without any updates?");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pthread_mutex_lock(&userMutex))
|
||||
return 0;
|
||||
|
||||
actionQueue.push_back(act);
|
||||
struct kasmpasswd_t *set = readkasmpasswd(passwdfile);
|
||||
bool found = false;
|
||||
unsigned s;
|
||||
for (s = 0; s < set->num; s++) {
|
||||
if (!strcmp(set->entries[s].user, name)) {
|
||||
if (mask & USER_UPDATE_READ_MASK)
|
||||
set->entries[s].read = read;
|
||||
if (mask & USER_UPDATE_WRITE_MASK)
|
||||
set->entries[s].write = write;
|
||||
if (mask & USER_UPDATE_OWNER_MASK)
|
||||
set->entries[s].owner = owner;
|
||||
|
||||
if (mask & USER_UPDATE_PASSWORD_MASK)
|
||||
strcpy(set->entries[s].password, password);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
writekasmpasswd(passwdfile, set);
|
||||
vlog.info("User %s permissions updated", name);
|
||||
} else {
|
||||
vlog.error("Tried to update nonexistent user %s", name);
|
||||
|
||||
pthread_mutex_unlock(&userMutex);
|
||||
|
||||
free(set->entries);
|
||||
free(set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&userMutex);
|
||||
|
||||
free(set->entries);
|
||||
free(set);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t GetAPIMessager::netAddOrUpdateUser(const struct kasmpasswd_entry_t *entry) {
|
||||
|
||||
if (pthread_mutex_lock(&userMutex))
|
||||
return 0;
|
||||
|
||||
struct kasmpasswd_t *set = readkasmpasswd(passwdfile);
|
||||
unsigned s;
|
||||
bool updated = false;
|
||||
for (s = 0; s < set->num; s++) {
|
||||
if (!strcmp(set->entries[s].user, entry->user)) {
|
||||
set->entries[s] = *entry;
|
||||
updated = true;
|
||||
vlog.info("User %s updated", entry->user);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!updated) {
|
||||
s = set->num++;
|
||||
set->entries = (struct kasmpasswd_entry_t *) realloc(set->entries,
|
||||
set->num * sizeof(struct kasmpasswd_entry_t));
|
||||
set->entries[s] = *entry;
|
||||
vlog.info("User %s created", entry->user);
|
||||
}
|
||||
|
||||
writekasmpasswd(passwdfile, set);
|
||||
|
||||
pthread_mutex_unlock(&userMutex);
|
||||
|
||||
free(set->entries);
|
||||
free(set);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
void GetAPIMessager::netGetUsers(const char **outptr) {
|
||||
/*
|
||||
[
|
||||
{ "user": "username", "write": true, "owner": true },
|
||||
{ "user": "username", "write": true, "owner": true }
|
||||
]
|
||||
*/
|
||||
char *buf;
|
||||
char escapeduser[USERNAME_LEN * 2];
|
||||
|
||||
if (pthread_mutex_lock(&userMutex)) {
|
||||
*outptr = (char *) calloc(1, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
struct kasmpasswd_t *set = readkasmpasswd(passwdfile);
|
||||
|
||||
buf = (char *) calloc(set->num, 80);
|
||||
FILE *f = fmemopen(buf, set->num * 80, "w");
|
||||
|
||||
fprintf(f, "[\n");
|
||||
|
||||
unsigned s;
|
||||
for (s = 0; s < set->num; s++) {
|
||||
JSON_escape(set->entries[s].user, escapeduser);
|
||||
|
||||
fprintf(f, " { \"user\": \"%s\", \"read\": %s, \"write\": %s, \"owner\": %s }",
|
||||
escapeduser,
|
||||
set->entries[s].read ? "true" : "false",
|
||||
set->entries[s].write ? "true" : "false",
|
||||
set->entries[s].owner ? "true" : "false");
|
||||
|
||||
if (s == set->num - 1)
|
||||
fprintf(f, "\n");
|
||||
else
|
||||
fprintf(f, ",\n");
|
||||
}
|
||||
|
||||
free(set->entries);
|
||||
free(set);
|
||||
|
||||
fprintf(f, "]\n");
|
||||
|
||||
fclose(f);
|
||||
|
||||
pthread_mutex_unlock(&userMutex);
|
||||
*outptr = buf;
|
||||
}
|
||||
|
||||
void GetAPIMessager::netGetBottleneckStats(char *buf, uint32_t len) {
|
||||
/*
|
||||
{
|
||||
@@ -540,6 +692,15 @@ out:
|
||||
pthread_mutex_unlock(&frameStatMutex);
|
||||
}
|
||||
|
||||
void GetAPIMessager::netResetFrameStatsCall() {
|
||||
if (pthread_mutex_lock(&frameStatMutex))
|
||||
return;
|
||||
|
||||
serverFrameStats.inprogress = 0;
|
||||
|
||||
pthread_mutex_unlock(&frameStatMutex);
|
||||
}
|
||||
|
||||
uint8_t GetAPIMessager::netRequestFrameStats(USER_ACTION what, const char *client) {
|
||||
// Return 1 for success
|
||||
action_data act;
|
||||
|
||||
@@ -443,10 +443,10 @@ static uint8_t *screenshotCb(void *messager, uint16_t w, uint16_t h, const uint8
|
||||
}
|
||||
|
||||
static uint8_t adduserCb(void *messager, const char name[], const char pw[],
|
||||
const uint8_t write)
|
||||
const uint8_t read, const uint8_t write, const uint8_t owner)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
return msgr->netAddUser(name, pw, write);
|
||||
return msgr->netAddUser(name, pw, read, write, owner);
|
||||
}
|
||||
|
||||
static uint8_t removeCb(void *messager, const char name[])
|
||||
@@ -455,10 +455,24 @@ static uint8_t removeCb(void *messager, const char name[])
|
||||
return msgr->netRemoveUser(name);
|
||||
}
|
||||
|
||||
static uint8_t givecontrolCb(void *messager, const char name[])
|
||||
static uint8_t updateUserCb(void *messager, const char name[], const uint64_t mask,
|
||||
const char password[],
|
||||
const uint8_t read, const uint8_t write, const uint8_t owner)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
return msgr->netGiveControlTo(name);
|
||||
return msgr->netUpdateUser(name, mask, password, read, write, owner);
|
||||
}
|
||||
|
||||
static uint8_t addOrUpdateUserCb(void *messager, const struct kasmpasswd_entry_t *entry)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
return msgr->netAddOrUpdateUser(entry);
|
||||
}
|
||||
|
||||
static void getUsersCb(void *messager, const char **ptr)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
msgr->netGetUsers(ptr);
|
||||
}
|
||||
|
||||
static void bottleneckStatsCb(void *messager, char *buf, uint32_t len)
|
||||
@@ -473,6 +487,12 @@ static void frameStatsCb(void *messager, char *buf, uint32_t len)
|
||||
msgr->netGetFrameStats(buf, len);
|
||||
}
|
||||
|
||||
static void resetFrameStatsCb(void *messager)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
msgr->netResetFrameStatsCall();
|
||||
}
|
||||
|
||||
static uint8_t requestFrameStatsNoneCb(void *messager)
|
||||
{
|
||||
GetAPIMessager *msgr = (GetAPIMessager *) messager;
|
||||
@@ -613,9 +633,12 @@ WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr,
|
||||
settings.screenshotCb = screenshotCb;
|
||||
settings.adduserCb = adduserCb;
|
||||
settings.removeCb = removeCb;
|
||||
settings.givecontrolCb = givecontrolCb;
|
||||
settings.updateUserCb = updateUserCb;
|
||||
settings.addOrUpdateUserCb = addOrUpdateUserCb;
|
||||
settings.getUsersCb = getUsersCb;
|
||||
settings.bottleneckStatsCb = bottleneckStatsCb;
|
||||
settings.frameStatsCb = frameStatsCb;
|
||||
settings.resetFrameStatsCb = resetFrameStatsCb;
|
||||
|
||||
settings.requestFrameStatsNoneCb = requestFrameStatsNoneCb;
|
||||
settings.requestFrameStatsOwnerCb = requestFrameStatsOwnerCb;
|
||||
@@ -908,6 +931,8 @@ void network::createWebsocketListeners(std::list<SocketListener*> *listeners,
|
||||
freeaddrinfo(ai);
|
||||
throw;
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3114
common/network/cJSON.c
Normal file
3114
common/network/cJSON.c
Normal file
File diff suppressed because it is too large
Load Diff
295
common/network/cJSON.h
Normal file
295
common/network/cJSON.h
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// 2fc55f6 from Jan 20, 2022
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 15
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
25
common/network/datelog.h
Normal file
25
common/network/datelog.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/* Copyright (C) 2022 Kasm
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifndef NETWORK_DATELOG_H
|
||||
#define NETWORK_DATELOG_H
|
||||
|
||||
// 2022-05-18 19:51:26
|
||||
#define DATELOGFMT "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
#endif
|
||||
179
common/network/jsonescape.c
Normal file
179
common/network/jsonescape.c
Normal file
@@ -0,0 +1,179 @@
|
||||
/* Copyright (C) 2022 Kasm
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jsonescape.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
void JSON_escape(const char *in, char *out) {
|
||||
for (; *in; in++) {
|
||||
if (in[0] == '\b') {
|
||||
*out++ = '\\';
|
||||
*out++ = 'b';
|
||||
} else if (in[0] == '\f') {
|
||||
*out++ = '\\';
|
||||
*out++ = 'f';
|
||||
} else if (in[0] == '\n') {
|
||||
*out++ = '\\';
|
||||
*out++ = 'n';
|
||||
} else if (in[0] == '\r') {
|
||||
*out++ = '\\';
|
||||
*out++ = 'r';
|
||||
} else if (in[0] == '\t') {
|
||||
*out++ = '\\';
|
||||
*out++ = 't';
|
||||
} else if (in[0] == '"') {
|
||||
*out++ = '\\';
|
||||
*out++ = '"';
|
||||
} else if (in[0] == '\\') {
|
||||
*out++ = '\\';
|
||||
*out++ = '\\';
|
||||
} else {
|
||||
*out++ = *in;
|
||||
}
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
}
|
||||
|
||||
void JSON_unescape(const char *in, char *out) {
|
||||
for (; *in; in++) {
|
||||
if (in[0] == '\\' && in[1] == 'b') {
|
||||
*out++ = '\b';
|
||||
in++;
|
||||
} else if (in[0] == '\\' && in[1] == 'f') {
|
||||
*out++ = '\f';
|
||||
in++;
|
||||
} else if (in[0] == '\\' && in[1] == 'n') {
|
||||
*out++ = '\n';
|
||||
in++;
|
||||
} else if (in[0] == '\\' && in[1] == 'r') {
|
||||
*out++ = '\r';
|
||||
in++;
|
||||
} else if (in[0] == '\\' && in[1] == 't') {
|
||||
*out++ = '\t';
|
||||
in++;
|
||||
} else if (in[0] == '\\' && in[1] == '"') {
|
||||
*out++ = '"';
|
||||
in++;
|
||||
} else if (in[0] == '\\' && in[1] == '\\') {
|
||||
*out++ = '\\';
|
||||
in++;
|
||||
} else {
|
||||
*out++ = *in;
|
||||
}
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
}
|
||||
|
||||
struct kasmpasswd_t *parseJsonUsers(const char *data) {
|
||||
|
||||
cJSON *json = cJSON_Parse(data);
|
||||
if (!json)
|
||||
return NULL;
|
||||
|
||||
if (!(json->type & cJSON_Array))
|
||||
return NULL;
|
||||
|
||||
struct kasmpasswd_t *set = calloc(sizeof(struct kasmpasswd_t), 1);
|
||||
set->num = cJSON_GetArraySize(json);
|
||||
set->entries = calloc(sizeof(struct kasmpasswd_entry_t), set->num);
|
||||
|
||||
cJSON *cur;
|
||||
unsigned s, len;
|
||||
for (cur = json->child, s = 0; cur; cur = cur->next, s++) {
|
||||
if (!(cur->type & cJSON_Object))
|
||||
goto fail;
|
||||
|
||||
cJSON *e;
|
||||
struct kasmpasswd_entry_t * const entry = &set->entries[s];
|
||||
|
||||
entry->user[0] = '\0';
|
||||
entry->password[0] = '\0';
|
||||
entry->write = entry->owner = 0;
|
||||
|
||||
for (e = cur->child; e; e = e->next) {
|
||||
#define field(x) if (!strcmp(x, e->string))
|
||||
|
||||
field("user") {
|
||||
if (!(e->type & cJSON_String))
|
||||
goto fail;
|
||||
len = strlen(e->valuestring);
|
||||
|
||||
//printf("Val '%.*s'\n", len, start);
|
||||
|
||||
if (len >= USERNAME_LEN)
|
||||
goto fail;
|
||||
|
||||
memcpy(entry->user, e->valuestring, len);
|
||||
entry->user[len] = '\0';
|
||||
} else field("password") {
|
||||
if (!(e->type & cJSON_String))
|
||||
goto fail;
|
||||
len = strlen(e->valuestring);
|
||||
|
||||
//printf("Val '%.*s'\n", len, start);
|
||||
|
||||
if (len >= PASSWORD_LEN)
|
||||
goto fail;
|
||||
|
||||
memcpy(entry->password, e->valuestring, len);
|
||||
entry->password[len] = '\0';
|
||||
} else field("write") {
|
||||
if (!(e->type & (cJSON_False | cJSON_True)))
|
||||
goto fail;
|
||||
|
||||
if (e->type & cJSON_True)
|
||||
entry->write = 1;
|
||||
} else field("owner") {
|
||||
if (!(e->type & (cJSON_False | cJSON_True)))
|
||||
goto fail;
|
||||
|
||||
if (e->type & cJSON_True)
|
||||
entry->owner = 1;
|
||||
} else field("read") {
|
||||
if (!(e->type & (cJSON_False | cJSON_True)))
|
||||
goto fail;
|
||||
|
||||
if (e->type & cJSON_True)
|
||||
entry->read = 1;
|
||||
|
||||
} else {
|
||||
//printf("Unknown field '%.*s'\n", len, start);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#undef field
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_Delete(json);
|
||||
|
||||
return set;
|
||||
fail:
|
||||
free(set->entries);
|
||||
free(set);
|
||||
|
||||
cJSON_Delete(json);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
38
common/network/jsonescape.h
Normal file
38
common/network/jsonescape.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Copyright (C) 2022 Kasm
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifndef __NETWORK_JSON_ESCAPE_H__
|
||||
#define __NETWORK_JSON_ESCAPE_H__
|
||||
|
||||
#include <kasmpasswd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void JSON_escape(const char *in, char *out);
|
||||
void JSON_unescape(const char *in, char *out);
|
||||
|
||||
struct kasmpasswd_t *parseJsonUsers(const char *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern C
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
||||
#include <openssl/ssl.h>
|
||||
#include <stdint.h>
|
||||
#include "GetAPIEnums.h"
|
||||
#include "datelog.h"
|
||||
|
||||
#define BUFSIZE 65536
|
||||
#define DBUFSIZE (BUFSIZE * 3) / 4 - 20
|
||||
@@ -65,6 +67,8 @@ struct wspass_t {
|
||||
char ip[64];
|
||||
};
|
||||
|
||||
struct kasmpasswd_entry_t;
|
||||
|
||||
typedef struct {
|
||||
int verbose;
|
||||
int listen_sock;
|
||||
@@ -81,11 +85,15 @@ typedef struct {
|
||||
const uint8_t dedup,
|
||||
uint32_t *len, uint8_t *staging);
|
||||
uint8_t (*adduserCb)(void *messager, const char name[], const char pw[],
|
||||
const uint8_t write);
|
||||
const uint8_t read, const uint8_t write, const uint8_t owner);
|
||||
uint8_t (*removeCb)(void *messager, const char name[]);
|
||||
uint8_t (*givecontrolCb)(void *messager, const char name[]);
|
||||
uint8_t (*updateUserCb)(void *messager, const char name[], const uint64_t mask,
|
||||
const char password[],
|
||||
const uint8_t read, const uint8_t write, const uint8_t owner);
|
||||
uint8_t (*addOrUpdateUserCb)(void *messager, const struct kasmpasswd_entry_t *entry);
|
||||
void (*bottleneckStatsCb)(void *messager, char *buf, uint32_t len);
|
||||
void (*frameStatsCb)(void *messager, char *buf, uint32_t len);
|
||||
void (*resetFrameStatsCb)(void *messager);
|
||||
|
||||
uint8_t (*requestFrameStatsNoneCb)(void *messager);
|
||||
uint8_t (*requestFrameStatsOwnerCb)(void *messager);
|
||||
@@ -94,6 +102,7 @@ typedef struct {
|
||||
|
||||
uint8_t (*ownerConnectedCb)(void *messager);
|
||||
uint8_t (*numActiveUsersCb)(void *messager);
|
||||
void (*getUsersCb)(void *messager, const char **buf);
|
||||
uint8_t (*getClientFrameStatsNumCb)(void *messager);
|
||||
uint8_t (*serverFrameStatsReadyCb)(void *messager);
|
||||
} settings_t;
|
||||
@@ -112,18 +121,24 @@ ssize_t ws_send(ws_ctx_t *ctx, const void *buf, size_t len);
|
||||
//int b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize);
|
||||
//int b64_pton(char const *src, u_char *target, size_t targsize);
|
||||
|
||||
void wslog(char *logbuf, const unsigned websocket, const uint8_t debug);
|
||||
|
||||
extern __thread unsigned wsthread_handler_id;
|
||||
|
||||
#define gen_handler_msg(stream, ...) \
|
||||
if (settings.verbose) { \
|
||||
fprintf(stream, " websocket %d: ", wsthread_handler_id); \
|
||||
fprintf(stream, __VA_ARGS__); \
|
||||
char logbuf[2][1024]; \
|
||||
wslog(logbuf[0], wsthread_handler_id, 1); \
|
||||
sprintf(logbuf[1], __VA_ARGS__); \
|
||||
fprintf(stream, "%s%s", logbuf[0], logbuf[1]); \
|
||||
}
|
||||
|
||||
#define wserr(...) \
|
||||
{ \
|
||||
fprintf(stderr, " websocket %d: ", wsthread_handler_id); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
char logbuf[2][1024]; \
|
||||
wslog(logbuf[0], wsthread_handler_id, 0); \
|
||||
sprintf(logbuf[1], __VA_ARGS__); \
|
||||
fprintf(stderr, "%s%s", logbuf[0], logbuf[1]); \
|
||||
}
|
||||
|
||||
#define handler_msg(...) gen_handler_msg(stderr, __VA_ARGS__);
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace rfb {
|
||||
rdr::U32 __unused_attr keycode,
|
||||
bool __unused_attr down) { }
|
||||
virtual void pointerEvent(const Point& __unused_attr pos,
|
||||
const Point& __unused_attr abspos,
|
||||
int __unused_attr buttonMask,
|
||||
const bool __unused_attr skipClick,
|
||||
const bool __unused_attr skipRelease,
|
||||
|
||||
@@ -20,11 +20,14 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <os/Mutex.h>
|
||||
|
||||
#include <network/datelog.h>
|
||||
#include <rfb/util.h>
|
||||
#include <rfb/Logger_file.h>
|
||||
#include <rfb/LogWriter.h>
|
||||
|
||||
using namespace rfb;
|
||||
|
||||
@@ -55,14 +58,28 @@ void Logger_File::write(int level, const char *logname, const char *message)
|
||||
if (!m_file) return;
|
||||
}
|
||||
|
||||
time_t current = time(0);
|
||||
if (current != m_lastLogTime) {
|
||||
m_lastLogTime = current;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
if (tv.tv_sec != m_lastLogTime) {
|
||||
m_lastLogTime = tv.tv_sec;
|
||||
// fprintf(m_file, "\n%s", ctime(&m_lastLogTime));
|
||||
}
|
||||
|
||||
fprintf(m_file," %s:", logname);
|
||||
int column = strlen(logname) + 2;
|
||||
char timebuf[128];
|
||||
struct tm local;
|
||||
localtime_r(&tv.tv_sec, &local);
|
||||
strftime(timebuf, sizeof(timebuf), DATELOGFMT, &local);
|
||||
|
||||
const unsigned msec = tv.tv_usec / 1000;
|
||||
const char *levelname = "PRIO";
|
||||
if (level >= LogWriter::LEVEL_INFO)
|
||||
levelname = "INFO";
|
||||
if (level >= LogWriter::LEVEL_DEBUG)
|
||||
levelname = "DEBUG";
|
||||
|
||||
int column = fprintf(m_file, " %s,%03u [%s] %s:", timebuf, msec, levelname, logname);
|
||||
|
||||
if (column < indent) {
|
||||
fprintf(m_file,"%*s",indent-column,"");
|
||||
column = indent;
|
||||
|
||||
@@ -216,7 +216,7 @@ void SConnection::processSecurityMsg()
|
||||
bool done = ssecurity->processMsg(this);
|
||||
if (done) {
|
||||
state_ = RFBSTATE_QUERYING;
|
||||
setAccessRights(ssecurity->getAccessRights());
|
||||
//setAccessRights(ssecurity->getAccessRights());
|
||||
queryConnection(ssecurity->getUserName());
|
||||
}
|
||||
} catch (AuthFailureException& e) {
|
||||
@@ -292,7 +292,7 @@ void SConnection::clearBinaryClipboard()
|
||||
}
|
||||
|
||||
void SConnection::addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
||||
const rdr::U32 len)
|
||||
const rdr::U32 len, const rdr::U32 id)
|
||||
{
|
||||
binaryClipboard_t bin;
|
||||
strncpy(bin.mime, mime, sizeof(bin.mime));
|
||||
@@ -301,6 +301,8 @@ void SConnection::addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
||||
bin.data.resize(len);
|
||||
memcpy(&bin.data[0], data, len);
|
||||
|
||||
bin.id = id;
|
||||
|
||||
binaryClipboard.push_back(bin);
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace rfb {
|
||||
|
||||
virtual void clearBinaryClipboard();
|
||||
virtual void addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
||||
const rdr::U32 len);
|
||||
const rdr::U32 len, const rdr::U32 id);
|
||||
|
||||
virtual void supportsQEMUKeyEvent();
|
||||
|
||||
@@ -144,7 +144,6 @@ namespace rfb {
|
||||
static const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES
|
||||
static const AccessRights AccessNoQuery; // Connect without local user accepting
|
||||
static const AccessRights AccessFull; // All of the available AND FUTURE rights
|
||||
virtual void setAccessRights(AccessRights ar) = 0;
|
||||
|
||||
// Other methods
|
||||
|
||||
@@ -194,6 +193,7 @@ namespace rfb {
|
||||
|
||||
struct binaryClipboard_t {
|
||||
char mime[32];
|
||||
rdr::U32 id;
|
||||
std::vector<unsigned char> data;
|
||||
};
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ void SMsgHandler::clearBinaryClipboard()
|
||||
}
|
||||
|
||||
void SMsgHandler::addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
||||
const rdr::U32 len)
|
||||
const rdr::U32 len, const rdr::U32 id)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace rfb {
|
||||
virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
|
||||
virtual void clearBinaryClipboard();
|
||||
virtual void addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
||||
const rdr::U32 len);
|
||||
const rdr::U32 len, const rdr::U32 id);
|
||||
|
||||
virtual void sendStats(const bool toClient = true) = 0;
|
||||
virtual void handleFrameStats(rdr::U32 all, rdr::U32 render) = 0;
|
||||
|
||||
@@ -226,7 +226,8 @@ void SMsgReader::readPointerEvent()
|
||||
int y = is->readU16();
|
||||
int scrollX = is->readS16();
|
||||
int scrollY = is->readS16();
|
||||
handler->pointerEvent(Point(x, y), mask, false, false, scrollX, scrollY);
|
||||
|
||||
handler->pointerEvent(Point(x, y), Point(0, 0), mask, false, false, scrollX, scrollY);
|
||||
}
|
||||
|
||||
|
||||
@@ -276,7 +277,7 @@ void SMsgReader::readBinaryClipboard()
|
||||
|
||||
vlog.debug("Received binary clipboard, type %s, %u bytes", mime, len);
|
||||
|
||||
handler->addBinaryClipboard(mime, (rdr::U8 *) ca.buf, len);
|
||||
handler->addBinaryClipboard(mime, (rdr::U8 *) ca.buf, len, 0);
|
||||
valid++;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,9 @@ void SMsgWriter::writeBinaryClipboard(const std::vector<SConnection::binaryClipb
|
||||
os->writeU8(b.size());
|
||||
rdr::U8 i;
|
||||
for (i = 0; i < b.size(); i++) {
|
||||
const rdr::U32 id = b[i].id;
|
||||
os->writeU32(id);
|
||||
|
||||
const rdr::U8 mimelen = strlen(b[i].mime);
|
||||
os->writeU8(mimelen);
|
||||
os->writeBytes(b[i].mime, mimelen);
|
||||
|
||||
@@ -226,4 +226,4 @@ static void bandwidthPreset() {
|
||||
rfb::PresetParameter rfb::Server::preferBandwidth
|
||||
("PreferBandwidth",
|
||||
"Set various options for lower bandwidth use. The default is off, aka to prefer quality.",
|
||||
false, bandwidthPreset);
|
||||
false, bandwidthPreset);
|
||||
@@ -77,7 +77,6 @@ namespace rfb {
|
||||
static BoolParameter ignoreClientSettingsKasm;
|
||||
static BoolParameter selfBench;
|
||||
static PresetParameter preferBandwidth;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -87,10 +87,16 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
||||
user[at - peerEndpoint.buf] = '\0';
|
||||
}
|
||||
|
||||
bool write, owner;
|
||||
if (!getPerms(write, owner) || !write) {
|
||||
bool read, write, owner;
|
||||
if (!getPerms(read, write, owner)) {
|
||||
accessRights &= ~(WRITER_PERMS | AccessView);
|
||||
}
|
||||
if (!write) {
|
||||
accessRights &= ~WRITER_PERMS;
|
||||
}
|
||||
if (!read) {
|
||||
accessRights &= ~AccessView;
|
||||
}
|
||||
|
||||
// Configure the socket
|
||||
setSocketTimeouts();
|
||||
@@ -361,17 +367,18 @@ char *percentEncode4(const uint16_t *str, const unsigned len) {
|
||||
}
|
||||
|
||||
static void cliplog(const char *str, const int len, const int origlen,
|
||||
const char *dir, const char *client) {
|
||||
const char *dir, const char *client, const unsigned id) {
|
||||
if (Server::DLP_ClipLog[0] == 'o')
|
||||
return;
|
||||
if (Server::DLP_ClipLog[0] == 'i') {
|
||||
vlog.info("DLP: client %s: %s %u (%u requested) clipboard bytes", client, dir, len, origlen);
|
||||
vlog.info("DLP: client %s: %s %u (%u requested) clipboard bytes, id %u", client, dir,
|
||||
len, origlen, id);
|
||||
} else {
|
||||
// URL-encode it
|
||||
char *enc = percentEncode(str, len);
|
||||
|
||||
vlog.info("DLP: client %s: %s %u (%u requested) clipboard bytes: '%s'",
|
||||
client, dir, len, origlen, enc);
|
||||
vlog.info("DLP: client %s: %s %u (%u requested) clipboard bytes, id %u: '%s'",
|
||||
client, dir, len, origlen, id, enc);
|
||||
free(enc);
|
||||
}
|
||||
}
|
||||
@@ -433,7 +440,8 @@ void VNCSConnectionST::clearBinaryClipboardData()
|
||||
|
||||
void VNCSConnectionST::sendBinaryClipboardDataOrClose(const char* mime,
|
||||
const unsigned char *data,
|
||||
const unsigned len)
|
||||
const unsigned len,
|
||||
const unsigned id)
|
||||
{
|
||||
try {
|
||||
if (!(accessRights & AccessCutText)) return;
|
||||
@@ -444,10 +452,11 @@ void VNCSConnectionST::sendBinaryClipboardDataOrClose(const char* mime,
|
||||
return;
|
||||
}
|
||||
|
||||
cliplog((const char *) data, len, len, "sent", sock->getPeerAddress());
|
||||
cliplog((const char *) data, len, len, "sent", sock->getPeerAddress(),
|
||||
id);
|
||||
if (state() != RFBSTATE_NORMAL) return;
|
||||
|
||||
addBinaryClipboard(mime, data, len);
|
||||
addBinaryClipboard(mime, data, len, id);
|
||||
binclipTimer.start(100);
|
||||
} catch(rdr::Exception& e) {
|
||||
close(e.str());
|
||||
@@ -703,14 +712,58 @@ void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
|
||||
setCursor();
|
||||
}
|
||||
|
||||
void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask, const bool skipClick, const bool skipRelease, int scrollX, int scrollY)
|
||||
void VNCSConnectionST::pointerEvent(const Point& pos, const Point& abspos, int buttonMask, const bool skipClick, const bool skipRelease, int scrollX, int scrollY)
|
||||
{
|
||||
pointerEventTime = lastEventTime = time(0);
|
||||
server->lastUserInputTime = lastEventTime;
|
||||
if (!(accessRights & AccessPtrEvents)) return;
|
||||
if (!(accessRights & AccessPtrEvents)) {
|
||||
// This particular event is lost, but it's a corner case - you removed write access
|
||||
// from yourself, then added it back. The intended use is for multiple clients,
|
||||
// where the leader removes and adds back access for others, not himself.
|
||||
recheckPerms();
|
||||
return;
|
||||
}
|
||||
if (!rfb::Server::acceptPointerEvents) return;
|
||||
if (!server->pointerClient || server->pointerClient == this) {
|
||||
pointerEventPos = pos;
|
||||
Point newpos = pos;
|
||||
if (pos.x & 0x4000) {
|
||||
newpos.x &= ~0x4000;
|
||||
newpos.y &= ~0x4000;
|
||||
|
||||
if (newpos.x & 0x8000) {
|
||||
newpos.x &= ~0x8000;
|
||||
newpos.x = -newpos.x;
|
||||
}
|
||||
if (newpos.y & 0x8000) {
|
||||
newpos.y &= ~0x8000;
|
||||
newpos.y = -newpos.y;
|
||||
}
|
||||
|
||||
if (newpos.x < 0) {
|
||||
if (pointerEventPos.x + newpos.x >= 0)
|
||||
pointerEventPos.x += newpos.x;
|
||||
else
|
||||
pointerEventPos.x = 0;
|
||||
} else {
|
||||
pointerEventPos.x += newpos.x;
|
||||
if (pointerEventPos.x >= cp.width)
|
||||
pointerEventPos.x = cp.width;
|
||||
}
|
||||
|
||||
if (newpos.y < 0) {
|
||||
if (pointerEventPos.y + newpos.y >= 0)
|
||||
pointerEventPos.y += newpos.y;
|
||||
else
|
||||
pointerEventPos.y = 0;
|
||||
} else {
|
||||
pointerEventPos.y += newpos.y;
|
||||
if (pointerEventPos.y >= cp.height)
|
||||
pointerEventPos.y = cp.height;
|
||||
}
|
||||
} else {
|
||||
pointerEventPos = pos;
|
||||
}
|
||||
|
||||
if (buttonMask)
|
||||
server->pointerClient = this;
|
||||
else
|
||||
@@ -731,7 +784,7 @@ void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask, const bool
|
||||
}
|
||||
}
|
||||
|
||||
server->desktop->pointerEvent(pointerEventPos, buttonMask, skipclick, skiprelease, scrollX, scrollY);
|
||||
server->desktop->pointerEvent(newpos, pointerEventPos, buttonMask, skipclick, skiprelease, scrollX, scrollY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1037,6 +1090,14 @@ void VNCSConnectionST::handleClipboardAnnounceBinary(const unsigned num, const c
|
||||
if (!(accessRights & AccessCutText)) return;
|
||||
if (!rfb::Server::acceptCutText) return;
|
||||
server->handleClipboardAnnounceBinary(this, num, mimes);
|
||||
|
||||
const unsigned tolog = server->clipboardId++;
|
||||
|
||||
if (Server::DLP_ClipLog[0] == 'o')
|
||||
return;
|
||||
vlog.info("DLP: client %s: %s %u clipboard mimes, id %u",
|
||||
sock->getPeerAddress(), "received",
|
||||
num, tolog);
|
||||
}
|
||||
|
||||
// supportsLocalCursor() is called whenever the status of
|
||||
@@ -1105,11 +1166,12 @@ bool VNCSConnectionST::isShiftPressed()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VNCSConnectionST::getPerms(bool &write, bool &owner) const
|
||||
bool VNCSConnectionST::getPerms(bool &read, bool &write, bool &owner) const
|
||||
{
|
||||
bool found = false;
|
||||
if (disablebasicauth) {
|
||||
// We're running without basicauth
|
||||
read = true;
|
||||
write = true;
|
||||
return true;
|
||||
}
|
||||
@@ -1118,8 +1180,14 @@ bool VNCSConnectionST::getPerms(bool &write, bool &owner) const
|
||||
unsigned i;
|
||||
for (i = 0; i < set->num; i++) {
|
||||
if (!strcmp(set->entries[i].user, user)) {
|
||||
read = set->entries[i].read;
|
||||
write = set->entries[i].write;
|
||||
owner = set->entries[i].owner;
|
||||
|
||||
// Writer can always read
|
||||
if (write)
|
||||
read = true;
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -1217,18 +1285,29 @@ void VNCSConnectionST::writeFramebufferUpdate()
|
||||
if (needsPermCheck) {
|
||||
needsPermCheck = false;
|
||||
|
||||
bool write, owner, ret;
|
||||
ret = getPerms(write, owner);
|
||||
bool read, write, owner, ret;
|
||||
ret = getPerms(read, write, owner);
|
||||
if (!ret) {
|
||||
close("User was deleted");
|
||||
return;
|
||||
} else if (!write) {
|
||||
}
|
||||
|
||||
if (!write) {
|
||||
accessRights &= ~WRITER_PERMS;
|
||||
} else {
|
||||
accessRights |= WRITER_PERMS;
|
||||
}
|
||||
|
||||
if (!read) {
|
||||
accessRights &= ~AccessView;
|
||||
} else {
|
||||
accessRights |= AccessView;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(accessRights & AccessView))
|
||||
return;
|
||||
|
||||
// Updates often consists of many small writes, and in continuous
|
||||
// mode, we will also have small fence messages around the update. We
|
||||
// need to aggregate these in order to not clog up TCP's congestion
|
||||
@@ -1659,8 +1738,8 @@ bool VNCSConnectionST::checkOwnerConn() const
|
||||
std::list<VNCSConnectionST*>::const_iterator it;
|
||||
|
||||
for (it = server->clients.begin(); it != server->clients.end(); it++) {
|
||||
bool write, owner;
|
||||
if ((*it)->getPerms(write, owner) && owner)
|
||||
bool read, write, owner;
|
||||
if ((*it)->getPerms(read, write, owner) && owner)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace rfb {
|
||||
void announceClipboardOrClose(bool available);
|
||||
void clearBinaryClipboardData();
|
||||
void sendBinaryClipboardDataOrClose(const char* mime, const unsigned char *data,
|
||||
const unsigned len);
|
||||
const unsigned len, const unsigned id);
|
||||
void getBinaryClipboardData(const char* mime, const unsigned char **data,
|
||||
unsigned *len);
|
||||
|
||||
@@ -171,8 +171,8 @@ namespace rfb {
|
||||
virtual void handleFrameStats(rdr::U32 all, rdr::U32 render);
|
||||
|
||||
bool is_owner() const {
|
||||
bool write, owner;
|
||||
if (getPerms(write, owner) && owner)
|
||||
bool read, write, owner;
|
||||
if (getPerms(read, write, owner) && owner)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -207,7 +207,7 @@ namespace rfb {
|
||||
virtual void queryConnection(const char* userName);
|
||||
virtual void clientInit(bool shared);
|
||||
virtual void setPixelFormat(const PixelFormat& pf);
|
||||
virtual void pointerEvent(const Point& pos, int buttonMask, const bool skipClick, const bool skipRelease, int scrollX, int scrollY);
|
||||
virtual void pointerEvent(const Point& pos, const Point& abspos,int buttonMask, const bool skipClick, const bool skipRelease, int scrollX, int scrollY);
|
||||
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
|
||||
virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
|
||||
virtual void setDesktopSize(int fb_width, int fb_height,
|
||||
@@ -227,19 +227,6 @@ namespace rfb {
|
||||
(AccessPtrEvents | AccessKeyEvents);
|
||||
}
|
||||
|
||||
// setAccessRights() allows a security package to limit the access rights
|
||||
// of a VNCSConnectioST to the server. These access rights are applied
|
||||
// such that the actual rights granted are the minimum of the server's
|
||||
// default access settings and the connection's access settings.
|
||||
virtual void setAccessRights(AccessRights ar) {
|
||||
accessRights = ar;
|
||||
|
||||
bool write, owner;
|
||||
if (!getPerms(write, owner) || !write)
|
||||
accessRights &= ~WRITER_PERMS;
|
||||
needsPermCheck = false;
|
||||
}
|
||||
|
||||
// Timer callbacks
|
||||
virtual bool handleTimeout(Timer* t);
|
||||
|
||||
@@ -247,7 +234,7 @@ namespace rfb {
|
||||
|
||||
bool isShiftPressed();
|
||||
|
||||
bool getPerms(bool &write, bool &owner) const;
|
||||
bool getPerms(bool &read, bool &write, bool &owner) const;
|
||||
|
||||
bool checkOwnerConn() const;
|
||||
|
||||
|
||||
@@ -131,7 +131,8 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
|
||||
renderedCursorInvalid(false),
|
||||
queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
|
||||
lastConnectionTime(0), disableclients(false),
|
||||
frameTimer(this), apimessager(NULL), trackingFrameStats(0)
|
||||
frameTimer(this), apimessager(NULL), trackingFrameStats(0),
|
||||
clipboardId(0)
|
||||
{
|
||||
lastUserInputTime = lastDisconnectTime = time(0);
|
||||
slog.debug("creating single-threaded server %s", name.buf);
|
||||
@@ -539,8 +540,10 @@ void VNCServerST::sendBinaryClipboardData(const char* mime, const unsigned char
|
||||
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
||||
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
|
||||
ci_next = ci; ci_next++;
|
||||
(*ci)->sendBinaryClipboardDataOrClose(mime, data, len);
|
||||
(*ci)->sendBinaryClipboardDataOrClose(mime, data, len, clipboardId);
|
||||
}
|
||||
|
||||
clipboardId++;
|
||||
}
|
||||
|
||||
void VNCServerST::getBinaryClipboardData(const char* mime, const unsigned char **data,
|
||||
@@ -805,49 +808,11 @@ static void checkAPIMessages(network::GetAPIMessager *apimessager,
|
||||
slog.info("Main thread processing user API request %u/%u", i + 1, num);
|
||||
|
||||
const network::GetAPIMessager::action_data &act = apimessager->actionQueue[i];
|
||||
struct kasmpasswd_t *set = NULL;
|
||||
unsigned s;
|
||||
bool found;
|
||||
|
||||
switch (act.action) {
|
||||
case network::GetAPIMessager::USER_REMOVE:
|
||||
set = readkasmpasswd(kasmpasswdpath);
|
||||
found = false;
|
||||
for (s = 0; s < set->num; s++) {
|
||||
if (!strcmp(set->entries[s].user, act.data.user)) {
|
||||
set->entries[s].user[0] = '\0';
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
writekasmpasswd(kasmpasswdpath, set);
|
||||
slog.info("User %s removed", act.data.user);
|
||||
} else {
|
||||
slog.error("Tried to remove nonexistent user %s", act.data.user);
|
||||
}
|
||||
case network::GetAPIMessager::NONE:
|
||||
slog.info("Empty request (bug!)");
|
||||
break;
|
||||
case network::GetAPIMessager::USER_GIVE_CONTROL:
|
||||
set = readkasmpasswd(kasmpasswdpath);
|
||||
found = false;
|
||||
for (s = 0; s < set->num; s++) {
|
||||
if (!strcmp(set->entries[s].user, act.data.user)) {
|
||||
set->entries[s].write = 1;
|
||||
found = true;
|
||||
} else {
|
||||
set->entries[s].write = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
writekasmpasswd(kasmpasswdpath, set);
|
||||
slog.info("User %s given control", act.data.user);
|
||||
} else {
|
||||
slog.error("Tried to give control to nonexistent user %s", act.data.user);
|
||||
}
|
||||
break;
|
||||
|
||||
case network::GetAPIMessager::WANT_FRAME_STATS_SERVERONLY:
|
||||
trackingFrameStats = act.action;
|
||||
break;
|
||||
@@ -862,11 +827,6 @@ static void checkAPIMessages(network::GetAPIMessager *apimessager,
|
||||
memcpy(trackingClient, act.data.password, 128);
|
||||
break;
|
||||
}
|
||||
|
||||
if (set) {
|
||||
free(set->entries);
|
||||
free(set);
|
||||
}
|
||||
}
|
||||
|
||||
apimessager->actionQueue.clear();
|
||||
|
||||
@@ -281,6 +281,8 @@ namespace rfb {
|
||||
} DLPRegion;
|
||||
|
||||
void translateDLPRegion(rdr::U16 &x1, rdr::U16 &y1, rdr::U16 &x2, rdr::U16 &y2) const;
|
||||
|
||||
rdr::U32 clipboardId;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
2
debian/Makefile.to_fakebuild_tar_package
vendored
2
debian/Makefile.to_fakebuild_tar_package
vendored
@@ -16,12 +16,14 @@ install: unpack_tarball
|
||||
cp $(SRC_BIN)/vncserver $(DESTDIR)/usr/bin/kasmvncserver
|
||||
cp $(SRC_BIN)/vncconfig $(DESTDIR)/usr/bin/kasmvncconfig
|
||||
cp $(SRC_BIN)/kasmvncpasswd $(DESTDIR)/usr/bin/
|
||||
cp $(SRC_BIN)/kasmxproxy $(DESTDIR)/usr/bin/
|
||||
cp -r $(SRC)/share/doc/kasmvnc*/* $(DESTDIR)/usr/share/doc/kasmvncserver/
|
||||
rsync -r --exclude '.git*' --exclude po2js --exclude xgettext-html \
|
||||
--exclude www/utils/ --exclude .eslintrc \
|
||||
$(SRC)/share/kasmvnc $(DESTDIR)/usr/share
|
||||
cp $(SRC)/man/man1/Xvnc.1 $(DESTDIR)/usr/share/man/man1/Xkasmvnc.1
|
||||
cp $(SRC)/share/man/man1/vncserver.1 $(DST_MAN)/kasmvncserver.1
|
||||
cp $(SRC)/share/man/man1/kasmxproxy.1 $(DST_MAN)/kasmxproxy.1
|
||||
cp $(SRC)/share/man/man1/vncpasswd.1 $(DST_MAN)/kasmvncpasswd.1
|
||||
cp $(SRC)/share/man/man1/vncconfig.1 $(DST_MAN)/kasmvncconfig.1
|
||||
|
||||
|
||||
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -1,3 +1,9 @@
|
||||
kasmvnc (0.9.3~beta-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Kasm Technologies LLC <info@kasmweb.com> Tue, 22 Mar 2022 09:15:38 +0000
|
||||
|
||||
kasmvnc (0.9.1~beta-1) unstable; urgency=medium
|
||||
|
||||
* Initial release of the Debian package.
|
||||
|
||||
2
debian/control
vendored
2
debian/control
vendored
@@ -3,7 +3,7 @@ Section: x11
|
||||
Priority: optional
|
||||
Maintainer: Kasm Technologies LLC <info@kasmweb.com>
|
||||
Build-Depends: debhelper (>= 11), rsync, libjpeg-dev, libjpeg-dev, libpng-dev,
|
||||
libtiff-dev, libgif-dev, libavcodec-dev, libssl-dev, libgl1, libxfont2, libsm6, libunwind8
|
||||
libtiff-dev, libgif-dev, libavcodec-dev, libssl-dev, libgl1, libxfont2, libsm6, libxext-dev, libxrandr-dev, libxtst-dev, libxcursor-dev, libunwind8
|
||||
Standards-Version: 4.1.3
|
||||
Homepage: https://github.com/kasmtech/KasmVNC
|
||||
#Vcs-Browser: https://salsa.debian.org/debian/kasmvnc
|
||||
|
||||
2
debian/postinst
vendored
2
debian/postinst
vendored
@@ -21,7 +21,7 @@ case "$1" in
|
||||
configure)
|
||||
bindir=/usr/bin
|
||||
mandir=/usr/share/man
|
||||
commands="kasmvncserver kasmvncpasswd kasmvncconfig Xkasmvnc"
|
||||
commands="kasmvncserver kasmvncpasswd kasmvncconfig Xkasmvnc kasmxproxy"
|
||||
|
||||
for kasm_command in $commands; do
|
||||
generic_command=`echo "$kasm_command" | sed -e 's/kasm//'`;
|
||||
|
||||
2
debian/prerm
vendored
2
debian/prerm
vendored
@@ -21,7 +21,7 @@ case "$1" in
|
||||
remove)
|
||||
bindir=/usr/bin
|
||||
mandir=/usr/share/man
|
||||
commands="kasmvncserver kasmvncpasswd kasmvncconfig Xkasmvnc"
|
||||
commands="kasmvncserver kasmvncpasswd kasmvncconfig Xkasmvnc kasmxproxy"
|
||||
|
||||
for kasm_command in $commands; do
|
||||
generic_command=`echo "$kasm_command" | sed -e 's/kasm//'`;
|
||||
|
||||
4491
doc/rfbproto.rst
Normal file
4491
doc/rfbproto.rst
Normal file
File diff suppressed because it is too large
Load Diff
2
kasmweb
2
kasmweb
Submodule kasmweb updated: 9383783efd...43ab612108
108
opensuse/kasmvncserver.spec
Normal file
108
opensuse/kasmvncserver.spec
Normal file
@@ -0,0 +1,108 @@
|
||||
Name: kasmvncserver
|
||||
Version: 0.9.3~beta
|
||||
Release: leap15
|
||||
Summary: VNC server accessible from a web browser
|
||||
|
||||
License: GPLv2+
|
||||
URL: https://github.com/kasmtech/KasmVNC
|
||||
|
||||
BuildRequires: rsync
|
||||
Requires: xauth, libxkbcommon-x11-0, xkeyboard-config, x11-tools, openssl, perl, libpixman-1-0, libjpeg8, libgomp1, libXfont2-2, libXdmcp6, libglvnd, xkbcomp
|
||||
Conflicts: tigervnc, tigervnc-x11vnc
|
||||
|
||||
%description
|
||||
VNC stands for Virtual Network Computing. It is, in essence, a remote
|
||||
display system which allows you to view a computing `desktop' environment
|
||||
not only on the machine where it is running, but from anywhere on the
|
||||
Internet and from a wide variety of machine architectures.
|
||||
|
||||
KasmVNC has different goals than TigerVNC:
|
||||
|
||||
Web-based - KasmVNC is designed to provide a web accessible remote desktop.
|
||||
It comes with a web server and web-socket server built in. There is no need to
|
||||
install other components. Simply run and navigate to your desktop's URL on the
|
||||
port you specify. While you can still tun on the legacy VNC port, it is
|
||||
disabled by default.
|
||||
|
||||
Security - KasmVNC defaults to HTTPS and allows for HTTP Basic Auth. VNC
|
||||
Password authentication is limited by specification to 8 characters and is not
|
||||
sufficient for use on an internet accessible remote desktop. Our goal is to
|
||||
create a by default secure, web based experience.
|
||||
|
||||
Simplicity - KasmVNC aims at being simple to deploy and configure.
|
||||
|
||||
%prep
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
TARGET_OS=$KASMVNC_BUILD_OS
|
||||
TARGET_OS_CODENAME=$KASMVNC_BUILD_OS_CODENAME
|
||||
TARBALL=$RPM_SOURCE_DIR/kasmvnc.${TARGET_OS}_${TARGET_OS_CODENAME}.tar.gz
|
||||
TAR_DATA=$(mktemp -d)
|
||||
tar -xzf "$TARBALL" -C "$TAR_DATA"
|
||||
|
||||
SRC=$TAR_DATA/usr/local
|
||||
SRC_BIN=$SRC/bin
|
||||
DESTDIR=$RPM_BUILD_ROOT
|
||||
DST_MAN=$DESTDIR/usr/share/man/man1
|
||||
|
||||
mkdir -p $DESTDIR/usr/bin $DESTDIR/usr/share/man/man1 \
|
||||
$DESTDIR/usr/share/doc/kasmvncserver
|
||||
cp $SRC_BIN/Xvnc $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/vncserver $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/vncconfig $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/kasmvncpasswd $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/kasmxproxy $DESTDIR/usr/bin;
|
||||
cd $DESTDIR/usr/bin && ln -s kasmvncpasswd vncpasswd;
|
||||
cp -r $SRC/share/doc/kasmvnc*/* $DESTDIR/usr/share/doc/kasmvncserver/
|
||||
rsync -r --exclude '.git*' --exclude po2js --exclude xgettext-html \
|
||||
--exclude www/utils/ --exclude .eslintrc \
|
||||
$SRC/share/kasmvnc $DESTDIR/usr/share
|
||||
cp $SRC/man/man1/Xvnc.1 $DESTDIR/usr/share/man/man1/;
|
||||
cp $SRC/share/man/man1/vncserver.1 $DST_MAN;
|
||||
cp $SRC/share/man/man1/vncconfig.1 $DST_MAN;
|
||||
cp $SRC/share/man/man1/vncpasswd.1 $DST_MAN;
|
||||
cp $SRC/share/man/man1/kasmxproxy.1 $DST_MAN;
|
||||
cd $DST_MAN && ln -s vncpasswd.1 kasmvncpasswd.1;
|
||||
|
||||
|
||||
%files
|
||||
/usr/bin/*
|
||||
/usr/share/man/man1/*
|
||||
/usr/share/kasmvnc/www
|
||||
|
||||
%license /usr/share/doc/kasmvncserver/LICENSE.TXT
|
||||
%doc /usr/share/doc/kasmvncserver/README.md
|
||||
|
||||
%changelog
|
||||
* Tue Mar 22 2022 KasmTech <info@kasmweb.com> - 0.9.3~beta-1
|
||||
* Fri Feb 12 2021 KasmTech <info@kasmweb.com> - 0.9.1~beta-1
|
||||
- Initial release of the rpm package.
|
||||
|
||||
%post
|
||||
kasmvnc_group="kasmvnc-cert"
|
||||
|
||||
create_kasmvnc_group() {
|
||||
if ! getent group "$kasmvnc_group" >/dev/null; then
|
||||
groupadd --system "$kasmvnc_group"
|
||||
fi
|
||||
}
|
||||
|
||||
make_self_signed_certificate() {
|
||||
local cert_file=/etc/pki/tls/private/kasmvnc.pem
|
||||
[ -f "$cert_file" ] && return 0
|
||||
|
||||
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
|
||||
-keyout "$cert_file" \
|
||||
-out "$cert_file" -subj \
|
||||
"/C=US/ST=VA/L=None/O=None/OU=DoFu/CN=kasm/emailAddress=none@none.none"
|
||||
chgrp "$kasmvnc_group" "$cert_file"
|
||||
chmod 640 "$cert_file"
|
||||
}
|
||||
|
||||
create_kasmvnc_group
|
||||
make_self_signed_certificate
|
||||
|
||||
%postun
|
||||
rm -f /etc/pki/tls/private/kasmvnc.pem
|
||||
108
oracle/kasmvncserver.spec
Normal file
108
oracle/kasmvncserver.spec
Normal file
@@ -0,0 +1,108 @@
|
||||
Name: kasmvncserver
|
||||
Version: 0.9.3~beta
|
||||
Release: 1%{?dist}
|
||||
Summary: VNC server accessible from a web browser
|
||||
|
||||
License: GPLv2+
|
||||
URL: https://github.com/kasmtech/KasmVNC
|
||||
|
||||
BuildRequires: rsync
|
||||
Requires: xorg-x11-xauth, xorg-x11-xkb-utils, xkeyboard-config, xorg-x11-server-utils, openssl, perl
|
||||
Conflicts: tigervnc-server, tigervnc-server-minimal
|
||||
|
||||
%description
|
||||
VNC stands for Virtual Network Computing. It is, in essence, a remote
|
||||
display system which allows you to view a computing `desktop' environment
|
||||
not only on the machine where it is running, but from anywhere on the
|
||||
Internet and from a wide variety of machine architectures.
|
||||
|
||||
KasmVNC has different goals than TigerVNC:
|
||||
|
||||
Web-based - KasmVNC is designed to provide a web accessible remote desktop.
|
||||
It comes with a web server and web-socket server built in. There is no need to
|
||||
install other components. Simply run and navigate to your desktop's URL on the
|
||||
port you specify. While you can still tun on the legacy VNC port, it is
|
||||
disabled by default.
|
||||
|
||||
Security - KasmVNC defaults to HTTPS and allows for HTTP Basic Auth. VNC
|
||||
Password authentication is limited by specification to 8 characters and is not
|
||||
sufficient for use on an internet accessible remote desktop. Our goal is to
|
||||
create a by default secure, web based experience.
|
||||
|
||||
Simplicity - KasmVNC aims at being simple to deploy and configure.
|
||||
|
||||
%prep
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
TARGET_OS=$KASMVNC_BUILD_OS
|
||||
TARGET_OS_CODENAME=$KASMVNC_BUILD_OS_CODENAME
|
||||
TARBALL=$RPM_SOURCE_DIR/kasmvnc.${TARGET_OS}_${TARGET_OS_CODENAME}.tar.gz
|
||||
TAR_DATA=$(mktemp -d)
|
||||
tar -xzf "$TARBALL" -C "$TAR_DATA"
|
||||
|
||||
SRC=$TAR_DATA/usr/local
|
||||
SRC_BIN=$SRC/bin
|
||||
DESTDIR=$RPM_BUILD_ROOT
|
||||
DST_MAN=$DESTDIR/usr/share/man/man1
|
||||
|
||||
mkdir -p $DESTDIR/usr/bin $DESTDIR/usr/share/man/man1 \
|
||||
$DESTDIR/usr/share/doc/kasmvncserver
|
||||
cp $SRC_BIN/Xvnc $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/vncserver $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/vncconfig $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/kasmvncpasswd $DESTDIR/usr/bin;
|
||||
cp $SRC_BIN/kasmxproxy $DESTDIR/usr/bin;
|
||||
cd $DESTDIR/usr/bin && ln -s kasmvncpasswd vncpasswd;
|
||||
cp -r $SRC/share/doc/kasmvnc*/* $DESTDIR/usr/share/doc/kasmvncserver/
|
||||
rsync -r --exclude '.git*' --exclude po2js --exclude xgettext-html \
|
||||
--exclude www/utils/ --exclude .eslintrc \
|
||||
$SRC/share/kasmvnc $DESTDIR/usr/share
|
||||
cp $SRC/man/man1/Xvnc.1 $DESTDIR/usr/share/man/man1/;
|
||||
cp $SRC/share/man/man1/vncserver.1 $DST_MAN;
|
||||
cp $SRC/share/man/man1/vncconfig.1 $DST_MAN;
|
||||
cp $SRC/share/man/man1/vncpasswd.1 $DST_MAN;
|
||||
cp $SRC/share/man/man1/kasmxproxy.1 $DST_MAN;
|
||||
cd $DST_MAN && ln -s vncpasswd.1 kasmvncpasswd.1;
|
||||
|
||||
|
||||
%files
|
||||
/usr/bin/*
|
||||
/usr/share/man/man1/*
|
||||
/usr/share/kasmvnc/www
|
||||
|
||||
%license /usr/share/doc/kasmvncserver/LICENSE.TXT
|
||||
%doc /usr/share/doc/kasmvncserver/README.md
|
||||
|
||||
%changelog
|
||||
* Tue Mar 22 2022 KasmTech <info@kasmweb.com> - 0.9.3~beta-1
|
||||
* Fri Feb 12 2021 KasmTech <info@kasmweb.com> - 0.9.1~beta-1
|
||||
- Initial release of the rpm package.
|
||||
|
||||
%post
|
||||
kasmvnc_group="kasmvnc-cert"
|
||||
|
||||
create_kasmvnc_group() {
|
||||
if ! getent group "$kasmvnc_group" >/dev/null; then
|
||||
groupadd --system "$kasmvnc_group"
|
||||
fi
|
||||
}
|
||||
|
||||
make_self_signed_certificate() {
|
||||
local cert_file=/etc/pki/tls/private/kasmvnc.pem
|
||||
[ -f "$cert_file" ] && return 0
|
||||
|
||||
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
|
||||
-keyout "$cert_file" \
|
||||
-out "$cert_file" -subj \
|
||||
"/C=US/ST=VA/L=None/O=None/OU=DoFu/CN=kasm/emailAddress=none@none.none"
|
||||
chgrp "$kasmvnc_group" "$cert_file"
|
||||
chmod 640 "$cert_file"
|
||||
}
|
||||
|
||||
create_kasmvnc_group
|
||||
make_self_signed_certificate
|
||||
|
||||
%postun
|
||||
rm -f /etc/pki/tls/private/kasmvnc.pem
|
||||
@@ -45,6 +45,7 @@ mkdir -p $OUTDIR/man/man1
|
||||
|
||||
make DESTDIR=$TMPDIR/inst install
|
||||
if [ $SERVER = 1 ]; then
|
||||
install -m 755 ./unix/kasmxproxy/kasmxproxy $OUTDIR/bin/
|
||||
install -m 755 ./xorg.build/bin/Xvnc $OUTDIR/bin/
|
||||
install -m 644 ./xorg.build/man/man1/Xvnc.1 $OUTDIR/man/man1/Xvnc.1
|
||||
install -m 644 ./xorg.build/man/man1/Xserver.1 $OUTDIR/man/man1/Xserver.1
|
||||
|
||||
@@ -3,6 +3,7 @@ add_subdirectory(common)
|
||||
add_subdirectory(vncconfig)
|
||||
add_subdirectory(vncpasswd)
|
||||
add_subdirectory(kasmvncpasswd)
|
||||
add_subdirectory(kasmxproxy)
|
||||
|
||||
install(PROGRAMS vncserver DESTINATION ${BIN_DIR})
|
||||
install(FILES vncserver.man DESTINATION ${MAN_DIR}/man1 RENAME vncserver.1)
|
||||
|
||||
39
unix/kasm-upload-crash-dump.sh
Executable file
39
unix/kasm-upload-crash-dump.sh
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
|
||||
URL=https://to-be-filled.com/path
|
||||
|
||||
die() {
|
||||
echo "$@"
|
||||
exit
|
||||
}
|
||||
|
||||
[ "$#" -ne 1 ] && die "Usage: $0 logfile"
|
||||
|
||||
grep -q Backtrace: $1 || die "No crash in log file"
|
||||
|
||||
CURL=`which curl`
|
||||
WGET=`which wget`
|
||||
|
||||
[ -n "$CURL" -o -n "$WGET" ] || die "Curl or wget required"
|
||||
|
||||
BIN=`grep vnc $1 | tail -n1 | cut -d: -f2 | cut -d\( -f1`
|
||||
[ -f $BIN ] || die "Can't locate binary"
|
||||
|
||||
#
|
||||
# prep done, filter the log file
|
||||
#
|
||||
|
||||
TMP=`mktemp`
|
||||
|
||||
LANG=C date >> $TMP
|
||||
md5sum $BIN >> $TMP
|
||||
$BIN -version 2>&1 | grep built >> $TMP
|
||||
grep -A200 Backtrace: $1 >> $TMP
|
||||
|
||||
if [ -n "$CURL" ]; then
|
||||
echo curl --data-binary @"$TMP" "$URL"
|
||||
else
|
||||
echo wget --post-file "$TMP" "$URL"
|
||||
fi
|
||||
|
||||
rm $TMP
|
||||
@@ -60,6 +60,8 @@ struct kasmpasswd_t *readkasmpasswd(const char path[]) {
|
||||
strcpy(set->entries[cur].user, buf);
|
||||
strcpy(set->entries[cur].password, pw);
|
||||
|
||||
if (strchr(perms, 'r'))
|
||||
set->entries[cur].read = 1;
|
||||
if (strchr(perms, 'w'))
|
||||
set->entries[cur].write = 1;
|
||||
if (strchr(perms, 'o'))
|
||||
@@ -90,22 +92,17 @@ void writekasmpasswd(const char path[], const struct kasmpasswd_t *set) {
|
||||
return;
|
||||
}
|
||||
|
||||
static const char * const perms[] = {
|
||||
"",
|
||||
"w",
|
||||
"o",
|
||||
"ow"
|
||||
};
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < set->num; i++) {
|
||||
if (!set->entries[i].user[0])
|
||||
continue;
|
||||
|
||||
fprintf(f, "%s:%s:%s\n",
|
||||
fprintf(f, "%s:%s:%s%s%s\n",
|
||||
set->entries[i].user,
|
||||
set->entries[i].password,
|
||||
perms[set->entries[i].owner * 2 + set->entries[i].write]);
|
||||
set->entries[i].read ? "r" : "",
|
||||
set->entries[i].write ? "w" : "",
|
||||
set->entries[i].owner ? "o" : "");
|
||||
}
|
||||
|
||||
fsync(fileno(f));
|
||||
|
||||
@@ -8,10 +8,14 @@ extern "C" {
|
||||
struct kasmpasswd_entry_t {
|
||||
char user[32];
|
||||
char password[128];
|
||||
unsigned char read : 1;
|
||||
unsigned char write : 1;
|
||||
unsigned char owner : 1;
|
||||
};
|
||||
|
||||
#define USERNAME_LEN sizeof(((struct kasmpasswd_entry_t *)0)->user)
|
||||
#define PASSWORD_LEN sizeof(((struct kasmpasswd_entry_t *)0)->password)
|
||||
|
||||
struct kasmpasswd_t {
|
||||
struct kasmpasswd_entry_t *entries;
|
||||
unsigned num;
|
||||
|
||||
@@ -33,13 +33,15 @@
|
||||
|
||||
static void usage(const char *prog)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s -u username [-wnod] [file]\n"
|
||||
fprintf(stderr, "Usage: %s -u username [-wnod] [password_file]\n"
|
||||
"-r Read permission\n"
|
||||
"-w Write permission\n"
|
||||
"-o Owner\n"
|
||||
"-n Don't change password, change permissions only\n"
|
||||
"-d Delete this user\n"
|
||||
"\n"
|
||||
"The file is updated atomically.\n\n"
|
||||
"The password file is updated atomically.\n"
|
||||
"For more information, run \"man vncpasswd\".\n\n"
|
||||
"To pass the password via a pipe, use\n"
|
||||
"echo -e \"password\\npassword\\n\" | %s [-args]\n",
|
||||
prog, prog);
|
||||
@@ -118,10 +120,10 @@ int main(int argc, char** argv)
|
||||
{
|
||||
const char *fname = NULL;
|
||||
const char *user = NULL;
|
||||
const char args[] = "u:wnod";
|
||||
const char args[] = "u:rwnod";
|
||||
int opt;
|
||||
|
||||
unsigned char nopass = 0, writer = 0, owner = 0, deleting = 0;
|
||||
unsigned char nopass = 0, reader = 0, writer = 0, owner = 0, deleting = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, args)) != -1) {
|
||||
switch (opt) {
|
||||
@@ -135,6 +137,9 @@ int main(int argc, char** argv)
|
||||
case 'n':
|
||||
nopass = 1;
|
||||
break;
|
||||
case 'r':
|
||||
reader = 1;
|
||||
break;
|
||||
case 'w':
|
||||
writer = 1;
|
||||
break;
|
||||
@@ -150,7 +155,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (deleting && (nopass || writer || owner))
|
||||
if (deleting && (nopass || reader || writer || owner))
|
||||
usage(argv[0]);
|
||||
|
||||
if (!user)
|
||||
@@ -175,6 +180,7 @@ int main(int argc, char** argv)
|
||||
if (nopass) {
|
||||
for (i = 0; i < set->num; i++) {
|
||||
if (!strcmp(set->entries[i].user, user)) {
|
||||
set->entries[i].read = reader;
|
||||
set->entries[i].write = writer;
|
||||
set->entries[i].owner = owner;
|
||||
|
||||
@@ -211,6 +217,7 @@ int main(int argc, char** argv)
|
||||
|
||||
strcpy(set->entries[i].user, user);
|
||||
strcpy(set->entries[i].password, encrypted);
|
||||
set->entries[i].read = reader;
|
||||
set->entries[i].write = writer;
|
||||
set->entries[i].owner = owner;
|
||||
|
||||
|
||||
1
unix/kasmxproxy/.gitignore
vendored
Normal file
1
unix/kasmxproxy/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
kasmxproxy
|
||||
11
unix/kasmxproxy/CMakeLists.txt
Normal file
11
unix/kasmxproxy/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
include_directories(${X11_INCLUDE_DIR})
|
||||
|
||||
add_executable(kasmxproxy
|
||||
xxhash.c
|
||||
kasmxproxy.c)
|
||||
|
||||
target_link_libraries(kasmxproxy ${X11_LIBRARIES} ${X11_XTest_LIB} ${X11_Xrandr_LIB}
|
||||
${X11_Xcursor_LIB} ${X11_Xfixes_LIB})
|
||||
|
||||
install(TARGETS kasmxproxy DESTINATION ${BIN_DIR})
|
||||
install(FILES kasmxproxy.man DESTINATION ${MAN_DIR}/man1 RENAME kasmxproxy.1)
|
||||
530
unix/kasmxproxy/kasmxproxy.c
Normal file
530
unix/kasmxproxy/kasmxproxy.c
Normal file
@@ -0,0 +1,530 @@
|
||||
/* Copyright (C) 2021 Kasm. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <unistd.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
#include <X11/extensions/XTest.h>
|
||||
|
||||
#include "xxhash.h"
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
static void help(const char name[]) {
|
||||
printf("Usage: %s [opts]\n\n"
|
||||
"-a --app-display disp App display, default :0\n"
|
||||
"-v --vnc-display disp VNC display, default :1\n"
|
||||
"\n"
|
||||
"-f --fps fps FPS, default 30\n"
|
||||
"-r --resize Enable resize, default disabled.\n"
|
||||
" Do not enable this if there's a physical screen\n"
|
||||
" connected to the app display.\n",
|
||||
name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#define CUT_MAX (16 * 1024)
|
||||
static uint8_t cutbuf[CUT_MAX];
|
||||
|
||||
static void supplyselection(Display *disp, const XEvent * const ev, const Atom xa_targets) {
|
||||
XSelectionEvent sev;
|
||||
|
||||
sev.type = SelectionNotify;
|
||||
sev.display = disp;
|
||||
sev.requestor = ev->xselectionrequest.requestor;
|
||||
sev.selection = ev->xselectionrequest.selection;
|
||||
sev.target = ev->xselectionrequest.target;
|
||||
sev.time = ev->xselectionrequest.time;
|
||||
/*printf("someone wants our clipboard, sel %lu, tgt %lu, prop %lu\n",
|
||||
sev.selection, sev.target,
|
||||
ev.xselectionrequest.property);*/
|
||||
|
||||
if (ev->xselectionrequest.property == None)
|
||||
sev.property = sev.target;
|
||||
else
|
||||
sev.property = ev->xselectionrequest.property;
|
||||
|
||||
const uint32_t len = strlen((char *) cutbuf);
|
||||
|
||||
if (xa_targets != None &&
|
||||
sev.target == xa_targets) {
|
||||
// Which formats can we do
|
||||
Atom tgt[2] = {
|
||||
xa_targets,
|
||||
XA_STRING
|
||||
};
|
||||
|
||||
XChangeProperty(disp, sev.requestor,
|
||||
ev->xselectionrequest.property,
|
||||
XA_ATOM, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char *) tgt,
|
||||
2);
|
||||
//puts("sent targets");
|
||||
} else {
|
||||
// Data
|
||||
XChangeProperty(disp, sev.requestor,
|
||||
ev->xselectionrequest.property,
|
||||
sev.target, 8,
|
||||
PropModeReplace,
|
||||
cutbuf, len);
|
||||
//printf("sent data, of len %u\n", len);
|
||||
}
|
||||
|
||||
// Send the notify event
|
||||
XSendEvent(disp, sev.requestor, False, 0,
|
||||
(XEvent *) &sev);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
const char *appstr = ":0";
|
||||
const char *vncstr = ":1";
|
||||
uint8_t resize = 0;
|
||||
uint8_t fps = 30;
|
||||
|
||||
const struct option longargs[] = {
|
||||
{"app-display", 1, NULL, 'a'},
|
||||
{"vnc-display", 1, NULL, 'v'},
|
||||
{"resize", 0, NULL, 'r'},
|
||||
{"fps", 1, NULL, 'f'},
|
||||
|
||||
{NULL, 0, NULL, 0},
|
||||
};
|
||||
|
||||
while (1) {
|
||||
int c = getopt_long(argc, argv, "a:v:rf:", longargs, NULL);
|
||||
if (c == -1)
|
||||
break;
|
||||
switch (c) {
|
||||
case 'a':
|
||||
appstr = strdup(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
vncstr = strdup(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
resize = 1;
|
||||
break;
|
||||
case 'f':
|
||||
fps = atoi(optarg);
|
||||
if (fps < 1 || fps > 120) {
|
||||
printf("Invalid fps\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
help(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Display *appdisp = XOpenDisplay(appstr);
|
||||
if (!appdisp) {
|
||||
printf("Cannot open display %s\n", appstr);
|
||||
return 1;
|
||||
}
|
||||
if (!XShmQueryExtension(appdisp)) {
|
||||
printf("Display %s lacks SHM extension\n", appstr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Display *vncdisp = XOpenDisplay(vncstr);
|
||||
if (!vncdisp) {
|
||||
printf("Cannot open display %s\n", vncstr);
|
||||
return 1;
|
||||
}
|
||||
if (!XShmQueryExtension(vncdisp)) {
|
||||
printf("Display %s lacks SHM extension\n", vncstr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const int appscreen = DefaultScreen(appdisp);
|
||||
const int vncscreen = DefaultScreen(vncdisp);
|
||||
Visual *appvis = DefaultVisual(appdisp, appscreen);
|
||||
//Visual *vncvis = DefaultVisual(vncdisp, vncscreen);
|
||||
const int appdepth = DefaultDepth(appdisp, appscreen);
|
||||
const int vncdepth = DefaultDepth(vncdisp, vncscreen);
|
||||
if (appdepth != vncdepth) {
|
||||
printf("Depths don't match, app %u vnc %u\n", appdepth, vncdepth);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Window approot = DefaultRootWindow(appdisp);
|
||||
Window vncroot = DefaultRootWindow(vncdisp);
|
||||
XWindowAttributes appattr, vncattr;
|
||||
|
||||
XGCValues gcval;
|
||||
gcval.plane_mask = AllPlanes;
|
||||
gcval.function = GXcopy;
|
||||
GC gc = XCreateGC(vncdisp, vncroot, GCFunction | GCPlaneMask, &gcval);
|
||||
|
||||
XImage *img = NULL;
|
||||
XShmSegmentInfo shminfo;
|
||||
unsigned imgw = 0, imgh = 0;
|
||||
|
||||
if (XGrabPointer(vncdisp, vncroot, False,
|
||||
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
|
||||
GrabModeAsync, GrabModeAsync, None, None,
|
||||
CurrentTime) != Success)
|
||||
return 1;
|
||||
if (XGrabKeyboard(vncdisp, vncroot, False, GrabModeAsync, GrabModeAsync,
|
||||
CurrentTime) != Success)
|
||||
return 1;
|
||||
|
||||
int xfixesbase, xfixeserrbase;
|
||||
XFixesQueryExtension(appdisp, &xfixesbase, &xfixeserrbase);
|
||||
XFixesSelectSelectionInput(appdisp, approot, XA_PRIMARY,
|
||||
XFixesSetSelectionOwnerNotifyMask);
|
||||
|
||||
int xfixesbasevnc, xfixeserrbasevnc;
|
||||
XFixesQueryExtension(vncdisp, &xfixesbasevnc, &xfixeserrbasevnc);
|
||||
XFixesSelectSelectionInput(vncdisp, vncroot, XA_PRIMARY,
|
||||
XFixesSetSelectionOwnerNotifyMask);
|
||||
|
||||
Atom xa_targets_vnc = XInternAtom(vncdisp, "TARGETS", False);
|
||||
Atom xa_targets_app = XInternAtom(appdisp, "TARGETS", False);
|
||||
Window selwin = XCreateSimpleWindow(appdisp, approot, 3, 2, 1, 1, 0, 0, 0);
|
||||
Window vncselwin = XCreateSimpleWindow(vncdisp, vncroot, 3, 2, 1, 1, 0, 0, 0);
|
||||
|
||||
XFixesCursorImage *cursor = NULL;
|
||||
uint64_t cursorhash = 0;
|
||||
Cursor xcursor = None;
|
||||
|
||||
const unsigned sleeptime = 1000 * 1000 / fps;
|
||||
|
||||
while (1) {
|
||||
if (!XGetWindowAttributes(appdisp, approot, &appattr))
|
||||
break;
|
||||
if (!XGetWindowAttributes(vncdisp, vncroot, &vncattr))
|
||||
break;
|
||||
if (resize && (appattr.width != vncattr.width ||
|
||||
appattr.height != vncattr.height)) {
|
||||
// resize app display to VNC display size
|
||||
XRRScreenConfiguration *config = XRRGetScreenInfo(appdisp, approot);
|
||||
|
||||
int nsizes, i, match = -1;
|
||||
XRRScreenSize *sizes = XRRConfigSizes(config, &nsizes);
|
||||
//printf("%u sizes\n", nsizes);
|
||||
for (i = 0; i < nsizes; i++) {
|
||||
if (sizes[i].width == vncattr.width &&
|
||||
sizes[i].height == vncattr.height) {
|
||||
//printf("match %u\n", i);
|
||||
match = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match >= 0) {
|
||||
XRRSetScreenConfig(appdisp, config, approot, match,
|
||||
RR_Rotate_0, CurrentTime);
|
||||
} else {
|
||||
/*XRRSetScreenSize(appdisp, approot,
|
||||
vncattr.width, vncattr.height,
|
||||
sizes[0].mwidth, sizes[0].mheight);*/
|
||||
XRRScreenResources *res = XRRGetScreenResources(appdisp, approot);
|
||||
//printf("%u outputs, %u crtcs\n", res->noutput, res->ncrtc);
|
||||
// Nvidia crap uses a *different* list for 1.0 and 1.2!
|
||||
unsigned oldmode = 0xffff;
|
||||
//printf("1.2 modes %u\n", res->nmode);
|
||||
for (i = 0; i < res->nmode; i++) {
|
||||
if (res->modes[i].width == vncattr.width &&
|
||||
res->modes[i].height == vncattr.height) {
|
||||
oldmode = i;
|
||||
//printf("old mode %u matched\n", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned tgt = 0;
|
||||
if (res->noutput > 1) {
|
||||
for (i = 0; i < res->noutput; i++) {
|
||||
XRROutputInfo *info = XRRGetOutputInfo(appdisp, res, res->outputs[i]);
|
||||
if (info->connection == RR_Connected)
|
||||
tgt = i;
|
||||
//printf("%u %s %u\n", i, info->name, info->connection);
|
||||
XRRFreeOutputInfo(info);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldmode < 0xffff) {
|
||||
Status s;
|
||||
// nvidia needs this weird dance
|
||||
s = XRRSetCrtcConfig(appdisp, res, res->crtcs[tgt],
|
||||
CurrentTime,
|
||||
0, 0,
|
||||
None, RR_Rotate_0,
|
||||
NULL, 0);
|
||||
//printf("disable %u\n", s);
|
||||
XRRSetScreenSize(appdisp, approot,
|
||||
vncattr.width, vncattr.height,
|
||||
sizes[0].mwidth, sizes[0].mheight);
|
||||
s = XRRSetCrtcConfig(appdisp, res, res->crtcs[tgt],
|
||||
CurrentTime,
|
||||
0, 0,
|
||||
res->modes[oldmode].id, RR_Rotate_0,
|
||||
&res->outputs[tgt], 1);
|
||||
//printf("set %u\n", s);
|
||||
} else {
|
||||
char name[32];
|
||||
sprintf(name, "%ux%u_60", vncattr.width, vncattr.height);
|
||||
printf("Creating new Mode %s\n", name);
|
||||
XRRModeInfo *mode = XRRAllocModeInfo(name, strlen(name));
|
||||
|
||||
mode->width = vncattr.width;
|
||||
mode->height = vncattr.height;
|
||||
|
||||
RRMode rmode = XRRCreateMode(appdisp, approot, mode);
|
||||
XRRAddOutputMode(appdisp,
|
||||
res->outputs[tgt],
|
||||
rmode);
|
||||
XRRFreeModeInfo(mode);
|
||||
}
|
||||
|
||||
XRRFreeScreenResources(res);
|
||||
}
|
||||
|
||||
XRRFreeScreenConfigInfo(config);
|
||||
}
|
||||
|
||||
const unsigned w = min(appattr.width, vncattr.width);
|
||||
const unsigned h = min(appattr.height, vncattr.height);
|
||||
|
||||
if (w != imgw || h != imgh) {
|
||||
if (img) {
|
||||
XShmDetach(appdisp, &shminfo);
|
||||
XDestroyImage(img);
|
||||
shmdt(shminfo.shmaddr);
|
||||
shmctl(shminfo.shmid, IPC_RMID, NULL);
|
||||
}
|
||||
img = XShmCreateImage(appdisp, appvis, appdepth, ZPixmap,
|
||||
NULL, &shminfo, w, h);
|
||||
if (!img)
|
||||
break;
|
||||
|
||||
shminfo.shmid = shmget(IPC_PRIVATE,
|
||||
img->bytes_per_line * img->height,
|
||||
IPC_CREAT | 0666);
|
||||
if (shminfo.shmid == -1)
|
||||
break;
|
||||
shminfo.shmaddr = img->data = shmat(shminfo.shmid, 0, 0);
|
||||
shminfo.readOnly = False;
|
||||
if (!XShmAttach(appdisp, &shminfo))
|
||||
break;
|
||||
|
||||
imgw = w;
|
||||
imgh = h;
|
||||
}
|
||||
|
||||
XShmGetImage(appdisp, approot, img, 0, 0, 0xffffffff);
|
||||
XPutImage(vncdisp, vncroot, gc, img, 0, 0, 0, 0, w, h);
|
||||
|
||||
// Handle events
|
||||
while (XPending(vncdisp)) {
|
||||
XEvent ev;
|
||||
XNextEvent(vncdisp, &ev);
|
||||
|
||||
if (ev.type == xfixesbasevnc + XFixesSelectionNotify) {
|
||||
XFixesSelectionNotifyEvent *xfe =
|
||||
(XFixesSelectionNotifyEvent *) &ev;
|
||||
// printf("vnc disp did a copy, owner %lu, root %lu\n",
|
||||
// xfe->owner, vncroot);
|
||||
if (xfe->owner == None || xfe->owner == vncroot)
|
||||
continue;
|
||||
|
||||
XConvertSelection(vncdisp, XA_PRIMARY, XA_STRING, XA_STRING,
|
||||
vncselwin, CurrentTime);
|
||||
} else switch (ev.type) {
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
XTestFakeKeyEvent(appdisp, ev.xkey.keycode,
|
||||
ev.type == KeyPress,
|
||||
CurrentTime);
|
||||
break;
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
XTestFakeButtonEvent(appdisp, ev.xbutton.button,
|
||||
ev.type == ButtonPress,
|
||||
CurrentTime);
|
||||
break;
|
||||
case MotionNotify:
|
||||
XTestFakeMotionEvent(appdisp, appscreen,
|
||||
ev.xmotion.x,
|
||||
ev.xmotion.y,
|
||||
CurrentTime);
|
||||
break;
|
||||
case SelectionRequest:
|
||||
supplyselection(vncdisp, &ev, xa_targets_vnc);
|
||||
break;
|
||||
case SelectionNotify:
|
||||
{
|
||||
Atom realtype;
|
||||
int fmt;
|
||||
unsigned long nitems, bytes_rem;
|
||||
unsigned char *data;
|
||||
if (XGetWindowProperty(vncdisp, vncselwin,
|
||||
XA_STRING,
|
||||
0, CUT_MAX / 4,
|
||||
False, AnyPropertyType,
|
||||
&realtype, &fmt,
|
||||
&nitems, &bytes_rem,
|
||||
&data) == Success) {
|
||||
|
||||
if (bytes_rem) {
|
||||
printf("Clipboard too large, ignoring\n");
|
||||
} else {
|
||||
const uint32_t len = nitems * (fmt / 8);
|
||||
//printf("realtype %lu, fmt %u, nitems %lu\n",
|
||||
// realtype, fmt, nitems);
|
||||
memcpy(cutbuf, data, len);
|
||||
if (len < CUT_MAX)
|
||||
cutbuf[len] = 0;
|
||||
else
|
||||
cutbuf[CUT_MAX - 1] = 0;
|
||||
|
||||
// Send it to the app screen
|
||||
XSetSelectionOwner(appdisp, XA_PRIMARY,
|
||||
approot,
|
||||
CurrentTime);
|
||||
}
|
||||
|
||||
XFree(data);
|
||||
} else {
|
||||
printf("Failed to fetch vnc clipboard\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SelectionClear:
|
||||
cutbuf[0] = '\0';
|
||||
XSetSelectionOwner(appdisp, XA_PRIMARY, None,
|
||||
CurrentTime);
|
||||
break;
|
||||
default:
|
||||
printf("Unexpected event type %u\n", ev.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// App-side events
|
||||
while (XPending(appdisp)) {
|
||||
XEvent ev;
|
||||
XNextEvent(appdisp, &ev);
|
||||
|
||||
if (ev.type == xfixesbase + XFixesSelectionNotify) {
|
||||
XFixesSelectionNotifyEvent *xfe =
|
||||
(XFixesSelectionNotifyEvent *) &ev;
|
||||
//printf("app disp did a copy, owner %lu\n", xfe->owner);
|
||||
if (xfe->owner == None || xfe->owner == approot)
|
||||
continue;
|
||||
|
||||
XConvertSelection(appdisp, XA_PRIMARY, XA_STRING, XA_STRING,
|
||||
selwin, CurrentTime);
|
||||
} else switch (ev.type) {
|
||||
case SelectionNotify:
|
||||
{
|
||||
Atom realtype;
|
||||
int fmt;
|
||||
unsigned long nitems, bytes_rem;
|
||||
unsigned char *data;
|
||||
if (XGetWindowProperty(appdisp, selwin,
|
||||
XA_STRING,
|
||||
0, CUT_MAX / 4,
|
||||
False, AnyPropertyType,
|
||||
&realtype, &fmt,
|
||||
&nitems, &bytes_rem,
|
||||
&data) == Success) {
|
||||
|
||||
if (bytes_rem) {
|
||||
printf("Clipboard too large, ignoring\n");
|
||||
} else {
|
||||
const uint32_t len = nitems * (fmt / 8);
|
||||
//printf("realtype %lu, fmt %u, nitems %lu\n",
|
||||
// realtype, fmt, nitems);
|
||||
memcpy(cutbuf, data, len);
|
||||
if (len < CUT_MAX)
|
||||
cutbuf[len] = 0;
|
||||
else
|
||||
cutbuf[CUT_MAX - 1] = 0;
|
||||
|
||||
// Send it to the VNC screen
|
||||
XSetSelectionOwner(vncdisp, XA_PRIMARY,
|
||||
vncroot,
|
||||
CurrentTime);
|
||||
}
|
||||
|
||||
XFree(data);
|
||||
} else {
|
||||
printf("Failed to fetch app clipboard\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SelectionRequest:
|
||||
supplyselection(appdisp, &ev, xa_targets_app);
|
||||
break;
|
||||
default:
|
||||
printf("Unexpected app event type %u\n", ev.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cursors
|
||||
cursor = XFixesGetCursorImage(appdisp);
|
||||
uint64_t newhash = XXH64(cursor->pixels,
|
||||
cursor->width * cursor->height * sizeof(unsigned long),
|
||||
0);
|
||||
if (cursorhash != newhash) {
|
||||
if (cursorhash)
|
||||
XFreeCursor(vncdisp, xcursor);
|
||||
|
||||
XcursorImage *converted = XcursorImageCreate(cursor->width, cursor->height);
|
||||
|
||||
converted->xhot = cursor->xhot;
|
||||
converted->yhot = cursor->yhot;
|
||||
unsigned i;
|
||||
for (i = 0; i < cursor->width * cursor->height; i++) {
|
||||
converted->pixels[i] = cursor->pixels[i];
|
||||
}
|
||||
|
||||
xcursor = XcursorImageLoadCursor(vncdisp, converted);
|
||||
XDefineCursor(vncdisp, vncroot, xcursor);
|
||||
|
||||
XcursorImageDestroy(converted);
|
||||
|
||||
cursorhash = newhash;
|
||||
}
|
||||
|
||||
usleep(sleeptime);
|
||||
}
|
||||
|
||||
XCloseDisplay(appdisp);
|
||||
XCloseDisplay(vncdisp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
46
unix/kasmxproxy/kasmxproxy.man
Normal file
46
unix/kasmxproxy/kasmxproxy.man
Normal file
@@ -0,0 +1,46 @@
|
||||
.TH kasmxproxy 1 "" "KasmVNC" "Virtual Network Computing"
|
||||
.SH NAME
|
||||
kasmxproxy \- proxy an existing X11 display to a KasmVNC display
|
||||
.SH SYNOPSIS
|
||||
.B kasmxproxy
|
||||
.RB [ \-a|\-\-app\-display
|
||||
.IR source\-display ]
|
||||
.RB [ \-v|\-\-vnc\-display
|
||||
.IR destination\-display ]
|
||||
.RB [ \-f|\-\-fps
|
||||
.IR FPS ]
|
||||
.RB [ \-r|\-\-resize ]
|
||||
.br
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B kasmxproxy
|
||||
is used to proxy an x display, usually attached to a physical GPU, to KasmVNC display. This is usually used in the context of providing GPU acceleration to a KasmVNC session.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-a, \-\-app\-display \fIsource-display\fP
|
||||
Existing X display to proxy.
|
||||
Defaults to :0.
|
||||
|
||||
.TP
|
||||
.B \-v, \-\-vnc\-display \fIdestination-display\fP
|
||||
X display, where source display will be available on.
|
||||
Defaults to :1.
|
||||
|
||||
.TP
|
||||
.B \-f, \-\-fps \fIframes-per-second\fP
|
||||
X display, where the source display will be available on.
|
||||
Defaults to 30 frames per second.
|
||||
|
||||
.TP
|
||||
.B \-r|\-\-resize
|
||||
Enable resizing. WARNING: DO NOT ENABLE IF PHYSICAL DISPLAY IS ATTACHED.
|
||||
Disabled by default.
|
||||
|
||||
.SH EXAMPLES
|
||||
.TP
|
||||
.BI "kasmxproxy -a :1 -v :10 -r"
|
||||
.B Proxy display :1 to display :10, with resizing on.
|
||||
|
||||
.SH AUTHOR
|
||||
Kasm Technologies http://kasmweb.com
|
||||
1
unix/kasmxproxy/xxhash.c
Symbolic link
1
unix/kasmxproxy/xxhash.c
Symbolic link
@@ -0,0 +1 @@
|
||||
../../common/rfb/xxhash.c
|
||||
1
unix/kasmxproxy/xxhash.h
Symbolic link
1
unix/kasmxproxy/xxhash.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../../common/rfb/xxhash.h
|
||||
@@ -281,7 +281,7 @@ $kasmAuthEnabled = 1;
|
||||
|
||||
if ($kasmAuthEnabled) {
|
||||
if (!(-e "$ENV{HOME}/.kasmpasswd")) {
|
||||
warn "\nYou will require a password to access your desktops.\n\n";
|
||||
warn "\nYou need to create a KasmVNC user to access your desktops.\n\n";
|
||||
system($exedir."kasmvncpasswd $ENV{HOME}/.kasmpasswd");
|
||||
if (($? >> 8) != 0) {
|
||||
exit 1;
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "xkbsrv.h"
|
||||
#include "xkbstr.h"
|
||||
#include "xserver-properties.h"
|
||||
#include "stdbool.h"
|
||||
extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey;
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/Xlib.h>
|
||||
@@ -66,6 +67,8 @@ static const unsigned short *codeMap;
|
||||
static unsigned int codeMapLen;
|
||||
|
||||
static KeySym pressedKeys[256];
|
||||
static unsigned int needFree[256];
|
||||
static bool freeKeys;
|
||||
|
||||
static int vncPointerProc(DeviceIntPtr pDevice, int onoff);
|
||||
static void vncKeyboardBell(int percent, DeviceIntPtr device,
|
||||
@@ -91,7 +94,7 @@ static void vncKeysymKeyboardEvent(KeySym keysym, int down);
|
||||
* Instead we call it from XserverDesktop at an appropriate
|
||||
* time.
|
||||
*/
|
||||
void vncInitInputDevice(void)
|
||||
void vncInitInputDevice(bool freeKeyMappings)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
@@ -110,6 +113,8 @@ void vncInitInputDevice(void)
|
||||
codeMap = code_map_qnum_to_xorgkbd;
|
||||
codeMapLen = code_map_qnum_to_xorgkbd_len;
|
||||
#endif
|
||||
freeKeys = freeKeyMappings;
|
||||
memset(needFree, 0, sizeof(needFree));
|
||||
|
||||
for (i = 0;i < 256;i++)
|
||||
pressedKeys[i] = NoSymbol;
|
||||
@@ -234,6 +239,40 @@ void vncPointerMove(int x, int y)
|
||||
cursorPosY = y;
|
||||
}
|
||||
|
||||
void vncPointerMoveRelative(int x, int y, int absx, int absy)
|
||||
{
|
||||
int valuators[2];
|
||||
#if XORG < 111
|
||||
int n;
|
||||
#endif
|
||||
#if XORG >= 110
|
||||
ValuatorMask mask;
|
||||
#endif
|
||||
|
||||
// if (cursorPosX == absx && cursorPosY == absy)
|
||||
// return;
|
||||
|
||||
valuators[0] = x;
|
||||
valuators[1] = y;
|
||||
#if XORG < 110
|
||||
n = GetPointerEvents(eventq, vncPointerDev, MotionNotify, 0,
|
||||
POINTER_RELATIVE, 0, 2, valuators);
|
||||
enqueueEvents(vncPointerDev, n);
|
||||
#elif XORG < 111
|
||||
valuator_mask_set_range(&mask, 0, 2, valuators);
|
||||
n = GetPointerEvents(eventq, vncPointerDev, MotionNotify, 0,
|
||||
POINTER_RELATIVE, &mask);
|
||||
enqueueEvents(vncPointerDev, n);
|
||||
#else
|
||||
valuator_mask_set_range(&mask, 0, 2, valuators);
|
||||
QueuePointerEvents(vncPointerDev, MotionNotify, 0,
|
||||
POINTER_RELATIVE, &mask);
|
||||
#endif
|
||||
|
||||
cursorPosX = absx;
|
||||
cursorPosY = absy;
|
||||
}
|
||||
|
||||
void vncScroll(int x, int y) {
|
||||
ValuatorMask mask;
|
||||
valuator_mask_zero(&mask);
|
||||
@@ -500,6 +539,7 @@ static void vncKeysymKeyboardEvent(KeySym keysym, int down)
|
||||
pressedKeys[i] = NoSymbol;
|
||||
pressKey(vncKeyboardDev, i, FALSE, "keycode");
|
||||
mieqProcessInputEvents();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -544,7 +584,7 @@ static void vncKeysymKeyboardEvent(KeySym keysym, int down)
|
||||
|
||||
/* No matches. Will have to add a new entry... */
|
||||
if (keycode == 0) {
|
||||
keycode = vncAddKeysym(keysym, state);
|
||||
keycode = vncAddKeysym(keysym, state, needFree, freeKeys);
|
||||
if (keycode == 0) {
|
||||
LOG_ERROR("Failure adding new keysym 0x%x", keysym);
|
||||
return;
|
||||
|
||||
@@ -25,16 +25,19 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <X11/X.h>
|
||||
#include "stdbool.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void vncInitInputDevice(void);
|
||||
void vncInitInputDevice(bool freeKeyMappings);
|
||||
|
||||
void vncPointerButtonAction(int buttonMask, const unsigned char skipclick,
|
||||
const unsigned char skiprelease);
|
||||
void vncPointerMove(int x, int y);
|
||||
void vncPointerMoveRelative(int x, int y, int absx, int absy);
|
||||
|
||||
void vncScroll(int x, int y);
|
||||
void vncGetPointerPos(int *x, int *y);
|
||||
|
||||
@@ -57,7 +60,8 @@ KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
|
||||
|
||||
int vncIsAffectedByNumLock(KeyCode keycode);
|
||||
|
||||
KeyCode vncAddKeysym(KeySym keysym, unsigned state);
|
||||
KeyCode vncAddKeysym(KeySym keysym, unsigned state, unsigned int *needfree, bool freeKeys);
|
||||
void vncRemoveKeycode(unsigned keycode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -25,16 +25,19 @@
|
||||
#include "xorg-version.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include "RFBGlue.h"
|
||||
#include "xkbsrv.h"
|
||||
#include "xkbstr.h"
|
||||
#include "eventstr.h"
|
||||
#include "scrnintstr.h"
|
||||
#include "mi.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
#include "Input.h"
|
||||
|
||||
@@ -50,7 +53,15 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LOG_NAME "Input"
|
||||
|
||||
#define LOG_ERROR(...) vncLogError(LOG_NAME, __VA_ARGS__)
|
||||
#define LOG_STATUS(...) vncLogStatus(LOG_NAME, __VA_ARGS__)
|
||||
#define LOG_INFO(...) vncLogInfo(LOG_NAME, __VA_ARGS__)
|
||||
#define LOG_DEBUG(...) vncLogDebug(LOG_NAME, __VA_ARGS__)
|
||||
|
||||
extern DeviceIntPtr vncKeyboardDev;
|
||||
static unsigned int MAX_MAPPINGS = UINT_MAX - 1;
|
||||
|
||||
static void vncXkbProcessDeviceEvent(int screenNum,
|
||||
InternalEvent *event,
|
||||
@@ -536,12 +547,16 @@ int vncIsAffectedByNumLock(KeyCode keycode)
|
||||
return 1;
|
||||
}
|
||||
|
||||
KeyCode vncAddKeysym(KeySym keysym, unsigned state)
|
||||
KeyCode vncAddKeysym(KeySym keysym, unsigned state, unsigned int *needFree, bool freeKeys)
|
||||
{
|
||||
DeviceIntPtr master;
|
||||
XkbDescPtr xkb;
|
||||
unsigned int key;
|
||||
|
||||
unsigned int key = 0;
|
||||
unsigned int i;
|
||||
unsigned int newest_k = 0;
|
||||
unsigned int oldest_k = 0;
|
||||
unsigned int freeCnt = 0;
|
||||
|
||||
XkbEventCauseRec cause;
|
||||
XkbChangesRec changes;
|
||||
|
||||
@@ -551,14 +566,45 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state)
|
||||
|
||||
master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
|
||||
xkb = master->key->xkbInfo->desc;
|
||||
for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) {
|
||||
if (XkbKeyNumGroups(xkb, key) == 0)
|
||||
break;
|
||||
|
||||
//find the first free key to map
|
||||
for (i = xkb->max_key_code; i >= xkb->min_key_code; i--) {
|
||||
if (XkbKeyNumGroups(xkb, i) == 0 && *(needFree + i) != UINT_MAX) {
|
||||
if (++freeCnt == 1)
|
||||
key = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (key < xkb->min_key_code)
|
||||
return 0;
|
||||
|
||||
//find the oldest and newest keys that have been remapped
|
||||
for (i = 1;i < 256;i++) {
|
||||
//protect from uint rollover
|
||||
if (*(needFree + i) == MAX_MAPPINGS)
|
||||
*(needFree + i) = 1;
|
||||
if (*(needFree + i) > *(needFree + newest_k) && *(needFree + i) != UINT_MAX)
|
||||
newest_k = i;
|
||||
if (*(needFree + i) < *(needFree + oldest_k) && *(needFree +i) > 0)
|
||||
oldest_k = i;
|
||||
//mark as free to use
|
||||
if (*(needFree + i) == UINT_MAX)
|
||||
*(needFree + i) = 0;
|
||||
}
|
||||
*(needFree + key) = ++(*(needFree + newest_k));
|
||||
|
||||
//if running low on free keys, free the oldest key that was used
|
||||
if (freeCnt < 3 && *(needFree + oldest_k) > 0 && freeKeys) {
|
||||
vncRemoveKeycode(oldest_k);
|
||||
LOG_DEBUG("Removed mapping for keycode %d", oldest_k);
|
||||
//mark as free to use after one more cycle
|
||||
*(needFree + oldest_k) = UINT_MAX;
|
||||
} else if (freeCnt < 3 && freeKeys) {
|
||||
//this should only happen if the system had fewer than 3 free keys to begin with
|
||||
LOG_INFO("The system has fewer than 3 unmapped keys with no available keys to free.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&changes, 0, sizeof(changes));
|
||||
memset(&cause, 0, sizeof(cause));
|
||||
|
||||
@@ -612,6 +658,40 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state)
|
||||
return key;
|
||||
}
|
||||
|
||||
void vncRemoveKeycode(unsigned keycode)
|
||||
{
|
||||
DeviceIntPtr master;
|
||||
XkbDescPtr xkb;
|
||||
|
||||
XkbEventCauseRec cause;
|
||||
XkbChangesRec changes;
|
||||
|
||||
master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
|
||||
xkb = master->key->xkbInfo->desc;
|
||||
|
||||
memset(&changes, 0, sizeof(changes));
|
||||
memset(&cause, 0, sizeof(cause));
|
||||
|
||||
XkbSetCauseUnknown(&cause);
|
||||
|
||||
KeySym ks = NoSymbol;
|
||||
|
||||
KeySymsRec keysyms;
|
||||
keysyms.minKeyCode = keycode;
|
||||
keysyms.maxKeyCode = keycode;
|
||||
keysyms.mapWidth = 1;
|
||||
keysyms.map = &ks;
|
||||
|
||||
unsigned check = 0;
|
||||
XkbUpdateKeyTypesFromCore(master, &keysyms, keycode, 1, &changes);
|
||||
XkbUpdateActions(master, keycode, 1, &changes, &check, &cause);
|
||||
|
||||
if (check)
|
||||
XkbCheckSecondaryEffects(master->key->xkbInfo, 1, &changes, &cause);
|
||||
|
||||
XkbSendNotification(master, &changes, &cause);
|
||||
}
|
||||
|
||||
static void vncXkbProcessDeviceEvent(int screenNum,
|
||||
InternalEvent *event,
|
||||
DeviceIntPtr dev)
|
||||
|
||||
@@ -41,6 +41,7 @@ nodist_EXTRA_Xvnc_SOURCES = dummy.cxx
|
||||
|
||||
Xvnc_CPPFLAGS = $(XVNC_CPPFLAGS) -DKASMVNC -DNO_MODULE_EXTS \
|
||||
-UHAVE_CONFIG_H \
|
||||
-DXVNCEXTRAVERSION="\".$(KASMVNC_COMMIT_ID)\"" \
|
||||
-DXFree86Server -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \
|
||||
-DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(KASMVNC_SRCDIR)/common -I$(KASMVNC_SRCDIR)/unix/common \
|
||||
-I$(top_srcdir)/include ${XSERVERLIBS_CFLAGS} -I$(includedir)
|
||||
|
||||
@@ -60,6 +60,10 @@ BoolParameter rawKeyboard("RawKeyboard",
|
||||
"Send keyboard events straight through and "
|
||||
"avoid mapping them to the current keyboard "
|
||||
"layout", false);
|
||||
BoolParameter freeKeyMappings("FreeKeyMappings",
|
||||
"Automatically free added keyboard mappings "
|
||||
"when there are not enough unused keys to "
|
||||
"map symbols to.", false);
|
||||
IntParameter queryConnectTimeout("QueryConnectTimeout",
|
||||
"Number of seconds to show the "
|
||||
"Accept Connection dialog before "
|
||||
@@ -370,7 +374,7 @@ void XserverDesktop::blockHandler(int* timeout)
|
||||
// so we abuse the fact that this routine will be called first thing
|
||||
// once the dix is done initialising.
|
||||
// [1] Technically Xvnc has InitInput(), but libvnc.so has nothing.
|
||||
vncInitInputDevice();
|
||||
vncInitInputDevice(freeKeyMappings);
|
||||
|
||||
try {
|
||||
std::list<Socket*> sockets;
|
||||
@@ -457,12 +461,17 @@ void XserverDesktop::approveConnection(uint32_t opaqueId, bool accept,
|
||||
//
|
||||
// SDesktop callbacks
|
||||
|
||||
|
||||
void XserverDesktop::pointerEvent(const Point& pos, int buttonMask,
|
||||
void XserverDesktop::pointerEvent(const Point& pos, const Point& abspos, int buttonMask,
|
||||
const bool skipClick, const bool skipRelease, int scrollX, int scrollY)
|
||||
{
|
||||
if (scrollX == 0 && scrollY == 0) {
|
||||
vncPointerMove(pos.x + vncGetScreenX(screenIndex), pos.y + vncGetScreenY(screenIndex));
|
||||
if (pos.equals(abspos)) {
|
||||
vncPointerMove(pos.x + vncGetScreenX(screenIndex), pos.y + vncGetScreenY(screenIndex));
|
||||
} else {
|
||||
vncPointerMoveRelative(pos.x, pos.y,
|
||||
abspos.x + vncGetScreenX(screenIndex),
|
||||
abspos.y + vncGetScreenY(screenIndex));
|
||||
}
|
||||
vncPointerButtonAction(buttonMask, skipClick, skipRelease);
|
||||
} else {
|
||||
vncScroll(scrollX, scrollY);
|
||||
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
const char* rejectMsg=0);
|
||||
|
||||
// rfb::SDesktop callbacks
|
||||
virtual void pointerEvent(const rfb::Point& pos, int buttonMask,
|
||||
virtual void pointerEvent(const rfb::Point& pos, const rfb::Point& abspos, int buttonMask,
|
||||
const bool skipClick, const bool skipRelease, int scrollX = 0, int scrollY = 0);
|
||||
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
|
||||
virtual unsigned int setScreenLayout(int fb_width, int fb_height,
|
||||
|
||||
@@ -733,13 +733,6 @@ static void vncSelectionCallback(CallbackListPtr *callbacks,
|
||||
LOG_DEBUG("Selection owner change for %s",
|
||||
NameForAtom(info->selection->selection));
|
||||
|
||||
/*
|
||||
* If we're the previous owner of this selection, then we're also the
|
||||
* owner of _the other_ selection. Make sure we drop all ownerships so
|
||||
* we either own both selections or nonw.
|
||||
*/
|
||||
DeleteWindowFromAnySelections(pWindow);
|
||||
|
||||
if ((info->selection->selection != xaPRIMARY) &&
|
||||
(info->selection->selection != xaCLIPBOARD))
|
||||
return;
|
||||
|
||||
@@ -159,7 +159,9 @@ static int vncVerbose = DEFAULT_LOG_VERBOSITY;
|
||||
static void
|
||||
vncPrintBanner(void)
|
||||
{
|
||||
ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT);
|
||||
ErrorF("\nXvnc %s%s - built %s\n%s", XVNCVERSION,
|
||||
sizeof(XVNCEXTRAVERSION) > 2 ? XVNCEXTRAVERSION : "",
|
||||
buildtime, XVNCCOPYRIGHT);
|
||||
ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE,
|
||||
VENDOR_STRING);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user