diff --git a/dockerfile-kasm-core b/dockerfile-kasm-core index 4092636..13dee53 100644 --- a/dockerfile-kasm-core +++ b/dockerfile-kasm-core @@ -60,6 +60,10 @@ COPY ./src/ubuntu/install/kasm_vnc $INST_SCRIPTS/kasm_vnc/ RUN bash $INST_SCRIPTS/kasm_vnc/install_kasm_vnc.sh && rm -rf $INST_SCRIPTS/kasm_vnc/ COPY ./src/common/install/kasm_vnc/kasmvnc.yaml /etc/kasmvnc/ +### Install Kasm Profile Sync +COPY ./src/ubuntu/install/profile_sync $INST_SCRIPTS/profile_sync/ +RUN bash $INST_SCRIPTS/profile_sync/install_profile_sync.sh + ### Install Kasm Upload Server COPY ./src/ubuntu/install/kasm_upload_server $INST_SCRIPTS/kasm_upload_server/ RUN bash $INST_SCRIPTS/kasm_upload_server/install_kasm_upload_server.sh && rm -rf $INST_SCRIPTS/kasm_upload_server/ diff --git a/dockerfile-kasm-core-alpine b/dockerfile-kasm-core-alpine index c52a9a3..83c6138 100644 --- a/dockerfile-kasm-core-alpine +++ b/dockerfile-kasm-core-alpine @@ -54,6 +54,10 @@ COPY ./src/ubuntu/install/kasm_vnc $INST_SCRIPTS/kasm_vnc/ RUN bash $INST_SCRIPTS/kasm_vnc/install_kasm_vnc.sh && rm -rf $INST_SCRIPTS/kasm_vnc/ COPY ./src/common/install/kasm_vnc/kasmvnc.yaml /etc/kasmvnc/ +### Install Kasm Profile Sync +COPY ./src/ubuntu/install/profile_sync $INST_SCRIPTS/profile_sync/ +RUN bash $INST_SCRIPTS/profile_sync/install_profile_sync.sh + ### Install Kasm Upload Server COPY ./src/ubuntu/install/kasm_upload_server $INST_SCRIPTS/kasm_upload_server/ RUN bash $INST_SCRIPTS/kasm_upload_server/install_kasm_upload_server.sh && rm -rf $INST_SCRIPTS/kasm_upload_server/ diff --git a/dockerfile-kasm-core-fedora b/dockerfile-kasm-core-fedora index 786a185..42dd787 100644 --- a/dockerfile-kasm-core-fedora +++ b/dockerfile-kasm-core-fedora @@ -41,7 +41,7 @@ ENV HOME=/home/kasm-default-profile \ LANG=$LANG \ LANGUAGE=$LANGUAGE \ LC_ALL=$LC_ALL \ - DISTRO=$DISTRO + DISTRO=$DISTRO WORKDIR $HOME RUN mkdir -p $HOME/Desktop @@ -69,6 +69,10 @@ COPY ./src/ubuntu/install/kasm_vnc $INST_SCRIPTS/kasm_vnc/ RUN bash $INST_SCRIPTS/kasm_vnc/install_kasm_vnc.sh && rm -rf $INST_SCRIPTS/kasm_vnc/ COPY ./src/common/install/kasm_vnc/kasmvnc.yaml /etc/kasmvnc/ +### Install Kasm Profile Sync +COPY ./src/ubuntu/install/profile_sync $INST_SCRIPTS/profile_sync/ +RUN bash $INST_SCRIPTS/profile_sync/install_profile_sync.sh + ### Install Kasm Upload Server COPY ./src/ubuntu/install/kasm_upload_server $INST_SCRIPTS/kasm_upload_server/ RUN bash $INST_SCRIPTS/kasm_upload_server/install_kasm_upload_server.sh && rm -rf $INST_SCRIPTS/kasm_upload_server/ diff --git a/dockerfile-kasm-core-oracle b/dockerfile-kasm-core-oracle index d3a3ace..1da6722 100644 --- a/dockerfile-kasm-core-oracle +++ b/dockerfile-kasm-core-oracle @@ -47,7 +47,7 @@ ENV HOME=/home/kasm-default-profile \ LANG=$LANG \ LANGUAGE=$LANGUAGE \ LC_ALL=$LC_ALL \ - DISTRO=$DISTRO + DISTRO=$DISTRO WORKDIR $HOME RUN mkdir -p $HOME/Desktop @@ -84,6 +84,10 @@ COPY ./src/ubuntu/install/kasm_vnc $INST_SCRIPTS/kasm_vnc/ RUN bash $INST_SCRIPTS/kasm_vnc/install_kasm_vnc.sh && rm -rf $INST_SCRIPTS/kasm_vnc/ COPY ./src/common/install/kasm_vnc/kasmvnc.yaml /etc/kasmvnc/ +### Install Kasm Profile Sync +COPY ./src/ubuntu/install/profile_sync $INST_SCRIPTS/profile_sync/ +RUN bash $INST_SCRIPTS/profile_sync/install_profile_sync.sh + ### Install Kasm Upload Server COPY ./src/ubuntu/install/kasm_upload_server $INST_SCRIPTS/kasm_upload_server/ RUN bash $INST_SCRIPTS/kasm_upload_server/install_kasm_upload_server.sh && rm -rf $INST_SCRIPTS/kasm_upload_server/ diff --git a/dockerfile-kasm-core-suse b/dockerfile-kasm-core-suse index 7418c51..0127a7b 100644 --- a/dockerfile-kasm-core-suse +++ b/dockerfile-kasm-core-suse @@ -38,7 +38,7 @@ ENV HOME=/home/kasm-default-profile \ LANGUAGE=$LANGUAGE \ LC_ALL=$LC_ALL \ PULSE_RUNTIME_PATH=/var/run/pulse \ - DISTRO=$DISTRO + DISTRO=$DISTRO WORKDIR $HOME RUN mkdir -p $HOME/Desktop @@ -59,6 +59,10 @@ COPY ./src/ubuntu/install/kasm_vnc $INST_SCRIPTS/kasm_vnc/ RUN bash $INST_SCRIPTS/kasm_vnc/install_kasm_vnc.sh && rm -rf $INST_SCRIPTS/kasm_vnc/ COPY ./src/common/install/kasm_vnc/kasmvnc.yaml /etc/kasmvnc/ +### Install Kasm Profile Sync +COPY ./src/ubuntu/install/profile_sync $INST_SCRIPTS/profile_sync/ +RUN bash $INST_SCRIPTS/profile_sync/install_profile_sync.sh + ### Install Kasm Upload Server COPY ./src/ubuntu/install/kasm_upload_server $INST_SCRIPTS/kasm_upload_server/ RUN bash $INST_SCRIPTS/kasm_upload_server/install_kasm_upload_server.sh && rm -rf $INST_SCRIPTS/kasm_upload_server/ diff --git a/src/common/scripts/kasm_hook_scripts/kasm_pre_shutdown_user.sh b/src/common/scripts/kasm_hook_scripts/kasm_pre_shutdown_user.sh index 5edf0a4..26bf102 100644 --- a/src/common/scripts/kasm_hook_scripts/kasm_pre_shutdown_user.sh +++ b/src/common/scripts/kasm_hook_scripts/kasm_pre_shutdown_user.sh @@ -1,7 +1,16 @@ #!/usr/bin/env bash set -e echo "Executing kasm_pre_shutdown_user.sh" + PAUSE_ON_EXIT="false" +if [ -z ${KASM_PROFILE_CHUNK_SIZE} ]; then + KASM_PROFILE_CHUNK_SIZE=100000 +fi + +if [ -f /usr/bin/kasm-profile-sync ]; then + kasm_profile_sync_found=1 +fi + for x in {1..10} do @@ -34,4 +43,28 @@ then sleep 1 fi +if [ ! -z "$KASM_PROFILE_LDR" ]; then + CURRENT_SIZE=$(du -s $HOME | grep -Po '^\d+') + if [ -z ${KASM_PROFILE_FILTER} ]; then + KASM_PROFILE_FILTER=".vnc,.cache,Downloads,Uploads,.config/*/Singleton*" + fi + + if [ ! -z "$KASM_PROFILE_SIZE_LIMIT" ]; then + SIZE_LIMIT_MB=$(echo "$KASM_PROFILE_SIZE_LIMIT / 1000" | bc) + if [[ $CURRENT_SIZE -gt KASM_PROFILE_SIZE_LIMIT ]]; then + http_proxy="" https_proxy="" curl -k "https://${KASM_API_HOST}:${KASM_API_PORT}/api/set_kasm_session_status?token=${KASM_API_JWT}" -H 'Content-Type: application/json' -d '{"destroyed": true}' + echo 'Profile size limit exceeded.' + exit 0 + fi + fi + + if [ -z "$kasm_profile_sync_found" ]; then + echo >&2 "Profile sync not available" + else + echo "Packing and uploading user profile to object storage." + http_proxy="" https_proxy="" /usr/bin/kasm-profile-sync --upload /home/kasm-user --insecure --filter "${KASM_PROFILE_FILTER}" --remote ${KASM_API_HOST} --port ${KASM_API_PORT} -c ${KASM_PROFILE_CHUNK_SIZE} --token ${KASM_API_JWT} --bigfiles skip + echo "Profile upload complete." + fi +fi + echo "Done" diff --git a/src/common/startup_scripts/vnc_startup.sh b/src/common/startup_scripts/vnc_startup.sh index 8a4de31..419a1a6 100755 --- a/src/common/startup_scripts/vnc_startup.sh +++ b/src/common/startup_scripts/vnc_startup.sh @@ -4,6 +4,10 @@ set -e no_proxy="localhost,127.0.0.1" +if [ -f /usr/bin/kasm-profile-sync ]; then + kasm_profile_sync_found=1 +fi + # Set lang values if [ "${LC_ALL}" != "en_US.UTF-8" ]; then export LANG=${LC_ALL} @@ -20,7 +24,11 @@ VNC_VIEW_ONLY_PW=$tmpval tmpval=$VNC_PW unset VNC_PW VNC_PW=$tmpval + BUILD_ARCH=$(uname -p) +if [ -z ${KASM_PROFILE_CHUNK_SIZE} ]; then + KASM_PROFILE_CHUNK_SIZE=100000 +fi if [ -z ${DRINODE+x} ]; then DRINODE="/dev/dri/renderD128" fi @@ -49,6 +57,70 @@ function help (){ " } +trap cleanup SIGINT SIGTERM SIGQUIT SIGHUP ERR + +function pull_profile (){ + if [ ! -z "$KASM_PROFILE_LDR" ]; then + if [ -z "$kasm_profile_sync_found" ]; then + echo >&2 "Profile sync not available" + sleep 3 + http_proxy="" https_proxy="" curl -k "https://${KASM_API_HOST}:${KASM_API_PORT}/api/set_kasm_session_status?token=${KASM_API_JWT}" -H 'Content-Type: application/json' -d '{"status": "running"}' + return + fi + + echo "Downloading and unpacking user profile from object storage." + set +e + http_proxy="" https_proxy="" /usr/bin/kasm-profile-sync --download /home/kasm-user --insecure --remote ${KASM_API_HOST} --port ${KASM_API_PORT} -c ${KASM_PROFILE_CHUNK_SIZE} --token ${KASM_API_JWT} + PROCESS_SYNC_EXIT_CODE=$? + set -e + if (( PROCESS_SYNC_EXIT_CODE > 1 )); then + echo "Profile-sync failed with a non-recoverable error. See server side logs for more details." + exit 1 + fi + echo "Profile load complete." + # Update the status of the container to running + sleep 3 + http_proxy="" https_proxy="" curl -k "https://${KASM_API_HOST}:${KASM_API_PORT}/api/set_kasm_session_status?token=${KASM_API_JWT}" -H 'Content-Type: application/json' -d '{"status": "running"}' + + fi +} + +function push_profile(){ + if [ ! -z "$KASM_PROFILE_LDR" ]; then + if [ -z "$kasm_profile_sync_found" ]; then + echo >&2 "Profile sync not available" + return + fi + + echo "Packing and uploading user profile to object storage." + /usr/bin/kasm-profile-sync --upload /home/kasm-user --insecure --remote ${KASM_API_HOST} --port ${KASM_API_PORT} -c ${KASM_PROFILE_CHUNK_SIZE} --token ${KASM_API_JWT} + echo "Profile upload complete." + fi +} + +function profile_size_check(){ + if [ ! -z "$KASM_PROFILE_SIZE_LIMIT" ] + then + SIZE_CHECK_FAILED=false + while true + do + sleep 60 + CURRENT_SIZE=$(du -s $HOME | grep -Po '^\d+') + SIZE_LIMIT_MB=$(echo "$KASM_PROFILE_SIZE_LIMIT / 1000" | bc) + if [[ $CURRENT_SIZE -gt KASM_PROFILE_SIZE_LIMIT ]] + then + notify-send "Profile Size Exceeds Limit" "Your home profile has exceeded the size limit of ${SIZE_LIMIT_MB}MB. Changes on your desktop will not be saved between sessions until you reduce the size of your profile." -i /usr/share/icons/ubuntu-mono-dark/apps/22/dropboxstatus-x.svg -t 57000 + SIZE_CHECK_FAILED=true + else + if [ "$SIZE_CHECK_FAILED" = true ] ; then + SIZE_CHECK_FAILED=false + notify-send "Profile Size" "Your home profile size is now under the limit and will be saved when your session is terminated." -i /usr/share/icons/ubuntu-mono-dark/apps/22/dropboxstatus-logo.svg -t 57000 + fi + fi + done + fi +} + ## correct forwarding of shutdown signal function cleanup () { kill -s SIGTERM $! @@ -236,6 +308,9 @@ if [[ $1 =~ -h|--help ]]; then exit 0 fi +# Syncronize user-space loaded persistent profiles +pull_profile + # should also source $STARTUPDIR/generate_container_user if [ -f $HOME/.bashrc ]; then source $HOME/.bashrc @@ -247,8 +322,6 @@ if [[ ${KASM_DEBUG:-0} == 1 ]]; then set -x fi -trap cleanup SIGINT SIGTERM - ## resolve_vnc_connection VNC_IP=$(hostname -i) if [[ $DEBUG == true ]]; then @@ -281,6 +354,7 @@ start_audio_out start_audio_in start_upload start_gamepad +profile_size_check & start_webcam STARTUP_COMPLETE=1 diff --git a/src/ubuntu/install/profile_sync/install_profile_sync.sh b/src/ubuntu/install/profile_sync/install_profile_sync.sh new file mode 100755 index 0000000..cba1cb5 --- /dev/null +++ b/src/ubuntu/install/profile_sync/install_profile_sync.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +set -eo pipefail + +check_distro_is_supported() { + if [[ "$profile_distro" = oracle_7 ]]; then + exit + fi +} + +delimit_distro_version_with_underscore() { + local distro="$1" + echo "$distro" | sed 's/^\([a-zA-Z]\+\)\([0-9]\+\)$/\1_\2/' +} + +detect_deb_distro() { + local distro + local codename + local full_name + + distro=$(grep -Po -m 1 '(?<=PRETTY_NAME=")[^ ]+' /etc/os-release) + codename=$(grep -Po -m 1 "(?<=_CODENAME=)\w+" /etc/os-release) + full_name="${distro}_${codename}" + echo "${full_name,,}" +} + +handle_debian_and_ubuntu_conversion() { + if [[ "$DISTRO" = @(debian|ubuntu) ]]; then + profile_distro=$(detect_deb_distro) + fi +} + +handle_other_distros_conversion() { + profile_distro=$(delimit_distro_version_with_underscore "$DISTRO") + + case "$DISTRO" in + kali) profile_distro="kali_kali-rolling" + ;; + opensuse) profile_distro="opensuse_15" + ;; + alpine) + if grep -q 'v3.17' /etc/os-release; then + profile_distro="alpine_317" + fi + if grep -q 'v3.18' /etc/os-release; then + profile_distro="alpine_318" + fi + ;; + rockylinux*) + profile_distro=$(echo "$profile_distro" | sed -e 's/linux//') + ;; + almalinux*) + profile_distro=$(echo "$profile_distro" | sed -e 's/linux//') + ;; + esac +} + +convert_local_distro_to_profile_sync_distro() { + handle_debian_and_ubuntu_conversion + if [ -n "$profile_distro" ]; then + return + fi + + handle_other_distros_conversion +} + +download_and_symlink() { + COMMIT_ID_SHORT=$(echo "${COMMIT_ID}" | cut -c1-6) + BINARY_NAME="${profile_distro}_${BRANCH}_${COMMIT_ID_SHORT}_${ARCH}-kasm-profile-sync" + BUILD_URL="https://kasmweb-build-artifacts.s3.amazonaws.com/profile-sync/${COMMIT_ID}/${BINARY_NAME}" + + cd /usr/bin/ + wget "$BUILD_URL" + chmod +x "$BINARY_NAME" + ln -s "$BINARY_NAME" kasm-profile-sync +} + +ARCH=$(arch) +BRANCH="release_1.0.0" +COMMIT_ID="2934416796e7bffe7244e80411e51be68c2c198f" + +convert_local_distro_to_profile_sync_distro +check_distro_is_supported +download_and_symlink diff --git a/src/ubuntu/install/tools/install_tools.sh b/src/ubuntu/install/tools/install_tools.sh index 7ef19d4..da4506b 100644 --- a/src/ubuntu/install/tools/install_tools.sh +++ b/src/ubuntu/install/tools/install_tools.sh @@ -3,12 +3,12 @@ set -e echo "Install some common tools for further installation" if [[ "${DISTRO}" == @(centos|oracle7) ]] ; then - yum install -y vim wget net-tools bzip2 python3 ca-certificates + yum install -y vim wget net-tools bzip2 python3 ca-certificates bc elif [[ "${DISTRO}" == @(fedora37|fedora38|oracle8|oracle9|rockylinux9|rockylinux8|almalinux8|almalinux9) ]]; then - dnf install -y wget net-tools bzip2 python3 tar vim hostname procps-ng + dnf install -y wget net-tools bzip2 python3 tar vim hostname procps-ng bc elif [ "${DISTRO}" == "opensuse" ]; then sed -i 's/download.opensuse.org/mirrorcache-us.opensuse.org/g' /etc/zypp/repos.d/*.repo - zypper install -yn wget net-tools bzip2 python3 tar vim gzip iputils + zypper install -yn wget net-tools bzip2 python3 tar vim gzip iputils bc elif [ "${DISTRO}" == "alpine" ]; then apk add --no-cache \ ca-certificates \ @@ -23,12 +23,13 @@ elif [ "${DISTRO}" == "alpine" ]; then shadow \ sudo \ tar \ - wget + wget \ + bc else apt-get update # Update tzdata noninteractive (otherwise our script is hung on user input later). DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata - apt-get install -y vim wget net-tools locales bzip2 wmctrl software-properties-common mesa-utils + apt-get install -y vim wget net-tools locales bzip2 wmctrl software-properties-common mesa-utils bc echo "generate locales for en_US.UTF-8" locale-gen en_US.UTF-8 diff --git a/src/ubuntu/install/xfce/install_xfce_ui.sh b/src/ubuntu/install/xfce/install_xfce_ui.sh index 124ac87..0b1f792 100644 --- a/src/ubuntu/install/xfce/install_xfce_ui.sh +++ b/src/ubuntu/install/xfce/install_xfce_ui.sh @@ -63,7 +63,8 @@ if [ "${DISTRO}" == "kali" ]; then xfce4-genmon-plugin \ xfce4-screenshooter \ xfce4-taskmanager \ - xfce4-whiskermenu-plugin + xfce4-whiskermenu-plugin \ + xfce4-notifyd elif [[ "$DISTRO" = @(ubuntu|debian) ]]; then apt-get install -y \ dbus-x11 \